Skip to content

Commit

Permalink
Merge branch 'main' into feat/where-find-us
Browse files Browse the repository at this point in the history
  • Loading branch information
vincelwt authored Apr 24, 2024
2 parents 1ab8855 + 62fefdb commit d3643b7
Show file tree
Hide file tree
Showing 15 changed files with 215 additions and 29 deletions.
1 change: 0 additions & 1 deletion .github/workflows/build-push-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ jobs:
push: true
tags: |
lunary/${{ matrix.service }}:latest
lunary/${{ matrix.service }}:1.2.11
lunary/${{ matrix.service }}:rev-${{ steps.date.outputs.date }}-${{ steps.commit.outputs.hash }}
${{ github.event.release.tag_name != '' && format('lunary/{0}:{1}', matrix.service, steps.release_tag.outputs.tag) || '' }}
platforms: linux/amd64,linux/arm64
Expand Down
47 changes: 40 additions & 7 deletions packages/backend/src/api/v1/runs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import Router from "koa-router"

import ingest from "./ingest"
import { fileExport } from "./export"
import { deserializeLogic } from "shared"
import { Feedback, deserializeLogic } from "shared"
import { convertChecksToSQL } from "@/src/utils/checks"
import { checkAccess } from "@/src/utils/authorization"
import { jsonrepair } from "jsonrepair"
import { z } from "zod"

const runs = new Router({
prefix: "/runs",
Expand Down Expand Up @@ -263,28 +264,60 @@ runs.get("/:id", async (ctx) => {
})

runs.patch("/:id", checkAccess("logs", "update"), async (ctx: Context) => {
// TODO: each value should probably have their own endpoint
// TODO: zod
const { projectId } = ctx.state
const { id } = ctx.params
const { isPublic, feedback, tags } = ctx.request.body as {
const { isPublic, tags } = ctx.request.body as {
isPublic: boolean
feedback: string
tags: string[]
}

let valuesToUpdate = {}
if (isPublic) {
valuesToUpdate.isPublic = isPublic
}
if (tags) {
valuesToUpdate.tags = tags
}

await sql`
update
run
set
is_public = ${isPublic},
feedback = ${feedback},
tags = ${tags}
set ${sql(valuesToUpdate)}
where
project_id= ${projectId as string}
and id = ${id}`

ctx.status = 200
})

runs.patch(
"/:id/feedback",
checkAccess("logs", "update"),
async (ctx: Context) => {
const { projectId } = ctx.state
const { id } = ctx.params
const feedback = Feedback.parse(ctx.request.body)

let [{ feedback: existingFeedback }] =
(await sql`select feedback from run where id = ${id}`) || {}

const newFeedback = { ...existingFeedback, ...feedback }

await sql`
update
run
set
feedback = ${sql.json(newFeedback)}
where
id = ${id}
and project_id = ${projectId}`

ctx.status = 200
},
)

runs.get("/:id/related", checkAccess("logs", "read"), async (ctx) => {
const id = ctx.params.id

Expand Down
114 changes: 114 additions & 0 deletions packages/frontend/components/blocks/Feedbacks/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { useFixedColorScheme } from "@/utils/hooks"
import { ActionIcon, Box, Button, Popover, TextInput } from "@mantine/core"
import { IconMessage, IconThumbDown, IconThumbUp } from "@tabler/icons-react"
import { useState } from "react"
import { Feedback } from "shared"

function getColor(color: string) {
const scheme = useFixedColorScheme()
return scheme === "light" ? `var(--mantine-color-${color}-5)` : color
}

export default function Feedbacks({
feedback,
updateFeedback,
}: {
feedback: Feedback
updateFeedback: (...props: any) => any
}) {
if (!feedback) {
feedback = { comment: null, thumb: null }
}

if (feedback?.thumbs) {
feedback.thumb = feedback.thumbs // legacy key name
}

if (feedback?.thumbs && feedback.thumb) {
delete feedback.thumbs
}

function ThumbFeedback({ value }: { value?: "up" | "down" | null }) {
console.log(value)
function ThumbUp() {
const color = getColor(value === "up" ? "green" : "gray")
return <IconThumbUp color={color} fill={color} fillOpacity={0.2} />
}

function ThumbDown() {
const color = getColor(value === "down" ? "red" : "gray")
return <IconThumbDown color={color} fill={color} fillOpacity={0.2} />
}

return (
<Box>
<ActionIcon
variant="transparent"
onClick={() => {
if (feedback.thumb === "down") {
feedback.thumb = null
} else {
feedback.thumb = "down"
}
updateFeedback(feedback)
}}
>
<ThumbDown />
</ActionIcon>
<ActionIcon
variant="transparent"
onClick={() => {
if (feedback.thumb === "up") {
feedback.thumb = null
} else {
feedback.thumb = "up"
}
updateFeedback(feedback)
}}
>
<ThumbUp />
</ActionIcon>
</Box>
)
}

function CommentFeedback({ value }) {
const [comment, setComment] = useState(value)
return (
<Popover width={300} trapFocus position="bottom" withArrow shadow="md">
<Popover.Target>
<ActionIcon variant="transparent">
<IconMessage color={value ? "green" : "gray"} />
</ActionIcon>
</Popover.Target>
<Popover.Dropdown>
<TextInput
value={comment}
size="xs"
mt="xs"
onChange={(e) => setComment(e.target.value)}
/>
<Button
mt="md"
size="xs"
style={{ float: "right" }}
onClick={() => {
feedback.comment = comment
updateFeedback(feedback)
}}
>
Save
</Button>
</Popover.Dropdown>
</Popover>
)
}

console.log(feedback)
return (
<>
<CommentFeedback value={feedback?.comment} />
<ThumbFeedback value={feedback?.thumb} />
</>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ export default function Feedback({

if (!data) return null

if (data.type === "thumb") {
data = { thumbs: data.value }
}

if (data.type === "comment") {
data = { comment: data.value }
}

const getIconProps = (color: string) => ({
size: 20,
fillOpacity: 0.2,
Expand All @@ -49,10 +57,8 @@ export default function Feedback({
: "",
}}
>
{data?.thumbs === "up" && <IconThumbUp {...getIconProps("green")} />}
{data?.thumbs === "down" && (
<IconThumbDown {...getIconProps("red")} />
)}
{data?.thumb === "up" && <IconThumbUp {...getIconProps("green")} />}
{data?.thumb === "down" && <IconThumbDown {...getIconProps("red")} />}
{typeof data?.rating === "number" && (
<Group gap={3}>
{Array.from({ length: data.rating }).map((_, i) => (
Expand All @@ -61,7 +67,7 @@ export default function Feedback({
</Group>
)}
{data?.emoji && <span>{data.emoji}</span>}
{typeof data?.comment === "string" && (
{typeof data?.comment === "string" && data?.comment !== "" && (
/* Support for comment == "" in the filters */
<Tooltip label={`“${data.comment}”`} disabled={!data.comment}>
<IconMessage {...getIconProps("teal")} />
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/components/blocks/RunChat.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useCallback, useMemo, useState } from "react"

import Feedback from "@/components/blocks/Feedback"
import Feedback from "@/components/blocks/OldFeedback"
import { BubbleMessage } from "@/components/SmartViewer/Message"

import {
Expand Down
25 changes: 20 additions & 5 deletions packages/frontend/components/blocks/RunInputOutput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import SmartViewer from "../SmartViewer"
import CopyText, { SuperCopyButton } from "./CopyText"
import ErrorBoundary from "./ErrorBoundary"
import TokensBadge from "./TokensBadge"
import Feedbacks from "./Feedbacks"

const isChatMessages = (obj) => {
return Array.isArray(obj)
Expand Down Expand Up @@ -134,11 +135,13 @@ const PARAMS = [

export default function RunInputOutput({
initialRun,
withFeedback = false,
withPlayground = true,
withShare = false,
mutateLogs,
}) {
const { user } = useUser()
const { run, update } = useRun(initialRun?.id, initialRun)
const { run, update, updateFeedback } = useRun(initialRun?.id, initialRun)

const canEnablePlayground =
withPlayground &&
Expand Down Expand Up @@ -283,17 +286,29 @@ export default function RunInputOutput({

{(run?.output || run?.error) && (
<>
<Group justify="space-between">
<Group mt="lg" justify="space-between">
<Text fw="bold" size="sm">
{run.error
? "Error"
: run.type === "retriever"
? "Documents"
: "Output"}
</Text>
{run.tokens?.completion && (
<TokensBadge tokens={run.tokens?.completion} />
)}

<Group>
{withFeedback && (
<Feedbacks
feedback={run.feedback}
updateFeedback={async (feedback) => {
await updateFeedback(feedback)
await mutateLogs()
}}
/>
)}
{run.tokens?.completion && (
<TokensBadge tokens={run.tokens?.completion} />
)}
</Group>
</Group>
<SmartViewer data={run.output} error={run.error} />
</>
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/components/checks/ChecksUIData.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import {
IconUserCheck,
IconWorldWww,
} from "@tabler/icons-react"
import Feedback from "../blocks/Feedback"
import Feedback from "../blocks/OldFeedback"
import AppUserAvatar from "../blocks/AppUserAvatar"
import { Group, Text } from "@mantine/core"
import { capitalize, formatAppUser } from "@/utils/format"
Expand Down
1 change: 0 additions & 1 deletion packages/frontend/components/checks/SmartSelectInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,6 @@ export default function SmartCheckSelect({
w="min-content"
>
<Combobox.Target>

<Pill.Group style={{ flexWrap: "nowrap", overflow: "hidden" }}>
{renderedValue}
</Pill.Group>
Expand Down
1 change: 1 addition & 0 deletions packages/frontend/pages/logs/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export default function PublicRun() {
{data && (
<RunInputOutput
initialRun={data}
withFeedback={true}
withPlayground={false}
withShare={false}
/>
Expand Down
4 changes: 3 additions & 1 deletion packages/frontend/pages/logs/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -163,11 +163,11 @@ export default function Logs() {
loading,
validating,
loadMore,
mutate,
} = useProjectInfiniteSWR(`/runs?${serializedChecks}`)

const { run: selectedRun, loading: runLoading } = useRun(selectedRunId)

console.log(selectedRun?.projectId)
useEffect(() => {
if (selectedRun && selectedRun.projectId !== projectId) {
setProjectId(selectedRun.projectId)
Expand Down Expand Up @@ -407,8 +407,10 @@ export default function Logs() {
{selectedRun?.type === "llm" && (
<RunInputOutput
initialRun={selectedRun}
withFeedback={true}
withPlayground={true}
withShare={true}
mutateLogs={mutate}
/>
)}
{selectedRun?.type === "thread" && (
Expand Down
15 changes: 10 additions & 5 deletions packages/frontend/utils/dataHooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,8 @@ export function useProjectInfiniteSWR(key: string, ...args: any[]) {
return generateKey(key, projectId, `page=${pageIndex}&limit=100`)
}

const { data, isLoading, isValidating, size, setSize } = useSWRInfinite(
getKey,
...(args as [any]),
)
const { data, isLoading, isValidating, size, setSize, mutate } =
useSWRInfinite(getKey, ...(args as [any]))

function loadMore() {
const hasMore = data && data[data.length - 1]?.length >= PAGE_SIZE
Expand All @@ -93,6 +91,7 @@ export function useProjectInfiniteSWR(key: string, ...args: any[]) {
loading: isLoading,
validating: isValidating,
loadMore,
mutate,
}
}

Expand Down Expand Up @@ -337,14 +336,20 @@ export function useRun(id: string | null, initialData?: any) {
},
)

const { trigger: updateFeedback } = useProjectMutation(
id && `/runs/${id}/feedback`,
fetcher.patch,
)

async function updateRun(data) {
mutate({ ...run, ...data }, { revalidate: false })
mutate({ ...run, ...data })
await update(data)
}

return {
run,
update: updateRun,
updateFeedback,
mutate,
loading: isLoading,
}
Expand Down
Loading

0 comments on commit d3643b7

Please sign in to comment.