Skip to content

Commit

Permalink
Merge branch 'development' of github.com:Scale3-Labs/langtrace into d…
Browse files Browse the repository at this point in the history
…evelopment
  • Loading branch information
karthikscale3 committed May 22, 2024
2 parents 020a3a9 + 20d4132 commit b9b73db
Show file tree
Hide file tree
Showing 5 changed files with 584 additions and 271 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export default function Page() {
const router = useRouter();
const [prompts, setPrompts] = useState<Prompt[]>([]);
const [selectedPrompt, setSelectedPrompt] = useState<Prompt>();
const [createDialogOpen, setCreateDialogOpen] = useState<boolean>(false);
const [live, setLive] = useState<boolean>(false);
const queryClient = useQueryClient();

Expand Down Expand Up @@ -72,6 +73,8 @@ export default function Page() {
<CreatePromptDialog
promptsetId={promptsetId}
version={prompts.length + 1}
open={createDialogOpen}
setOpen={setCreateDialogOpen}
/>
</div>
</div>
Expand All @@ -93,11 +96,15 @@ export default function Page() {
currentPrompt={selectedPrompt}
promptsetId={promptsetId}
version={prompts.length + 1}
open={createDialogOpen}
setOpen={setCreateDialogOpen}
/>
) : (
<CreatePromptDialog
promptsetId={promptsetId}
version={prompts.length + 1}
open={createDialogOpen}
setOpen={setCreateDialogOpen}
/>
)}
</div>
Expand Down Expand Up @@ -247,7 +254,6 @@ function PageLoading() {
<ChevronLeft className="w-6 h-6 mr-2" />
Back
</Button>
<CreatePromptDialog promptsetId={""} disabled={true} />
</div>
<div className="flex gap-4 w-full h-screen">
<Skeleton className="w-[340px] h-screen" />
Expand Down
93 changes: 78 additions & 15 deletions components/playground/common.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
"use client";

import PromptRegistryDialog from "@/components/playground/prompt-registry-dialog";
import LLMPicker from "@/components/shared/llm-picker";
import { Button } from "@/components/ui/button";
import { Separator } from "@/components/ui/separator";
Expand All @@ -9,6 +12,8 @@ import {
import { cn } from "@/lib/utils";
import { MinusCircleIcon, PlusIcon } from "lucide-react";
import { useEffect, useRef, useState } from "react";
import { useQuery } from "react-query";
import { toast } from "sonner";

export function RoleBadge({
role,
Expand All @@ -34,15 +39,24 @@ export function ExpandingTextArea({
value,
onChange,
setFocusing,
saveButtonRef,
handleSave,
}: {
value: string;
onChange: any;
setFocusing?: any;
saveButtonRef: React.RefObject<HTMLButtonElement>;
handleSave: (open: boolean) => void;
}) {
const textAreaRef = useRef<HTMLTextAreaElement>(null);

const handleClickOutside = (event: any) => {
if (textAreaRef.current && !textAreaRef.current.contains(event.target)) {
if (
textAreaRef.current &&
!textAreaRef.current.contains(event.target) &&
saveButtonRef.current &&
!saveButtonRef.current.contains(event.target)
) {
setFocusing(false);
}
};
Expand All @@ -63,13 +77,25 @@ export function ExpandingTextArea({
};

return (
<textarea
className="rounded-md text-sm w-[290px] bg-background"
ref={textAreaRef}
defaultValue={value}
onChange={handleChange}
style={{ overflowY: "auto", resize: "none", height: "auto" }}
/>
<div className="relative w-[290px]">
<textarea
className="rounded-md text-sm w-[290px] bg-background pr-10"
ref={textAreaRef}
defaultValue={value}
onChange={handleChange}
style={{ overflowY: "auto", resize: "none", height: "auto" }}
/>
<div className="absolute right-2 bottom-2 py-2">
<Button
className="text-sm px-6"
size={"icon"}
onClick={() => handleSave(true)}
ref={saveButtonRef}
>
Save
</Button>
</div>
</div>
);
}

Expand Down Expand Up @@ -107,6 +133,34 @@ export function Message({
}
};
const [editing, setEditing] = useState(false);
const [dialogOpen, setDialogOpen] = useState(false);
const [selectedPromptRegistry, setSelectedPromptRegistry] =
useState<any>(null);
const saveButtonRef = useRef<HTMLButtonElement>(null);
const [currentPrompt, setCurrentPrompt] = useState<any>(undefined);

useQuery({
queryKey: ["fetch-prompts-query", selectedPromptRegistry?.id],
queryFn: async () => {
const response = await fetch(
`/api/promptset?promptset_id=${selectedPromptRegistry?.id}`
);
if (!response.ok) {
const error = await response.json();
throw new Error(error?.message || "Failed to fetch tests");
}
const result = await response.json();
setCurrentPrompt(result?.promptsets?.prompts[0] || undefined);
return result;
},
enabled: !!selectedPromptRegistry,
onError: (error) => {
toast.error("Failed to fetch prompts", {
description: error instanceof Error ? error.message : String(error),
});
},
});

return (
<>
<div className="flex items-center justify-between cursor-pointer group hover:bg-muted rounded-md p-4">
Expand All @@ -129,13 +183,17 @@ export function Message({
</p>
)}
{editing && (
<ExpandingTextArea
onChange={(value: string) => {
setMessage({ ...message, content: value });
}}
value={message.content}
setFocusing={setEditing}
/>
<div>
<ExpandingTextArea
onChange={(value: string) => {
setMessage({ ...message, content: value });
}}
value={message.content}
setFocusing={setEditing}
saveButtonRef={saveButtonRef}
handleSave={setDialogOpen}
/>
</div>
)}
</div>
</div>
Expand All @@ -151,6 +209,11 @@ export function Message({
</Button>
</div>
<Separator />
<PromptRegistryDialog
openDialog={dialogOpen}
setOpenDialog={setDialogOpen}
passedPrompt={message.content}
/>
</>
);
}
Expand Down
206 changes: 206 additions & 0 deletions components/playground/prompt-registry-dialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
"use client";

import { CreatePromptset } from "@/components/project/dataset/create";
import { Button } from "@/components/ui/button";
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
} from "@/components/ui/command";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Label } from "@/components/ui/label";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { cn } from "@/lib/utils";
import { Check, ChevronsUpDown } from "lucide-react";
import { usePathname } from "next/navigation";
import * as React from "react";
import { useQuery } from "react-query";
import { toast } from "sonner";
import CreatePromptDialog from "../shared/create-prompt-dialog";

import { Promptset } from "@prisma/client";

export interface PromptRegistryDialogProps {
openDialog?: boolean;
setOpenDialog: (open: boolean) => void;
passedPrompt: string;
}

export default function PromptRegistryDialog({
openDialog = false,
setOpenDialog,
passedPrompt,
}: PromptRegistryDialogProps) {
const [selectedPromptsetId, setSelectedPromptsetId] = React.useState("");
const [busy, setBusy] = React.useState(false);
const [open, setOpen] = React.useState(false);
const [prompts, setPrompts] = React.useState([]);

const fetchPrompts = async () => {
setBusy(true);
try {
const response = await fetch(
`/api/promptset?promptset_id=${selectedPromptsetId}`
);
if (!response.ok) {
const error = await response.json();
throw new Error(error?.message || "Failed to fetch prompts");
}
const result = await response.json();
setPrompts(result?.promptsets?.prompts || []);
setBusy(false);
} catch (error) {
toast.error("Failed to fetch prompts", {
description: error instanceof Error ? error.message : String(error),
});
setBusy(false);
}
};

return (
<Dialog open={openDialog} onOpenChange={setOpenDialog}>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>Save to Registry</DialogTitle>
<DialogDescription>
Save the selected prompt to a registry.
</DialogDescription>
</DialogHeader>
<div className="flex flex-col gap-2">
<Label htmlFor="name" className="text-left">
Select a registry
</Label>
<PromptRegistryCombobox
selectedPromptsetId={selectedPromptsetId}
setSelectedPromptsetId={setSelectedPromptsetId}
/>
</div>
<DialogFooter>
<Button
disabled={busy || !selectedPromptsetId}
onClick={async () => {
setOpen(true);
setSelectedPromptsetId(selectedPromptsetId);
await fetchPrompts();
}}
>
Save
</Button>
</DialogFooter>
<CreatePromptDialog
open={open}
setOpen={setOpen}
promptsetId={selectedPromptsetId}
passedPrompt={passedPrompt}
showButton={false}
version={prompts.length + 1}
currentPrompt={prompts[0]}
setOpenDialog={setOpenDialog}
/>
</DialogContent>
</Dialog>
);
}

export function PromptRegistryCombobox({
selectedPromptsetId,
setSelectedPromptsetId,
}: {
selectedPromptsetId: string;
setSelectedPromptsetId: (promptsetId: string) => void;
}) {
const pathname = usePathname();
const projectId = pathname.split("/")[2];
const [open, setOpen] = React.useState(false);

const {
data: promptsets,
isLoading: promptsetsLoading,
error: promptsetsError,
} = useQuery({
queryKey: ["fetch-promptsets-query", projectId],
queryFn: async () => {
const response = await fetch(`/api/promptset?id=${projectId}`);
if (!response.ok) {
const error = await response.json();
throw new Error(error?.message || "Failed to fetch prompt sets");
}
const result = await response.json();

return result;
},
onError: (error) => {
toast.error("Failed to fetch prompt sets", {
description: error instanceof Error ? error.message : String(error),
});
},
});

if (promptsetsLoading) {
return <div>Loading...</div>;
}

return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
role="combobox"
aria-expanded={open}
className="w-[250px] justify-between"
>
{selectedPromptsetId
? promptsets?.promptsets?.find(
(promptset: Promptset) => promptset.id === selectedPromptsetId
)?.name
: "Select promptset..."}
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent className="w-[250px] p-0">
<Command>
<CommandInput placeholder="Search framework..." />
<CommandEmpty>No promptset found.</CommandEmpty>
<CommandGroup>
{promptsets?.promptsets?.map((promptset: Promptset) => (
<CommandItem
key={promptset.id}
value={promptset.id}
onSelect={(currentValue) => {
setSelectedPromptsetId(currentValue);
setOpen(false);
}}
>
<Check
className={cn(
"mr-2 h-4 w-4",
selectedPromptsetId === promptset.id
? "opacity-100"
: "opacity-0"
)}
/>
{promptset.name}
</CommandItem>
))}
<CommandItem>
<CreatePromptset variant={"ghost"} projectId={projectId} />
</CommandItem>
</CommandGroup>
</Command>
</PopoverContent>
</Popover>
);
}
Loading

0 comments on commit b9b73db

Please sign in to comment.