Skip to content

Commit

Permalink
cr
Browse files Browse the repository at this point in the history
  • Loading branch information
bracesproul committed Oct 17, 2024
1 parent 7b8aecd commit 52567c0
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 95 deletions.
2 changes: 1 addition & 1 deletion frontend/app/components/GeneratingQuestionsToolUI.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export const useGeneratingQuestionsUI = () =>
<div className="flex flex-col mb-4">
<span className="flex flex-row gap-2 items-center justify-start pb-4 text-gray-300">
<Globe className="w-5 h-5" />
<p className="text-xl">Generated Questions & Sources</p>
<p className="text-xl">Research Plan & Sources</p>
</span>
<div className="mb-10">
<div className="flex flex-wrap items-center justify-start gap-2">
Expand Down
73 changes: 57 additions & 16 deletions frontend/app/components/ThreadHistory.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { isToday, isYesterday, isWithinInterval, subDays } from "date-fns";
import { dummyThreads } from "../utils/dummy";
import { TooltipIconButton } from "./ui/assistant-ui/tooltip-icon-button";
import { Button } from "./ui/button";
import { SquarePen, History } from "lucide-react";
import { SquarePen, History, Trash2 } from "lucide-react";
import { Sheet, SheetContent, SheetTrigger } from "./ui/sheet";
import { ThreadActual } from "../hooks/useThreads";
import { useToast } from "../hooks/use-toast";
import { Skeleton } from "./ui/skeleton";
import { useEffect, useState } from "react";

interface ThreadHistoryProps {
isUserThreadsLoading: boolean;
Expand All @@ -15,46 +15,76 @@ interface ThreadHistoryProps {
userThreads: ThreadActual[];
userId: string | undefined;
createThread: (id: string) => Promise<any>;
clearMessages: () => void;
assistantId: string | undefined;
switchSelectedThread: (thread: ThreadActual) => void;
getUserThreads: (id: string) => Promise<void>;
deleteThread: (id: string) => Promise<void>;
}

interface ThreadProps {
id: string;
onClick: () => void;
onDelete: () => void;
label: string;
createdAt: Date;
}

const Thread = (props: ThreadProps) => (
<Button
className="px-2 hover:bg-[#393939] hover:text-white justify-start"
size="sm"
variant="ghost"
onClick={props.onClick}
>
<p className="truncate ... text-sm font-light">{props.label}</p>
</Button>
);
const Thread = (props: ThreadProps) => {
const [isHovering, setIsHovering] = useState(false);

return (
<div
className="flex flex-row gap-0 items-center justify-start w-full"
onMouseEnter={() => setIsHovering(true)}
onMouseLeave={() => setIsHovering(false)}
>
<Button
className="px-2 hover:bg-[#393939] hover:text-white justify-start items-center flex-grow min-w-[191px] pr-0"
size="sm"
variant="ghost"
onClick={props.onClick}
>
<p className="truncate text-sm font-light w-full text-left">
{props.label}
</p>
</Button>
{isHovering && (
<TooltipIconButton
tooltip="Delete thread"
variant="ghost"
className="hover:bg-[#373737] flex-shrink-0 p-2"
onClick={props.onDelete}
>
<Trash2 className="w-4 h-4 text-[#575757] hover:text-red-500 transition-colors ease-in" />
</TooltipIconButton>
)}
</div>
);
};

const LoadingThread = () => <Skeleton className="w-full h-8 bg-[#373737]" />;

const convertThreadActualToThreadProps = (
thread: ThreadActual,
switchSelectedThread: (thread: ThreadActual) => void,
deleteThread: (id: string) => void,
): ThreadProps => ({
id: thread.thread_id,
label: thread.values?.messages?.[0].content || "Untitled",
createdAt: new Date(thread.created_at),
onClick: () => {
return switchSelectedThread(thread);
},
onDelete: () => {
return deleteThread(thread.thread_id);
},
});

const groupThreads = (
threads: ThreadActual[],
switchSelectedThread: (thread: ThreadActual) => void,
deleteThread: (id: string) => void,
) => {
const today = new Date();
const yesterday = subDays(today, 1);
Expand All @@ -67,14 +97,18 @@ const groupThreads = (
(a, b) =>
new Date(b.created_at).getTime() - new Date(a.created_at).getTime(),
)
.map((t) => convertThreadActualToThreadProps(t, switchSelectedThread)),
.map((t) =>
convertThreadActualToThreadProps(t, switchSelectedThread, deleteThread),
),
yesterday: threads
.filter((thread) => isYesterday(new Date(thread.created_at)))
.sort(
(a, b) =>
new Date(b.created_at).getTime() - new Date(a.created_at).getTime(),
)
.map((t) => convertThreadActualToThreadProps(t, switchSelectedThread)),
.map((t) =>
convertThreadActualToThreadProps(t, switchSelectedThread, deleteThread),
),
lastSevenDays: threads
.filter((thread) =>
isWithinInterval(new Date(thread.created_at), {
Expand All @@ -86,14 +120,18 @@ const groupThreads = (
(a, b) =>
new Date(b.created_at).getTime() - new Date(a.created_at).getTime(),
)
.map((t) => convertThreadActualToThreadProps(t, switchSelectedThread)),
.map((t) =>
convertThreadActualToThreadProps(t, switchSelectedThread, deleteThread),
),
older: threads
.filter((thread) => new Date(thread.created_at) < sevenDaysAgo)
.sort(
(a, b) =>
new Date(b.created_at).getTime() - new Date(a.created_at).getTime(),
)
.map((t) => convertThreadActualToThreadProps(t, switchSelectedThread)),
.map((t) =>
convertThreadActualToThreadProps(t, switchSelectedThread, deleteThread),
),
};
};

Expand Down Expand Up @@ -147,6 +185,7 @@ export function ThreadHistory(props: ThreadHistoryProps) {
const groupedThreads = groupThreads(
props.userThreads,
props.switchSelectedThread,
props.deleteThread,
);

const createThread = async () => {
Expand All @@ -163,6 +202,8 @@ export function ThreadHistory(props: ThreadHistoryProps) {
if (currentThread && !currentThread.values && props.isEmpty) {
return;
}

props.clearMessages();
await props.createThread(props.userId);
// Re-fetch threads so that the new thread shows up.
await props.getUserThreads(props.userId);
Expand Down
97 changes: 26 additions & 71 deletions frontend/app/hooks/useGraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,70 +53,25 @@ export interface GraphInput {
messages?: Record<string, any>[];
}

export function useGraph(userId: string | undefined) {
interface UseGraphInput {
userId: string | undefined;
threadId: string | undefined;
}

export function useGraph(inputArgs: UseGraphInput) {
const { toast } = useToast();
const { getThreadById } = useThreads(userId);
const { getThreadById, setThreadId } = useThreads(inputArgs.userId);
const { shareRun } = useRuns();
const [messages, setMessages] = useState<BaseMessage[]>([]);
const [assistantId, setAssistantId] = useState<string>();
const [threadId, setThreadId] = useState<string>();
const [selectedModel, setSelectedModel] =
useState<ModelOptions>("openai/gpt-4o-mini");

useEffect(() => {
if (threadId || typeof window === "undefined" || !userId) return;
searchOrCreateThread(userId);
}, [userId]);

useEffect(() => {
if (assistantId || typeof window === "undefined") return;
getOrCreateAssistant();
}, []);

const searchOrCreateThread = async (id: string) => {
const threadIdCookie = getCookie("clc_py_thread_id");
if (!threadIdCookie) {
await createThread(id);
return;
}
// Thread ID is in cookies.

const thread = await getThreadById(threadIdCookie);
if (!thread.values) {
// No values = no activity. Can keep.
setThreadId(threadIdCookie);
return;
} else {
// Current thread has activity. Create a new thread.
await createThread(id);
return;
}
};

const createThread = async (id: string) => {
setMessages([]);
const client = createClient();
let thread;
try {
thread = await client.threads.create({
metadata: {
user_id: id,
},
});
if (!thread || !thread.thread_id) {
throw new Error("Thread creation failed.");
}
setThreadId(thread.thread_id);
setCookie("clc_py_thread_id", thread.thread_id);
} catch (e) {
console.error("Error creating thread", e);
toast({
title: "Error creating thread.",
});
}
return thread;
};

const getOrCreateAssistant = async () => {
const assistantIdCookie = getCookie("clc_py_assistant_id");
if (assistantIdCookie) {
Expand All @@ -132,7 +87,7 @@ export function useGraph(userId: string | undefined) {
};

const streamMessage = async (params: GraphInput) => {
if (!threadId) {
if (!inputArgs.threadId) {
toast({
title: "Error",
description: "Thread ID not found",
Expand Down Expand Up @@ -166,7 +121,7 @@ export function useGraph(userId: string | undefined) {
}),
};

const stream = client.runs.stream(threadId, assistantId, {
const stream = client.runs.stream(inputArgs.threadId, assistantId, {
input,
streamMode: "events",
config: {
Expand Down Expand Up @@ -608,22 +563,24 @@ export function useGraph(userId: string | undefined) {
if (runId) {
// Chain `.then` to not block the stream
shareRun(runId).then((sharedRunURL) => {
setMessages((prevMessages) => {
const langSmithToolCallMessage = new AIMessage({
content: "",
id: uuidv4(),
tool_calls: [
{
name: "langsmith_tool_ui",
args: { sharedRunURL },
id: sharedRunURL
?.split("https://smith.langchain.com/public/")[1]
.split("/")[0],
},
],
if (sharedRunURL) {
setMessages((prevMessages) => {
const langSmithToolCallMessage = new AIMessage({
content: "",
id: uuidv4(),
tool_calls: [
{
name: "langsmith_tool_ui",
args: { sharedRunURL },
id: sharedRunURL
?.split("https://smith.langchain.com/public/")[1]
.split("/")[0],
},
],
});
return [...prevMessages, langSmithToolCallMessage];
});
return [...prevMessages, langSmithToolCallMessage];
});
}
});
}
};
Expand Down Expand Up @@ -725,12 +682,10 @@ export function useGraph(userId: string | undefined) {
return {
messages,
assistantId,
threadId,
selectedModel,
setSelectedModel,
setMessages,
streamMessage,
createThread,
switchSelectedThread,
};
}
Loading

0 comments on commit 52567c0

Please sign in to comment.