Skip to content

Commit

Permalink
many fixes and enhancements for ai chat
Browse files Browse the repository at this point in the history
  • Loading branch information
seveibar committed Oct 5, 2024
1 parent 0981a00 commit 524da01
Show file tree
Hide file tree
Showing 8 changed files with 210 additions and 26 deletions.
36 changes: 31 additions & 5 deletions src/components/AiChatInterface.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,23 @@ import { createCircuitBoard1Template } from "@tscircuit/prompt-benchmarks"
import { TextDelta } from "@anthropic-ai/sdk/resources/messages.mjs"
import { MagicWandIcon } from "@radix-ui/react-icons"
import { AiChatMessage } from "./AiChatMessage"
import { useLocation } from "wouter"
import { Link, useLocation } from "wouter"
import { useSnippet } from "@/hooks/use-snippet"
import { Edit2 } from "lucide-react"
import { SnippetLink } from "./SnippetLink"

export default function AIChatInterface({
code,
hasUnsavedChanges,
snippetId,
onCodeChange,
onStartStreaming,
onStopStreaming,
errorMessage,
}: {
code: string
hasUnsavedChanges: boolean
snippetId?: string | null
onCodeChange: (code: string) => void
onStartStreaming: () => void
onStopStreaming: () => void
Expand All @@ -25,8 +32,9 @@ export default function AIChatInterface({
const [isStreaming, setIsStreaming] = useState(false)
const anthropic = useAiApi()
const messagesEndRef = useRef<HTMLDivElement>(null)
const { data: snippet } = useSnippet(snippetId!)
const [currentCodeBlock, setCurrentCodeBlock] = useState<string | null>(null)
const [location] = useLocation()
const [location, navigate] = useLocation()

useEffect(() => {
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" })
Expand Down Expand Up @@ -61,7 +69,7 @@ export default function AIChatInterface({
content: message,
},
],
max_tokens: 4096,
max_tokens: 1000,
})

let accumulatedContent = ""
Expand Down Expand Up @@ -130,9 +138,27 @@ export default function AIChatInterface({
return (
<div className="flex flex-col h-[calc(100vh-60px)] max-w-2xl mx-auto p-4 bg-gray-100">
<div className="flex-1 overflow-y-auto space-y-4 mb-4">
{snippet && (
<div className="flex pl-4 p-2 rounded items-center bg-white border border-gray-200 text-sm mb-4 shadow-sm">
<SnippetLink snippet={snippet} />
<div className="flex-grow" />
<Button
size="sm"
className="text-xs"
variant="ghost"
onClick={async () => {
navigate(`/editor?snippet_id=${snippet.snippet_id}`)
}}
disabled={hasUnsavedChanges}
>
Open in Editor
<Edit2 className="w-3 h-3 ml-2 opacity-60" />
</Button>
</div>
)}
{messages.length === 0 && (
<div className="text-gray-500 text-xl text-center mt-[30vh] flex flex-col items-center">
<div>Submit a prompt to get started!</div>
<div className="text-gray-500 text-xl text-center pt-[30vh] flex flex-col items-center">
<div>Submit a prompt to {snippet ? "edit!" : "get started!"}</div>
<div className="text-6xl mt-4"></div>
</div>
)}
Expand Down
2 changes: 1 addition & 1 deletion src/components/DownloadButtonAndMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export function DownloadButtonAndMenu({ className }: { className?: string }) {
<div className={className}>
<DropdownMenu>
<DropdownMenuTrigger>
<Button variant="outline" size="sm" className="h-6 px-2 text-xs">
<Button variant="ghost" size="sm" className="px-2 text-xs">
<Download className="mr-1 h-3 w-3" />
Download
<ChevronDown className="ml-1 h-3 w-3" />
Expand Down
29 changes: 20 additions & 9 deletions src/components/EditorNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ import {
EyeIcon,
CodeIcon,
Menu,
Sparkles,
} from "lucide-react"
import { Link } from "wouter"
import { Link, useLocation } from "wouter"
import { Button } from "@/components/ui/button"
import {
DropdownMenu,
Expand All @@ -30,6 +31,7 @@ import { useState, useEffect } from "react"
import { cn } from "@/lib/utils"
import { DownloadButtonAndMenu } from "./DownloadButtonAndMenu"
import { TypeBadge } from "./TypeBadge"
import { SnippetLink } from "./SnippetLink"

export default function EditorNav({
snippet,
Expand All @@ -48,11 +50,11 @@ export default function EditorNav({
isSaving: boolean
onSave: () => void
}) {
const [, navigate] = useLocation()
return (
<nav className="flex items-center justify-between px-2 py-3 border-b border-gray-200 bg-white text-sm border-t">
<div className="flex items-center space-x-1">
{/* <span className="text-base font-semibold">»</span> */}
<span className="text-md font-semibold">{snippet.name}</span>
<SnippetLink snippet={snippet} />
<Link href={`/${snippet.name}`}>
<Button variant="ghost" size="icon" className="h-6 w-6 ml-1">
<OpenInNewWindowIcon className="h-3 w-3 text-gray-700" />
Expand Down Expand Up @@ -98,13 +100,22 @@ export default function EditorNav({
</div>
)}
</div>
<div className="flex items-center space-x-2">
<div className="flex items-center space-x-1">
{snippet && <TypeBadge type={snippet.snippet_type} />}
<Button
variant="ghost"
size="sm"
disabled={hasUnsavedChanges || isSaving}
onClick={() => navigate(`/ai?snippet_id=${snippet.snippet_id}`)}
>
<Sparkles className="mr-1 h-3 w-3" />
Edit with AI
</Button>
<DownloadButtonAndMenu className="hidden md:flex" />
<Button
variant="outline"
variant="ghost"
size="sm"
className="hidden md:flex h-6 px-2 text-xs"
className="hidden md:flex px-2 text-xs"
onClick={() => {
const url = encodeTextToUrlHash(code)
navigator.clipboard.writeText(url)
Expand All @@ -115,9 +126,9 @@ export default function EditorNav({
Copy URL
</Button>
<Button
variant="outline"
variant="ghost"
size="sm"
className="hidden md:flex h-6 px-2 text-xs"
className="hidden md:flex px-2 text-xs"
>
<Eye className="mr-1 h-3 w-3" />
Public
Expand All @@ -126,7 +137,7 @@ export default function EditorNav({
variant="ghost"
size="icon"
className={cn(
"h-6 w-6 hidden md:flex",
"hidden md:flex",
!previewOpen
? "bg-blue-600 text-white hover:bg-blue-700 hover:text-white"
: "",
Expand Down
29 changes: 29 additions & 0 deletions src/components/SnippetLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Link } from "wouter"

export const SnippetLink = ({
snippet,
}: {
snippet: {
owner_name: string
name: string
unscoped_name: string
}
}) => {
return (
<>
<Link
className="text-blue-500 font-semibold hover:underline"
href={`/${snippet.owner_name}`}
>
{snippet.owner_name}
</Link>
<span className="px-0.5 text-gray-500">/</span>
<Link
className="text-blue-500 font-semibold hover:underline"
href={`/${snippet.name}`}
>
{snippet.unscoped_name}
</Link>
</>
)
}
49 changes: 45 additions & 4 deletions src/components/ViewSnippetSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@ import {
import { GitHubLogoIcon } from "@radix-ui/react-icons"
import { cn } from "@/lib/utils"
import { useCurrentSnippet } from "@/hooks/use-current-snippet"
import { useToast } from "@/hooks/use-toast"

export default function ViewSnippetSidebar({
className,
}: { className?: string }) {
const { snippet } = useCurrentSnippet()
const { toast } = useToast()

return (
<div
className={cn(
Expand All @@ -41,20 +44,58 @@ export default function ViewSnippetSidebar({
icon: <Bot className="w-5 h-5" />,
label: "Edit with AI",
badge: "AI",
href: `/ai?snippet_id=${snippet?.snippet_id}`,
},
// {
// icon: <GitHubLogoIcon className="w-5 h-5" />,
// label: "Github",
// },
{ icon: <GitFork className="w-5 h-5" />, label: "Forks" },
{ icon: <AtSign className="w-5 h-5" />, label: "References" },
{ icon: <Package className="w-5 h-5" />, label: "Dependencies" },
{ icon: <Clock className="w-5 h-5" />, label: "Versions" },
{
icon: <GitFork className="w-5 h-5" />,
label: "Forks",
notImplemented: true,
},
{
icon: <AtSign className="w-5 h-5" />,
label: "References",
notImplemented: true,
},
{
icon: <Package className="w-5 h-5" />,
label: "Dependencies",
notImplemented: true,
},
{
icon: <Clock className="w-5 h-5" />,
label: "Versions",
notImplemented: true,
},
// { icon: <Settings className="w-5 h-5" />, label: "Settings" },
].map((item, index) => (
<li key={index}>
<Link
href={item.href ?? "#"}
onClick={
item.notImplemented
? () => {
toast({
title: "Not Implemented!",
description: (
<div>
The {item.label} selection is not implemented yet.
Help us out!{" "}
<a
className="text-blue-500 hover:underline font-semibold"
href="https://github.com/tscircuit/snippets"
>
Check out our Github
</a>
</div>
),
})
}
: undefined
}
className="flex items-center gap-3 px-2 py-1.5 hover:bg-gray-200 rounded-md"
>
{item.icon}
Expand Down
2 changes: 1 addition & 1 deletion src/components/ui/toast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const ToastViewport = React.forwardRef<
<ToastPrimitives.Viewport
ref={ref}
className={cn(
"fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]",
"fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:top-0 sm:right-0 sm:flex-col md:max-w-[420px]",
className,
)}
{...props}
Expand Down
33 changes: 33 additions & 0 deletions src/hooks/use-save-snippet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { useState } from "react"
import { useAxios } from "./use-axios"
import { useMutation } from "react-query"
import { Snippet } from "fake-snippets-api/lib/db/schema"

export const useSaveSnippet = () => {
const axios = useAxios()

const saveSnippetMutation = useMutation<
Snippet,
Error,
{ code: string; snippet_type: string }
>({
mutationFn: async ({ code, snippet_type }) => {
const response = await axios.post("/snippets/create", {
code,
snippet_type,
owner_name: "seveibar", // Replace with actual user name or fetch from user context
})
return response.data.snippet
},
})

const saveSnippet = async (code: string, snippet_type: string) => {
return saveSnippetMutation.mutateAsync({ code, snippet_type })
}

return {
saveSnippet,
isLoading: saveSnippetMutation.isLoading,
error: saveSnippetMutation.error,
}
}
Loading

0 comments on commit 524da01

Please sign in to comment.