forked from langchain-ai/open-canvas
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f35aac3
commit 091c071
Showing
7 changed files
with
272 additions
and
168 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,144 +1,11 @@ | ||
"use client"; | ||
import { ArtifactRenderer } from "@/components/artifacts/ArtifactRenderer"; | ||
import { ContentComposerChatInterface } from "@/components/ContentComposer"; | ||
import { useToast } from "@/hooks/use-toast"; | ||
import { useGraph } from "@/hooks/useGraph"; | ||
import { useStore } from "@/hooks/useStore"; | ||
import { getLanguageTemplate } from "@/lib/get_language_template"; | ||
import { cn } from "@/lib/utils"; | ||
import { ProgrammingLanguageOptions } from "@/types"; | ||
import { AIMessage } from "@langchain/core/messages"; | ||
import { useEffect, useState } from "react"; | ||
import { v4 as uuidv4 } from "uuid"; | ||
import { Canvas } from "@/components/Canvas"; | ||
import { AuthProvider } from "../contexts/AuthContext"; | ||
|
||
export default function Home() { | ||
const { toast } = useToast(); | ||
const [chatStarted, setChatStarted] = useState(false); | ||
const [pendingArtifactSelection, setPendingArtifactSelection] = useState< | ||
string | null | ||
>(null); | ||
const [isEditing, setIsEditing] = useState(false); | ||
const { | ||
streamMessage, | ||
setMessages, | ||
setArtifacts, | ||
artifacts, | ||
messages, | ||
setSelectedArtifact, | ||
selectedArtifactId, | ||
createThread, | ||
setArtifactContent, | ||
assistantId, | ||
} = useGraph(); | ||
const { | ||
reflections, | ||
deleteReflections, | ||
getReflections, | ||
isLoadingReflections, | ||
} = useStore(assistantId); | ||
|
||
const createThreadWithChatStarted = async () => { | ||
setChatStarted(false); | ||
return createThread(); | ||
}; | ||
|
||
const handleQuickStart = ( | ||
type: "text" | "code", | ||
language?: ProgrammingLanguageOptions | ||
) => { | ||
if (type === "code" && !language) { | ||
toast({ | ||
title: "Language not selected", | ||
description: "Please select a language to continue", | ||
duration: 5000, | ||
}); | ||
return; | ||
} | ||
setChatStarted(true); | ||
|
||
const artifactId = uuidv4(); | ||
const artifact = { | ||
id: artifactId, | ||
title: `Quickstart ${type}`, | ||
content: | ||
type === "code" | ||
? getLanguageTemplate(language ?? "javascript") | ||
: "# Hello world", | ||
type, | ||
language: language ?? "english", | ||
}; | ||
setArtifacts((prevArtifacts) => [...prevArtifacts, artifact]); | ||
setMessages((prevMessages) => { | ||
const newMessage = new AIMessage({ | ||
content: "", | ||
tool_calls: [ | ||
{ | ||
id: artifactId, | ||
args: { title: artifact.title }, | ||
name: "artifact_ui", | ||
}, | ||
], | ||
}); | ||
return [...prevMessages, newMessage]; | ||
}); | ||
setIsEditing(true); | ||
setPendingArtifactSelection(artifactId); | ||
}; | ||
|
||
useEffect(() => { | ||
if (pendingArtifactSelection) { | ||
setSelectedArtifact(pendingArtifactSelection); | ||
setPendingArtifactSelection(null); | ||
} | ||
}, [artifacts, pendingArtifactSelection, setSelectedArtifact]); | ||
|
||
return ( | ||
<main className="h-screen flex flex-row"> | ||
<div | ||
className={cn( | ||
"transition-all duration-700", | ||
chatStarted ? "w-[35%]" : "w-full", | ||
"h-full mr-auto bg-gray-50/70 shadow-inner-right" | ||
)} | ||
> | ||
<ContentComposerChatInterface | ||
handleGetReflections={getReflections} | ||
handleDeleteReflections={deleteReflections} | ||
reflections={reflections} | ||
isLoadingReflections={isLoadingReflections} | ||
setSelectedArtifact={setSelectedArtifact} | ||
streamMessage={streamMessage} | ||
setArtifacts={setArtifacts} | ||
messages={messages} | ||
setMessages={setMessages} | ||
createThread={createThreadWithChatStarted} | ||
setChatStarted={setChatStarted} | ||
showNewThreadButton={chatStarted} | ||
handleQuickStart={handleQuickStart} | ||
/> | ||
</div> | ||
{chatStarted && ( | ||
<div className="w-full ml-auto"> | ||
<ArtifactRenderer | ||
handleGetReflections={getReflections} | ||
handleDeleteReflections={deleteReflections} | ||
reflections={reflections} | ||
isLoadingReflections={isLoadingReflections} | ||
setIsEditing={setIsEditing} | ||
isEditing={isEditing} | ||
setArtifactContent={setArtifactContent} | ||
setSelectedArtifactById={setSelectedArtifact} | ||
messages={messages} | ||
setMessages={setMessages} | ||
artifact={ | ||
selectedArtifactId | ||
? artifacts.find((a) => a.id === selectedArtifactId) | ||
: undefined | ||
} | ||
streamMessage={streamMessage} | ||
/> | ||
</div> | ||
)} | ||
</main> | ||
<AuthProvider> | ||
<Canvas /> | ||
</AuthProvider> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
"use client"; | ||
import { ArtifactRenderer } from "@/components/artifacts/ArtifactRenderer"; | ||
import { ContentComposerChatInterface } from "@/components/ContentComposer"; | ||
import { useToast } from "@/hooks/use-toast"; | ||
import { useGraph } from "@/hooks/useGraph"; | ||
import { useStore } from "@/hooks/useStore"; | ||
import { getLanguageTemplate } from "@/lib/get_language_template"; | ||
import { cn } from "@/lib/utils"; | ||
import { ProgrammingLanguageOptions } from "@/types"; | ||
import { AIMessage } from "@langchain/core/messages"; | ||
import { useEffect, useState } from "react"; | ||
import { v4 as uuidv4 } from "uuid"; | ||
|
||
export function Canvas() { | ||
const { toast } = useToast(); | ||
const [chatStarted, setChatStarted] = useState(false); | ||
const [pendingArtifactSelection, setPendingArtifactSelection] = useState< | ||
string | null | ||
>(null); | ||
const [isEditing, setIsEditing] = useState(false); | ||
const { | ||
streamMessage, | ||
setMessages, | ||
setArtifacts, | ||
artifacts, | ||
messages, | ||
setSelectedArtifact, | ||
selectedArtifactId, | ||
createThread, | ||
setArtifactContent, | ||
assistantId, | ||
} = useGraph(); | ||
const { | ||
reflections, | ||
deleteReflections, | ||
getReflections, | ||
isLoadingReflections, | ||
} = useStore(assistantId); | ||
|
||
const createThreadWithChatStarted = async () => { | ||
setChatStarted(false); | ||
return createThread(); | ||
}; | ||
|
||
const handleQuickStart = ( | ||
type: "text" | "code", | ||
language?: ProgrammingLanguageOptions | ||
) => { | ||
if (type === "code" && !language) { | ||
toast({ | ||
title: "Language not selected", | ||
description: "Please select a language to continue", | ||
duration: 5000, | ||
}); | ||
return; | ||
} | ||
setChatStarted(true); | ||
|
||
const artifactId = uuidv4(); | ||
const artifact = { | ||
id: artifactId, | ||
title: `Quickstart ${type}`, | ||
content: | ||
type === "code" | ||
? getLanguageTemplate(language ?? "javascript") | ||
: "# Hello world", | ||
type, | ||
language: language ?? "english", | ||
}; | ||
setArtifacts((prevArtifacts) => [...prevArtifacts, artifact]); | ||
setMessages((prevMessages) => { | ||
const newMessage = new AIMessage({ | ||
content: "", | ||
tool_calls: [ | ||
{ | ||
id: artifactId, | ||
args: { title: artifact.title }, | ||
name: "artifact_ui", | ||
}, | ||
], | ||
}); | ||
return [...prevMessages, newMessage]; | ||
}); | ||
setIsEditing(true); | ||
setPendingArtifactSelection(artifactId); | ||
}; | ||
|
||
useEffect(() => { | ||
if (pendingArtifactSelection) { | ||
setSelectedArtifact(pendingArtifactSelection); | ||
setPendingArtifactSelection(null); | ||
} | ||
}, [artifacts, pendingArtifactSelection, setSelectedArtifact]); | ||
|
||
return ( | ||
<main className="h-screen flex flex-row"> | ||
<div | ||
className={cn( | ||
"transition-all duration-700", | ||
chatStarted ? "w-[35%]" : "w-full", | ||
"h-full mr-auto bg-gray-50/70 shadow-inner-right" | ||
)} | ||
> | ||
<ContentComposerChatInterface | ||
handleGetReflections={getReflections} | ||
handleDeleteReflections={deleteReflections} | ||
reflections={reflections} | ||
isLoadingReflections={isLoadingReflections} | ||
setSelectedArtifact={setSelectedArtifact} | ||
streamMessage={streamMessage} | ||
setArtifacts={setArtifacts} | ||
messages={messages} | ||
setMessages={setMessages} | ||
createThread={createThreadWithChatStarted} | ||
setChatStarted={setChatStarted} | ||
showNewThreadButton={chatStarted} | ||
handleQuickStart={handleQuickStart} | ||
/> | ||
</div> | ||
{chatStarted && ( | ||
<div className="w-full ml-auto"> | ||
<ArtifactRenderer | ||
handleGetReflections={getReflections} | ||
handleDeleteReflections={deleteReflections} | ||
reflections={reflections} | ||
isLoadingReflections={isLoadingReflections} | ||
setIsEditing={setIsEditing} | ||
isEditing={isEditing} | ||
setArtifactContent={setArtifactContent} | ||
setSelectedArtifactById={setSelectedArtifact} | ||
messages={messages} | ||
setMessages={setMessages} | ||
artifact={ | ||
selectedArtifactId | ||
? artifacts.find((a) => a.id === selectedArtifactId) | ||
: undefined | ||
} | ||
streamMessage={streamMessage} | ||
/> | ||
</div> | ||
)} | ||
</main> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { useAuth } from "../contexts/AuthContext"; | ||
import { useRouter } from "next/router"; | ||
|
||
const ProtectedRoute = ({ children }: { children: React.ReactNode }) => { | ||
const auth = useAuth(); | ||
const router = useRouter(); | ||
|
||
if (!auth?.user) { | ||
router.push("/login"); | ||
return null; | ||
} | ||
|
||
return children; | ||
}; | ||
|
||
export default ProtectedRoute; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import { createSupabaseClient } from "@/lib/supabase"; | ||
import React, { createContext, useState, useEffect, useContext } from "react"; | ||
import { | ||
SignInWithPasswordCredentials, | ||
SignUpWithPasswordCredentials, | ||
User, | ||
} from "@supabase/supabase-js"; | ||
|
||
interface AuthContextType { | ||
signUp: (data: SignUpWithPasswordCredentials) => Promise<any>; | ||
signIn: (data: SignInWithPasswordCredentials) => Promise<any>; | ||
signOut: () => Promise<any>; | ||
user: User | undefined; | ||
} | ||
|
||
const AuthContext = createContext<AuthContextType | undefined>(undefined); | ||
|
||
export const AuthProvider = ({ children }: { children: React.ReactNode }) => { | ||
const supabase = createSupabaseClient(); | ||
const [user, setUser] = useState<User>(); | ||
const [loading, setLoading] = useState(true); | ||
|
||
useEffect(() => { | ||
const getSupabaseUser = async () => { | ||
const { | ||
data: { session }, | ||
} = await supabase.auth.getSession(); | ||
setUser(session?.user); | ||
setLoading(false); | ||
}; | ||
|
||
getSupabaseUser(); | ||
|
||
const { data: listener } = supabase.auth.onAuthStateChange( | ||
async (event, session) => { | ||
setUser(session?.user); | ||
setLoading(false); | ||
} | ||
); | ||
|
||
return () => { | ||
listener?.subscription.unsubscribe(); | ||
}; | ||
}, [supabase.auth]); | ||
|
||
const value = { | ||
signUp: (data: SignUpWithPasswordCredentials) => supabase.auth.signUp(data), | ||
signIn: (data: SignInWithPasswordCredentials) => | ||
supabase.auth.signInWithPassword(data), | ||
signOut: () => supabase.auth.signOut(), | ||
user, | ||
}; | ||
|
||
return ( | ||
<AuthContext.Provider value={value}> | ||
{!loading && children} | ||
</AuthContext.Provider> | ||
); | ||
}; | ||
|
||
export const useAuth = () => { | ||
return useContext(AuthContext); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { createClient } from "@supabase/supabase-js"; | ||
|
||
export const createSupabaseClient = () => { | ||
if (!process.env.NEXT_PUBLIC_SUPABASE_URL) { | ||
throw new Error("NEXT_PUBLIC_SUPABASE_URL is not defined"); | ||
} | ||
if (!process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY) { | ||
throw new Error("NEXT_PUBLIC_SUPABASE_ANON_KEY is not defined"); | ||
} | ||
return createClient( | ||
process.env.NEXT_PUBLIC_SUPABASE_URL, | ||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY | ||
); | ||
}; |
Oops, something went wrong.