Skip to content

Commit

Permalink
feat: adapt to the latest version of ai sdk
Browse files Browse the repository at this point in the history
  • Loading branch information
sunls24 committed Nov 25, 2024
1 parent a55d549 commit 9eb4888
Show file tree
Hide file tree
Showing 6 changed files with 228 additions and 256 deletions.
56 changes: 13 additions & 43 deletions app/api/chat/route.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { ChatCompletionCreateParams } from "openai/resources/chat/completions";
import { onToolCall, tools } from "@/app/api/chat/tools";
import { getOpenAI } from "@/app/api/openai";
import { CreateMessage, OpenAIStream, StreamingTextResponse } from "ai";
import { CoreMessage, streamText } from "ai";
import { getLocaleTime } from "@/lib/utils";
import OpenAI from "openai";
import { tools } from "@/app/api/chat/tools";
import { NextResponse } from "next/server";

export const runtime = "edge";
Expand All @@ -16,54 +14,26 @@ export async function POST(req: Request) {
if (config.systemPrompt) {
messages.unshift(systemPrompt());
}
const body: ChatCompletionCreateParams.ChatCompletionCreateParamsStreaming = {
stream: true,
model: config.model,
top_p: 1,
temperature: config.temperature,
tools: tools.filter((v) => config.plugins[v.function.name]?.enabled),
messages,
};
body.tools!.length || delete body.tools;

try {
const response = await getOpenAI(config.apiKey).chat.completions.create(
body,
);
const stream = OpenAIStream(response, {
experimental_onToolCall: async (
toolCallPayload,
appendToolCallMessage,
) => {
for (const tool of toolCallPayload.tools) {
const { name, arguments: args } = tool.func;
args.config = config.plugins[name];
const result = await onToolCall(name, args);

appendToolCallMessage({
tool_call_id: tool.id,
function_name: name,
tool_call_result: result,
});
}
return getOpenAI(config.apiKey).chat.completions.create({
...body,
messages: [...messages, ...appendToolCallMessage()],
});
},
const result = await streamText({
topP: 1,
temperature: config.temperature,
model: getOpenAI(config.apiKey).chat(config.model),
messages: messages,
maxSteps: 3,
tools: Object.fromEntries(
Object.entries(tools).filter(([key]) => config.plugins[key]?.enabled),
),
});

return new StreamingTextResponse(stream);
return result.toDataStreamResponse();
} catch (err: any) {
if (err instanceof OpenAI.APIError) {
return new NextResponse(err.message, { status: err.status });
}

return new NextResponse(err.message ?? err.toString(), { status: 500 });
}
}

function systemPrompt(): CreateMessage {
function systemPrompt(): CoreMessage {
return {
role: "system",
content: `You are an AI assistant, your duty is to provide accurate and rigorous answers. When encountering questions that cannot be handled, you need to clearly inform and guide the user to propose new questions. Please reply in Chinese.
Expand Down
64 changes: 16 additions & 48 deletions app/api/chat/tools.ts
Original file line number Diff line number Diff line change
@@ -1,63 +1,31 @@
import { ChatCompletionTool } from "openai/resources/chat/completions";
import { CoreTool, tool } from "ai";
import { z } from "zod";

interface ToolCall {
tool: ChatCompletionTool;
call: (name: string, args: Record<string, unknown>) => Promise<any>;
}

const toolMap: Record<string, ToolCall> = {
googleSearch: {
tool: {
type: "function",
function: {
name: "googleSearch",
description: "Search the web for information using Google",
parameters: {
type: "object",
properties: {
keyword: {
type: "string",
description: "Keywords for searching",
},
},
required: ["keyword"],
},
},
},
call: async (name, args) => {
export const tools: Record<string, CoreTool> = {
googleSearch: tool({
description: "Search the web for information using Google",
parameters: z.object({
keyword: z.string().describe("Keywords for searching"),
}),
execute: async ({ keyword }) => {
console.log(`- googleSearch: ${keyword}`);
const nothing = "nothing";
const cfg = args.config as any;
const apiKey = cfg.apiKey || process.env.GOOGLE_API_KEY;
const engineId = cfg.engineId || process.env.GOOGLE_ENGINE_ID;
const apiKey = process.env.GOOGLE_API_KEY;
const engineId = process.env.GOOGLE_ENGINE_ID;
if (!apiKey || !engineId) {
console.log(`- ${name} apiKey or engineId is empty`);
console.log("- googleSearch apiKey or engineId is empty");
return nothing;
}
try {
const res = await fetch(
`https://www.googleapis.com/customsearch/v1?&fields=items(title,link,snippet,pagemap/metatags(og:description))&key=${apiKey}&cx=${engineId}&q=${args.keyword}`,
`https://www.googleapis.com/customsearch/v1?&fields=items(title,link,snippet,pagemap/metatags(og:description))&key=${apiKey}&cx=${engineId}&q=${keyword}`,
);
const result = await res.json();
return result.items ?? nothing;
} catch (err: any) {
console.log(`- ${name} ${err.cause ?? err}`);
console.log(`- googleSearch: ${err.cause ?? err}`);
return nothing;
}
},
},
}),
};

export const tools: ChatCompletionTool[] = Object.values(toolMap).map(
(value) => value.tool,
);

export async function onToolCall(
name: string,
args: Record<string, unknown>,
): Promise<any> {
console.log("- onToolCall", name, args);
if (!toolMap.hasOwnProperty(name)) {
return `${name} tool not found`;
}
return toolMap[name].call(name, args);
}
40 changes: 0 additions & 40 deletions app/api/image/route.ts

This file was deleted.

9 changes: 5 additions & 4 deletions app/api/openai.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import OpenAI from "openai";
import { createOpenAI, OpenAIProvider } from "@ai-sdk/openai";

const baseURL = process.env.OPENAI_BASE_URL;
const OPENAI_API_KEY = process.env.OPENAI_API_KEY ?? "";
const clientPool: Map<string, OpenAI> = new Map();
const clientPool: Map<string, OpenAIProvider> = new Map();

export function getOpenAI(apiKey: string): OpenAI {
export function getOpenAI(apiKey: string): OpenAIProvider {
apiKey = apiKey || OPENAI_API_KEY;
if (!clientPool.has(apiKey)) {
clientPool.set(apiKey, new OpenAI({ apiKey }));
clientPool.set(apiKey, createOpenAI({ apiKey, baseURL }));
}
return clientPool.get(apiKey)!;
}
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"lint": "next lint"
},
"dependencies": {
"@ai-sdk/openai": "^1.0.4",
"@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-dropdown-menu": "^2.1.2",
"@radix-ui/react-label": "^2.1.0",
Expand All @@ -29,7 +30,6 @@
"mitt": "^3.0.1",
"next": "^15.0.3",
"next-themes": "^0.3.0",
"openai": "^4.73.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-markdown": "8.0.7",
Expand All @@ -38,12 +38,13 @@
"remark-breaks": "3.0.3",
"remark-gfm": "3.0.1",
"sonner": "^1.7.0",
"tailwind-merge": "^2.5.4",
"tailwind-merge": "^2.5.5",
"zod": "^3.23.8",
"zustand": "^5.0.1"
},
"devDependencies": {
"@tailwindcss/typography": "^0.5.15",
"@types/node": "^22.9.1",
"@types/node": "^22.9.3",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@types/react-syntax-highlighter": "^15.5.13",
Expand All @@ -56,6 +57,6 @@
"prettier-plugin-tailwindcss": "^0.6.9",
"tailwindcss": "^3.4.15",
"tailwindcss-animate": "^1.0.7",
"typescript": "^5.6.3"
"typescript": "^5.7.2"
}
}
Loading

0 comments on commit 9eb4888

Please sign in to comment.