From 571ce11e5322dbad657b561e93b457c6531c3d35 Mon Sep 17 00:00:00 2001 From: lloydzhou Date: Thu, 29 Aug 2024 19:55:09 +0800 Subject: [PATCH] stash code --- app/client/platforms/openai.ts | 10 ++- app/components/chat.tsx | 79 +++++++++++++++++++- app/constant.ts | 1 + app/store/index.ts | 1 + app/store/plugin.ts | 127 +++++++++++++++++++++++++++++++++ 5 files changed, 213 insertions(+), 5 deletions(-) create mode 100644 app/store/plugin.ts diff --git a/app/client/platforms/openai.ts b/app/client/platforms/openai.ts index 69dbad00505..b96e128f18d 100644 --- a/app/client/platforms/openai.ts +++ b/app/client/platforms/openai.ts @@ -14,6 +14,7 @@ import { useAccessStore, useAppConfig, useChatStore, + usePluginStore, } from "@/app/store"; import { collectModelsWithDefaultModel } from "@/app/utils/model"; import { @@ -240,6 +241,11 @@ export class ChatGPTApi implements LLMApi { ); } if (shouldStream) { + const [tools1, funcs2] = usePluginStore + .getState() + .getAsTools(useChatStore.getState().currentSession().mask?.plugin); + console.log("getAsTools", tools1, funcs2); + // return // TODO mock tools and funcs const tools = [ { @@ -276,8 +282,8 @@ export class ChatGPTApi implements LLMApi { chatPath, requestPayload, getHeaders(), - tools, - funcs, + tools1, + funcs2, controller, // parseSSE (text: string, runTools: ChatMessageTool[]) => { diff --git a/app/components/chat.tsx b/app/components/chat.tsx index 2ad579aa560..9d3b86f4ecc 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -54,6 +54,7 @@ import { useAppConfig, DEFAULT_TOPIC, ModelType, + usePluginStore, } from "../store"; import { @@ -440,6 +441,71 @@ export function ChatActions(props: { const config = useAppConfig(); const navigate = useNavigate(); const chatStore = useChatStore(); + const pluginStore = usePluginStore(); + console.log("pluginStore", pluginStore.getAll()); + // test + if (pluginStore.getAll().length == 0) { + pluginStore.create({ + title: "Pet API", + version: "1.0.0", + content: `{ + "openapi": "3.0.2", + "info": { + "title": "Pet API", + "version": "1.0.0" + }, + "paths": { + "/api/pets": { + "get": { + "operationId": "getPets", + "description": "Returns all pets from the system that the user has access to", + "responses": { + "200": { + "description": "List of Pets", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Pet": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "cat", + "dog" + ] + }, + "name": { + "type": "string" + } + }, + "required": [ + "id", + "type" + ] + } + } + } +}`, + }); + } // switch themes const theme = config.theme; @@ -738,15 +804,22 @@ export function ChatActions(props: { title: Locale.Plugin.Artifacts, value: Plugin.Artifacts, }, - ]} + ].concat( + pluginStore + .getAll() + .map((item) => ({ + title: `${item.title}@${item.version}`, + value: item.id, + })), + )} onClose={() => setShowPluginSelector(false)} onSelection={(s) => { const plugin = s[0]; chatStore.updateCurrentSession((session) => { session.mask.plugin = s; }); - if (plugin) { - showToast(plugin); + if (s.includes(Plugin.Artifacts)) { + showToast(Plugin.Artifacts); } }} /> diff --git a/app/constant.ts b/app/constant.ts index e88d497ca94..db365f0fc5a 100644 --- a/app/constant.ts +++ b/app/constant.ts @@ -78,6 +78,7 @@ export enum Plugin { export enum StoreKey { Chat = "chat-next-web-store", + Plugin = "chat-next-web-plugin", Access = "access-control", Config = "app-config", Mask = "mask-store", diff --git a/app/store/index.ts b/app/store/index.ts index 0760f48ca26..122afd5d3cb 100644 --- a/app/store/index.ts +++ b/app/store/index.ts @@ -2,3 +2,4 @@ export * from "./chat"; export * from "./update"; export * from "./access"; export * from "./config"; +export * from "./plugin"; diff --git a/app/store/plugin.ts b/app/store/plugin.ts new file mode 100644 index 00000000000..d93044c4dc1 --- /dev/null +++ b/app/store/plugin.ts @@ -0,0 +1,127 @@ +import OpenAPIClientAxios from "openapi-client-axios"; +import { getLang, Lang } from "../locales"; +import { StoreKey, Plugin } from "../constant"; +import { nanoid } from "nanoid"; +import { createPersistStore } from "../utils/store"; +import yaml from "js-yaml"; + +export type Plugin = { + id: string; + createdAt: number; + title: string; + version: string; + context: string; + builtin: boolean; +}; + +export const createEmptyPlugin = () => + ({ + id: nanoid(), + title: "", + version: "", + context: "", + builtin: false, + createdAt: Date.now(), + }) as Plugin; + +export const DEFAULT_PLUGIN_STATE = { + plugins: {} as Record, +}; + +export const usePluginStore = createPersistStore( + { ...DEFAULT_PLUGIN_STATE }, + + (set, get) => ({ + create(plugin?: Partial) { + const plugins = get().plugins; + const id = nanoid(); + plugins[id] = { + ...createEmptyPlugin(), + ...plugin, + id, + builtin: false, + }; + + set(() => ({ plugins })); + get().markUpdate(); + + return plugins[id]; + }, + updatePlugin(id: string, updater: (plugin: Plugin) => void) { + const plugins = get().plugins; + const plugin = plugins[id]; + if (!plugin) return; + const updatePlugin = { ...plugin }; + updater(updatePlugin); + plugins[id] = updatePlugin; + set(() => ({ plugins })); + get().markUpdate(); + }, + delete(id: string) { + const plugins = get().plugins; + delete plugins[id]; + set(() => ({ plugins })); + get().markUpdate(); + }, + + getAsTools(ids: string[]) { + const plugins = get().plugins; + const selected = ids + .map((id) => plugins[id]) + .filter((i) => i) + .map((i) => [ + i, + new OpenAPIClientAxios({ definition: yaml.load(i.content) }), + ]) + .map(([item, api]) => { + api.initSync(); + const operations = api.getOperations().map((o) => { + const parameters = o.parameters; + return [ + { + type: "function", + function: { + name: o.operationId, + description: o.description, + parameters: o.parameters, + }, + }, + api.client[o.operationId], + ]; + // return [{ + // }, function(arg) { + // const args = [] + // for (const p in parameters) { + // if (p.type === "object") { + // const a = {} + // for (const n of p.) + // } + // } + // }] + }); + return [item, api, operations]; + }); + console.log("selected", selected); + const result = selected.reduce((s, i) => s.concat(i[2]), []); + return [ + result.map(([t, _]) => t), + result.reduce((s, i) => { + s[i[0].function.name] = i[1]; + return s; + }, {}), + ]; + }, + get(id?: string) { + return get().plugins[id ?? 1145141919810]; + }, + getAll() { + return Object.values(get().plugins).sort( + (a, b) => b.createdAt - a.createdAt, + ); + }, + }), + { + name: StoreKey.Plugin, + version: 1, + }, +);