Skip to content

Commit

Permalink
Add imageGeneration plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
sunls24 committed Nov 7, 2023
1 parent a7b3472 commit cea4316
Showing 7 changed files with 97 additions and 27 deletions.
47 changes: 44 additions & 3 deletions app/api/chat/functions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { ChatCompletionCreateParams } from "openai/resources/chat/completions";
import { NodeHtmlMarkdown } from "node-html-markdown";
import OpenAI from "openai";

export const openai = new OpenAI({ apiKey: "" });

interface FunctionCall {
function: ChatCompletionCreateParams.Function;
@@ -38,7 +41,7 @@ const functionMap: Record<string, FunctionCall> = {
const result = await res.json();
return result.items ?? nothing;
} catch (err: any) {
console.log(`- ${name} ${args.keyword} ${err.cause ?? err}`);
console.log(`- ${err.cause ?? err} [${name} ${args.keyword}]`);
return nothing;
}
},
@@ -72,7 +75,7 @@ const functionMap: Record<string, FunctionCall> = {
}
return result;
} catch (err: any) {
console.log(`- ${name} ${url} ${err.cause ?? err}`);
console.log(`- ${err.cause ?? err} [${name} ${url}]`);
return "Unable to access this website";
}
},
@@ -124,11 +127,49 @@ const functionMap: Record<string, FunctionCall> = {
}
return result;
} catch (err: any) {
console.log(`- ${name} ${args.location} ${err.cause ?? err}`);
console.log(`- ${err.cause ?? err} [${name} ${args.location}]`);
return nothing;
}
},
},
imageGeneration: {
function: {
name: "imageGeneration",
description:
"Generate image by prompt. Returns the url of the image, please use md format to display image",
parameters: {
type: "object",
properties: {
prompt: {
type: "string",
},
style: {
type: "string",
description:
"The style of the generated images. Must be one of vivid or natural",
},
},
required: ["prompt"],
},
},
call: async (name, args) => {
const prompt = args.prompt as string;
try {
const response = await openai.images.generate({
prompt: prompt,
// @ts-ignore
style: args.style,
model: "dall-e-3",
size: "1024x1024",
n: 1,
});
return response.data[0].url;
} catch (err: any) {
console.log(`- ${err.cause ?? err} [${name} ${prompt}]`);
return "Generate failure";
}
},
},
};

export const functions: ChatCompletionCreateParams.Function[] = Object.values(
4 changes: 2 additions & 2 deletions app/api/chat/route.ts
Original file line number Diff line number Diff line change
@@ -3,14 +3,13 @@ import { ChatCompletionCreateParams } from "openai/resources/chat/completions";
import { CreateMessage, OpenAIStream, StreamingTextResponse } from "ai";
import { NextResponse } from "next/server";
import { ApiConfig, Plugins } from "@/lib/store/config";
import { functions, onFunctionCall } from "@/app/api/chat/functions";
import { functions, onFunctionCall, openai } from "@/app/api/chat/functions";
import { getLocaleTime } from "@/lib/utils";
import { apiKeyPool } from "@/lib/pool";

export const runtime = "edge";

apiKeyPool.update(process.env.OPENAI_API_KEY ?? "");
const openai = new OpenAI({ apiKey: "" });

export async function POST(req: Request) {
const { messages, config, contextIndex } = await req.json();
@@ -32,6 +31,7 @@ export async function POST(req: Request) {
openai.apiKey = await apiKeyPool.getNextEdge(apiConfig.apiKey);
try {
const response = await openai.chat.completions.create(body);
// @ts-ignore
const stream = OpenAIStream(response, {
experimental_onFunctionCall: async (
{ name, arguments: args },
36 changes: 27 additions & 9 deletions components/dialog/settings.tsx
Original file line number Diff line number Diff line change
@@ -92,6 +92,17 @@ function Settings({ trigger }: { trigger: React.ReactNode }) {
updateConfig((c) => (c.apiConfig.plugins.weatherInfo.amapKey = amapKey));
}

const [imageGeneration, setImageGeneration] = useState(
useConfig((state) => state.apiConfig.plugins.imageGeneration),
);

function onIGToggle(enabled: boolean) {
setImageGeneration({ ...imageGeneration, enabled });
updateConfig(
(c) => (c.apiConfig.plugins.imageGeneration.enabled = enabled),
);
}

return (
<Sheet>
<SheetTrigger asChild>{trigger}</SheetTrigger>
@@ -102,7 +113,7 @@ function Settings({ trigger }: { trigger: React.ReactNode }) {
<ScrollArea>
<Card className="mb-4 flex flex-col gap-4 p-4">
<div className="flex items-center justify-between">
<Label className="shrink-0">API Key</Label>
<Label>API Key</Label>
<Input
placeholder="自定义 OpenAI Api Key"
className="w-[70%]"
@@ -114,7 +125,7 @@ function Settings({ trigger }: { trigger: React.ReactNode }) {
<SettingsTemperature />
<Separator />
<div className="flex h-9 items-center justify-between">
<Label className="shrink-0">自动生成标题</Label>
<Label>自动生成标题</Label>
<Switch checked={autoTitle} onCheckedChange={onAutoTitleToggle} />
</div>
</Card>
@@ -125,7 +136,7 @@ function Settings({ trigger }: { trigger: React.ReactNode }) {
{searchEnabled && (
<>
<div className="flex items-center justify-between">
<Label className="shrink-0">API Key</Label>
<Label>API Key</Label>
<Input
placeholder="自定义 Search Api Key"
className="w-[70%]"
@@ -136,7 +147,7 @@ function Settings({ trigger }: { trigger: React.ReactNode }) {
/>
</div>
<div className="flex items-center justify-between">
<Label className="shrink-0">Engine ID</Label>
<Label>Engine ID</Label>
<Input
placeholder="自定义 Search Engine ID"
className="w-[70%]"
@@ -148,10 +159,17 @@ function Settings({ trigger }: { trigger: React.ReactNode }) {
</div>
</>
)}

<Separator />
<div className="flex h-9 items-center justify-between">
<Label className="shrink-0">浏览网页</Label>
<Label>图像生成</Label>
<Switch
checked={imageGeneration.enabled}
onCheckedChange={onIGToggle}
/>
</div>
<Separator />
<div className="flex h-9 items-center justify-between">
<Label>浏览网页</Label>
<Switch
checked={browseWebsite.enabled}
onCheckedChange={onBWToggle}
@@ -160,7 +178,7 @@ function Settings({ trigger }: { trigger: React.ReactNode }) {
{browseWebsite.enabled && (
<>
<div className="flex items-center gap-2">
<Label className="shrink-0">最大长度</Label>
<Label>最大长度</Label>
<TooltipWrap
trigger={<Info size={16} />}
content="避免触发 Token 限制"
@@ -179,7 +197,7 @@ function Settings({ trigger }: { trigger: React.ReactNode }) {
)}
<Separator />
<div className="flex h-9 items-center justify-between">
<Label className="shrink-0">查询天气</Label>
<Label>查询天气</Label>
<Switch
checked={weatherInfo.enabled}
onCheckedChange={onWIToggle}
@@ -188,7 +206,7 @@ function Settings({ trigger }: { trigger: React.ReactNode }) {
{weatherInfo.enabled && (
<>
<div className="flex items-center justify-between">
<Label className="shrink-0">高德 Key</Label>
<Label>高德 Key</Label>
<Input
placeholder="自定义高德 Key"
className="w-[70%]"
6 changes: 3 additions & 3 deletions lib/constants.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
export const StoreVersion = 2.0;
export const VERSION = "2.0.2";
export const StoreVersion = 2.1;
export const VERSION = "2.1.0";

export enum Store {
Chat = "chat-next-store",
Config = "chat-next-config",
}

export const models = ["gpt-3.5-turbo-1106"];
export const models = ["gpt-3.5-turbo", "gpt-3.5-turbo-1106"];

export const TOPIC_MAX_LENGTH = 12;
export const AUTO_TOPIC_LENGTH = 4;
19 changes: 15 additions & 4 deletions lib/store/config.ts
Original file line number Diff line number Diff line change
@@ -28,6 +28,13 @@ export const defaultConfig = {
enabled: false,
amapKey: "",
},
imageGeneration: {
enabled: false,
// model: "dall-e-3",
// size: "1024x1024",
// hd: false,
// n: 1,
},
},
},
};
@@ -52,10 +59,14 @@ export const useConfig = create<Config>()(
{
name: Store.Config,
version: StoreVersion,
// migrate(persistedState, version) {
// const state = persistedState as Config
// return state
// },
migrate(persistedState, version) {
const state = persistedState as Config;
if (!state.apiConfig.plugins.imageGeneration) {
state.apiConfig.plugins.imageGeneration =
defaultConfig.apiConfig.plugins.imageGeneration;
}
return state;
},
},
),
);
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "chat-next",
"version": "2.0.2",
"version": "2.1.0",
"private": true,
"scripts": {
"dev": "next dev",
@@ -28,7 +28,7 @@
"next": "^14.0.1",
"next-themes": "^0.2.1",
"node-html-markdown": "^1.3.0",
"openai": "^4.15.4",
"openai": "^4.16.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hot-toast": "^2.4.1",
8 changes: 4 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit cea4316

Please sign in to comment.