diff --git a/prisma/migrations/20230701042329_add_time_to_complete_to_model_output/migration.sql b/prisma/migrations/20230701042329_add_time_to_complete_to_model_output/migration.sql new file mode 100644 index 0000000..819ecb0 --- /dev/null +++ b/prisma/migrations/20230701042329_add_time_to_complete_to_model_output/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "ModelOutput" ADD COLUMN "timeToComplete" INTEGER NOT NULL DEFAULT 0; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 8be4861..161a4cd 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -76,10 +76,11 @@ model TemplateVariable { model ModelOutput { id String @id @default(uuid()) @db.Uuid - inputHash String - output Json - statusCode Int - errorMessage String? + inputHash String + output Json + statusCode Int + errorMessage String? + timeToComplete Int @default(0) promptVariantId String @db.Uuid promptVariant PromptVariant @relation(fields: [promptVariantId], references: [id], onDelete: Cascade) diff --git a/src/components/OutputsTable/OutputCell.tsx b/src/components/OutputsTable/OutputCell.tsx index e9f2033..9935464 100644 --- a/src/components/OutputsTable/OutputCell.tsx +++ b/src/components/OutputsTable/OutputCell.tsx @@ -1,12 +1,14 @@ import { api } from "~/utils/api"; import { type PromptVariant, type Scenario } from "./types"; -import { Spinner, Text, Box, Center } from "@chakra-ui/react"; +import { Spinner, Text, Box, Center, Flex, Icon } from "@chakra-ui/react"; import { useExperiment } from "~/utils/hooks"; import { type CreateChatCompletionResponse } from "openai"; import SyntaxHighlighter from "react-syntax-highlighter"; import { docco } from "react-syntax-highlighter/dist/cjs/styles/hljs"; import stringify from "json-stringify-pretty-compact"; import { type ReactElement } from "react"; +import { BsClock } from "react-icons/bs"; +import { type ModelOutput } from "@prisma/client"; export default function OutputCell({ scenario, @@ -22,13 +24,11 @@ export default function OutputCell({ const scenarioVariables = scenario.variableValues as Record; const templateHasVariables = - vars?.length === 0 || - vars?.some((v) => scenarioVariables[v.label] !== undefined); + vars?.length === 0 || vars?.some((v) => scenarioVariables[v.label] !== undefined); let disabledReason: string | null = null; - if (!templateHasVariables) - disabledReason = "Add a value to the scenario variables to see output"; + if (!templateHasVariables) disabledReason = "Add a value to the scenario variables to see output"; if (variant.config === null || Object.keys(variant.config).length === 0) disabledReason = "Save your prompt variant to see output"; @@ -45,17 +45,20 @@ export default function OutputCell({ if (disabledReason) return {disabledReason}; - if (output.isLoading) return
; + if (output.isLoading) + return ( +
+ +
+ ); - if (!output.data) - return Error retrieving output; + if (!output.data) return Error retrieving output; if (output.data.errorMessage) { return Error: {output.data.errorMessage}; } - const response = output.data - ?.output as unknown as CreateChatCompletionResponse; + const response = output.data?.output as unknown as CreateChatCompletionResponse; const message = response?.choices?.[0]?.message; if (message?.function_call) { @@ -64,9 +67,7 @@ export default function OutputCell({ try { parsedArgs = JSON.parse(rawArgs); } catch (e: any) { - parsedArgs = `Failed to parse arguments as JSON: '${rawArgs}' ERROR: ${ - e.message as string - }`; + parsedArgs = `Failed to parse arguments as JSON: '${rawArgs}' ERROR: ${e.message as string}`; } return ( @@ -88,9 +89,26 @@ export default function OutputCell({ { maxLength: 40 } )} + ); } - return {message?.content ?? JSON.stringify(output.data.output)}; + return ( + + {message?.content ?? JSON.stringify(output.data.output)} + + + ); } + +const OutputStats = ({ modelOutput }: { modelOutput: ModelOutput }) => { + const timeToComplete = modelOutput.timeToComplete; + + return ( + + + {(timeToComplete / 1000).toFixed(2)}s + + ); +}; diff --git a/src/server/api/routers/modelOutputs.router.ts b/src/server/api/routers/modelOutputs.router.ts index 8ce3c8a..501d2b0 100644 --- a/src/server/api/routers/modelOutputs.router.ts +++ b/src/server/api/routers/modelOutputs.router.ts @@ -61,6 +61,7 @@ export const modelOutputsRouter = createTRPCRouter({ output: existingResponse.output as Prisma.InputJsonValue, statusCode: existingResponse.statusCode, errorMessage: existingResponse.errorMessage, + timeToComplete: existingResponse.timeToComplete, }; } else { modelResponse = await getChatCompletion(filledTemplate, env.OPENAI_API_KEY); diff --git a/src/server/utils/getChatCompletion.ts b/src/server/utils/getChatCompletion.ts index bd97943..9a32868 100644 --- a/src/server/utils/getChatCompletion.ts +++ b/src/server/utils/getChatCompletion.ts @@ -6,12 +6,14 @@ type CompletionResponse = { output: Prisma.InputJsonValue | typeof Prisma.JsonNull; statusCode: number; errorMessage: string | null; + timeToComplete: number }; export async function getChatCompletion( payload: JSONSerializable, apiKey: string ): Promise { + const start = Date.now(); const response = await fetch("https://api.openai.com/v1/chat/completions", { method: "POST", headers: { @@ -25,9 +27,11 @@ export async function getChatCompletion( output: Prisma.JsonNull, errorMessage: null, statusCode: response.status, + timeToComplete: 0 }; try { + resp.timeToComplete = Date.now() - start; resp.output = await response.json(); if (!response.ok) {