From fb3ad8ed1bb7a5b5c78cf3c3dda4bf8fda93b45b Mon Sep 17 00:00:00 2001 From: Ethan Leifer Date: Fri, 19 Jan 2024 12:20:30 -0500 Subject: [PATCH 1/3] first round of content classifier --- src/app/api/ai/classify/route.ts | 52 +++++++++ src/app/content-analysis.tsx | 121 +++++++++++++++++++++ src/app/page.tsx | 8 +- src/app/schemas/content-classification.tsx | 66 +++++++++++ 4 files changed, 244 insertions(+), 3 deletions(-) create mode 100644 src/app/api/ai/classify/route.ts create mode 100644 src/app/content-analysis.tsx create mode 100644 src/app/schemas/content-classification.tsx diff --git a/src/app/api/ai/classify/route.ts b/src/app/api/ai/classify/route.ts new file mode 100644 index 0000000..56f926e --- /dev/null +++ b/src/app/api/ai/classify/route.ts @@ -0,0 +1,52 @@ +import { classification } from "@/app/schemas/content-classification" +import OpenAI from "openai" +import { OAIStream, withResponseModel } from "zod-stream" + +import { RateLimiter } from "@/lib/rate-limiter" + +const oai = new OpenAI({ + apiKey: process.env["OPENAI_API_KEY"] ?? undefined, + organization: process.env["OPENAI_ORG_ID"] ?? undefined +}) + +export const runtime = "edge" + +interface IRequest { + // response_model: { schema: typeof dashboardSchema; name: string } + messages: OpenAI.ChatCompletionMessageParam[] +} + +export async function POST(request: Request) { + const rateLimit = await RateLimiter(request) + + if (!rateLimit || rateLimit?.isLimited) { + return new Response("Daily limit exceeded", { + status: 429 + }) + } + const { messages } = (await request.json()) as IRequest + + const params = withResponseModel({ + response_model: { + schema: classification, + name: "classification of content" + }, + params: { + temperature: 0.2, + seed: 1, + messages, + + model: "gpt-4-1106-preview", + stream: true + }, + mode: "TOOLS" + }) + + const extractionStream = await oai.chat.completions.create(params) + + return new Response( + OAIStream({ + res: extractionStream + }) + ) +} diff --git a/src/app/content-analysis.tsx b/src/app/content-analysis.tsx new file mode 100644 index 0000000..bb71b4e --- /dev/null +++ b/src/app/content-analysis.tsx @@ -0,0 +1,121 @@ +import { useState } from "react" +import { useJsonStream } from "stream-hooks" + +import { Overview } from "@/components/overview" +import { Button } from "@/components/ui/button" +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" +import { Textarea } from "@/components/ui/textarea" + +import { classification } from "./schemas/content-classification" + +export const ContentAnalysis = () => { + const [submitted, setSubmitted] = useState(false) + const [prompt, _setPrompt] = useState("Paste your text here to classify it") + const { data, loading, startStream } = useJsonStream({ + schema: classification + }) + + const submitMessage = async () => { + try { + setSubmitted(true) + await startStream({ + url: "/api/ai/classify", + method: "POST", + body: { + messages: [ + { + content: `You are tasks with classifying the following content. + + Think about what this content could be. + + Then piece together the information you have to classify it. + `, + + role: "system" + }, + + { + content: prompt, + role: "user" + } + ] + } + }) + } catch (e) { + console.error(e) + } + } + + return !submitted ? ( + <> +
+

+ This example parses any kind of content and classifies and pulls out some vital + information from it. You can copy and paste email threads, newsletters or any other kind + of content. It will then classify the content and pull out the important information. +

+