Skip to content

Commit

Permalink
integrate chat CPT
Browse files Browse the repository at this point in the history
  • Loading branch information
molti-tasking committed Dec 13, 2024
1 parent ea99a4a commit f88ac27
Show file tree
Hide file tree
Showing 7 changed files with 244 additions and 28 deletions.
3 changes: 2 additions & 1 deletion .env.template
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
ALPHAVANTAGE_API_KEY='YOUR API KEY TO FETCH STOCK DATA'
ALPHAVANTAGE_API_KEY='YOUR API KEY TO FETCH STOCK DATA'
VITE_OPENAI_API_KEY='YOUR API KEY TO USE AN LLM'
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"deck.gl": "^9.0.35",
"lodash": "^4.17.21",
"lucide-react": "^0.452.0",
"openai": "^4.76.2",
"plotly.js": "^2.35.2",
"react": "^18.3.1",
"react-dom": "18.3.1",
Expand Down
38 changes: 33 additions & 5 deletions src/components/ExplorationStuff.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import {
DialogTrigger,
} from "@/components/ui/dialog";
import { useExploratoryStore } from "@/store/useExploratoryStore";
import { MountainIcon, StarsIcon } from "lucide-react";
import { Loader2, MountainIcon, StarsIcon } from "lucide-react";
import { useState } from "react";

export const ExplorationStuff = () => {
const activateIdeaSelection = useExploratoryStore(
Expand All @@ -20,13 +21,21 @@ export const ExplorationStuff = () => {
(state) => state.requestSuggestion
);
const events = useExploratoryStore((state) => state.events);
const suggestion = useExploratoryStore((state) => state.suggestion);

const [isLoading, setIsLoading] = useState<boolean>(false);

const onRequest = async () => {
setIsLoading(true);
await requestSuggestion().finally(() => setIsLoading(false));
};

return (
<Dialog>
<DialogTrigger>
<StarsIcon />
</DialogTrigger>
<DialogContent>
<DialogContent className="max-w-4xl">
<DialogHeader>
<DialogTitle>AI Data Exploration</DialogTitle>
<DialogDescription>
Expand All @@ -38,6 +47,20 @@ export const ExplorationStuff = () => {
<div className="my-2">
You already collected {events.length} Events.
</div>

{suggestion && (
<div className="py-2">
<strong className="flex items-center gap-2 mb-2">
AI Suggestion <StarsIcon />
</strong>

<div className="bg-blue-100 rounded-md p-4">
<pre className="whitespace-break-spaces max-h-80 overflow-scroll">
{suggestion}
</pre>
</div>
</div>
)}
<DialogFooter>
<DialogClose>
<Button
Expand All @@ -49,10 +72,15 @@ export const ExplorationStuff = () => {
</DialogClose>
<Button
variant={"secondary"}
disabled={!events.length}
onClick={() => requestSuggestion()}
disabled={!events.length || isLoading}
onClick={onRequest}
>
<StarsIcon className="mr-2" /> Generate Hypothesis
{isLoading ? (
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
) : (
<StarsIcon className="mr-2" />
)}
Generate Hypothesis
</Button>
</DialogFooter>
</DialogContent>
Expand Down
51 changes: 51 additions & 0 deletions src/lib/ai-chat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { ExplorationEvent } from "@/store/useExploratoryStore";

const OPENAI_API_KEY = import.meta.env.VITE_OPENAI_API_KEY;
console.log("Open api key ", OPENAI_API_KEY);

export async function fetchResearchCompletion(
events: ExplorationEvent[]
): Promise<string> {
const url = "https://api.openai.com/v1/chat/completions";

const requestBody = {
model: "gpt-4o",
messages: [
{
role: "system",
content:
"We are domain experts with a lot of time based data. We have many parallel time series and we explore the data in order to generate hypothesis for our research. In the next message we have collected certain user events and meta data.",
},
{
role: "user",
content: JSON.stringify(events),
},
{
role: "user",
content:
"Based on this information, generate one or more precise research hypothesis.",
},
],
};

const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${OPENAI_API_KEY}`,
},
body: JSON.stringify(requestBody),
});

if (!response.ok) {
console.error("Error:", response.status, response.statusText);
const errorDetails = await response.json();
console.error("Details:", errorDetails);
throw new Error("ERROR: " + String(errorDetails));
}

const data = await response.json();
console.log("Response: ", data);
const content = data.choices[0].message.content;
return content;
}
55 changes: 35 additions & 20 deletions src/store/useExploratoryStore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import { Input } from "@/components/ui/input";
import { ToastAction } from "@/components/ui/toast";
import { toast } from "@/hooks/use-toast";
import { ChartPresentationSettings } from "@/lib/ChartPresentationSettings";
import { fetchResearchCompletion } from "@/lib/ai-chat";
import { useState } from "react";

type ExplorationEvent = {
export type ExplorationEvent = {
userMessage?: string | undefined;
systemMessage?: string | undefined;
payload: object;
Expand All @@ -24,7 +25,7 @@ interface DataStore {
) => void;
addDataIdeaEvent: (payload: object) => void;

requestSuggestion: () => void;
requestSuggestion: () => Promise<void>;
}

const FeedbackForm = ({
Expand All @@ -36,7 +37,7 @@ const FeedbackForm = ({

return (
<div>
<div className="max-w-sm">
<div className="max-w-sm mb-1">
<Input
type="search"
id="clusterAssignmentHistoryDepth"
Expand All @@ -45,19 +46,21 @@ const FeedbackForm = ({
onChange={(e) => setFeedback(e.target.value)}
/>
</div>
<ToastAction
onClick={() => onSubmitFeedback(true, feedback)}
altText="Good"
>
Good
</ToastAction>

<ToastAction
onClick={() => onSubmitFeedback(false, feedback)}
altText="Bad"
>
Bad
</ToastAction>
<div className="flex flex-row gap-1 items-center">
<ToastAction
onClick={() => onSubmitFeedback(true, feedback)}
altText="Good"
>
Good
</ToastAction>

<ToastAction
onClick={() => onSubmitFeedback(false, feedback)}
altText="Bad"
>
Bad
</ToastAction>
</div>
</div>
);
};
Expand All @@ -81,8 +84,8 @@ export const useExploratoryStore = create<DataStore>((set, get) => {
};

toast({
title: "Uh oh! Something went wrong.",
description: "There was a problem with your request.",
title: "You updated the view settings.",
description: "How helpful was it?",
action: <FeedbackForm onSubmitFeedback={onSubmitFeedback} />,
});
};
Expand Down Expand Up @@ -130,8 +133,20 @@ export const useExploratoryStore = create<DataStore>((set, get) => {
set({ events: newUserEvents });
};

const requestSuggestion = () => {
alert("This says the AI: What's up?");
const requestSuggestion = async () => {
try {
const answer = await fetchResearchCompletion(get().events);
console.log("answer", answer);
if (typeof answer === "string") {
set({ suggestion: answer });
}
} catch (error) {
alert(
`We couldn't generate data: ${String(
"message" in error ? error.message : error
)}`
);
}
};

return {
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"],
"include": ["src", "openai.ts"],
"exclude": ["util/*"],
"references": [
{
Expand Down
Loading

0 comments on commit f88ac27

Please sign in to comment.