lloydzhou hai 1 ano
pai
achega
571ce11e53
Modificáronse 5 ficheiros con 213 adicións e 5 borrados
  1. 8 2
      app/client/platforms/openai.ts
  2. 76 3
      app/components/chat.tsx
  3. 1 0
      app/constant.ts
  4. 1 0
      app/store/index.ts
  5. 127 0
      app/store/plugin.ts

+ 8 - 2
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[]) => {

+ 76 - 3
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);
             }
           }}
         />

+ 1 - 0
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",

+ 1 - 0
app/store/index.ts

@@ -2,3 +2,4 @@ export * from "./chat";
 export * from "./update";
 export * from "./access";
 export * from "./config";
+export * from "./plugin";

+ 127 - 0
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<string, Plugin>,
+};
+
+export const usePluginStore = createPersistStore(
+  { ...DEFAULT_PLUGIN_STATE },
+
+  (set, get) => ({
+    create(plugin?: Partial<Plugin>) {
+      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,
+  },
+);