Browse Source

feat: 删除质谱AI对话接口

河畔一角 1 week ago
parent
commit
24850b939e

+ 5 - 5
.vscode/settings.json

@@ -1,7 +1,7 @@
 {
 {
-  "editor.defaultFormatter": "esbenp.prettier-vscode",
-  "[vue]": {
-    "editor.defaultFormatter": "esbenp.prettier-vscode"
-  },
-  "editor.formatOnSave": true
+  "editor.foldingImportsByDefault": true,
+  "editor.codeActionsOnSave": {
+    "source.organizeImports": "always",
+    "source.fixAll": "always"
+  }
 }
 }

+ 0 - 2
config.default.js

@@ -73,7 +73,6 @@ const AI_KEY = '';
 const EMBEDDING = 'text-embedding-v3';
 const EMBEDDING = 'text-embedding-v3';
 const MODEL = 'qwen-plus';
 const MODEL = 'qwen-plus';
 const DATABASE_URL = 'postgresql://';
 const DATABASE_URL = 'postgresql://';
-const ZHIPU_AI_KEY = '';
 
 
 /**
 /**
  * 模型配置
  * 模型配置
@@ -111,7 +110,6 @@ module.exports = {
   EMAIL_PASSWORD,
   EMAIL_PASSWORD,
   WECHAT_APP_ID,
   WECHAT_APP_ID,
   WECHAT_APP_SECRET,
   WECHAT_APP_SECRET,
-  ZHIPU_AI_KEY,
   AI_BASE_URL,
   AI_BASE_URL,
   AI_KEY,
   AI_KEY,
   EMBEDDING,
   EMBEDDING,

+ 2 - 19
controller/ai.controller.js

@@ -1,7 +1,5 @@
-const aiService = require('../service/ai/ai.service.js');
 const util = require('../utils/util');
 const util = require('../utils/util');
 const { model: openaiModel } = require('../service/ai/openai.service');
 const { model: openaiModel } = require('../service/ai/openai.service');
-const { findRelevantContent } = require('../service/ai/embedding.service');
 const { getSystemPrompt } = require('../service/ai/prompt.service');
 const { getSystemPrompt } = require('../service/ai/prompt.service');
 const { streamText } = require('ai');
 const { streamText } = require('ai');
 
 
@@ -21,21 +19,6 @@ function formatMessages(messages) {
 }
 }
 
 
 module.exports = {
 module.exports = {
-  async codeGenerate(ctx) {
-    const { message } = ctx.request.body;
-    if (!message) {
-      return util.fail(ctx, '请输入提示词');
-    }
-    try {
-      const result = await aiService.ApiZhipuAi(message);
-      util.success(ctx, {
-        jsx: result[0],
-        config: result[1],
-      });
-    } catch (error) {
-      util.fail(ctx, error);
-    }
-  },
   async chatStream(ctx) {
   async chatStream(ctx) {
     try {
     try {
       const { messages } = ctx.request.body;
       const { messages } = ctx.request.body;
@@ -50,8 +33,8 @@ module.exports = {
         : lastMessage.content;
         : lastMessage.content;
 
 
       // 获取相关上下文
       // 获取相关上下文
-      const relevantContent = await findRelevantContent(lastMessageContent);
-      const systemPrompt = getSystemPrompt(relevantContent.map((c) => c.content).join('\n'));
+      // const relevantContent = await findRelevantContent(lastMessageContent);
+      const systemPrompt = getSystemPrompt(lastMessageContent);
 
 
       const { textStream } = streamText({
       const { textStream } = streamText({
         model: openaiModel,
         model: openaiModel,

+ 2 - 1
package.json

@@ -49,7 +49,8 @@
   },
   },
   "devDependencies": {
   "devDependencies": {
     "dotenv": "^16.4.7",
     "dotenv": "^16.4.7",
-    "eslint": "^8.56.0"
+    "eslint": "^8.56.0",
+    "prettier": "^3.5.3"
   },
   },
   "packageManager": "pnpm@10.7.1+sha512.2d92c86b7928dc8284f53494fb4201f983da65f0fb4f0d40baafa5cf628fa31dae3e5968f12466f17df7e97310e30f343a648baea1b9b350685dafafffdf5808"
   "packageManager": "pnpm@10.7.1+sha512.2d92c86b7928dc8284f53494fb4201f983da65f0fb4f0d40baafa5cf628fa31dae3e5968f12466f17df7e97310e30f343a648baea1b9b350685dafafffdf5808"
 }
 }

+ 10 - 0
pnpm-lock.yaml

@@ -123,6 +123,9 @@ importers:
       eslint:
       eslint:
         specifier: ^8.56.0
         specifier: ^8.56.0
         version: 8.57.1
         version: 8.57.1
+      prettier:
+        specifier: ^3.5.3
+        version: 3.5.3
 
 
 packages:
 packages:
 
 
@@ -2259,6 +2262,11 @@ packages:
     resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
     resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
     engines: {node: '>= 0.8.0'}
     engines: {node: '>= 0.8.0'}
 
 
+  prettier@3.5.3:
+    resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==}
+    engines: {node: '>=14'}
+    hasBin: true
+
   process-nextick-args@2.0.1:
   process-nextick-args@2.0.1:
     resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
     resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
 
 
@@ -4412,6 +4420,8 @@ snapshots:
 
 
   prelude-ls@1.2.1: {}
   prelude-ls@1.2.1: {}
 
 
+  prettier@3.5.3: {}
+
   process-nextick-args@2.0.1: {}
   process-nextick-args@2.0.1: {}
 
 
   process@0.11.10: {}
   process@0.11.10: {}

+ 0 - 3
router/ai.router.js

@@ -14,9 +14,6 @@ const { chatStream } = require('../controller/ai.controller');
 // 流式chat
 // 流式chat
 router.post('/stream', bodyParser(), chatStream);
 router.post('/stream', bodyParser(), chatStream);
 
 
-// 项目配置
-router.post('/lib/chat', ai.codeGenerate);
-
 // 接口转发(get)
 // 接口转发(get)
 router.get('/proxy', async (ctx) => handleProxy(ctx, 'get'));
 router.get('/proxy', async (ctx) => handleProxy(ctx, 'get'));
 
 

+ 0 - 332
service/ai/ai.service.js

@@ -1,332 +0,0 @@
-const { ChatZhipuAI } = require('@langchain/community/chat_models/zhipuai');
-const { HumanMessage } = require('@langchain/core/messages');
-const { GlmModelProvider } = require('./provider/model/glm');
-const { RunnableConfig } = require('@langchain/core/runnables');
-const { extractCodeBlocks } = require('./provider/utils');
-const ZhipuAI = require('./provider/base/ZhipuAPIModel');
-const ZHIPU_AI_KEY = require('../../config').ZHIPU_AI_KEY;
-class AiService {
-  async buildGeneratePrompt({ message }) {
-    const codePrompt = `
-        You are a low-code component development expert.
-        Your task is to help me generate two files for a low-code development module: index.jsx and config.js.
-        The index.jsx file should define the structure of the component using React and Ant Design, and the config.js file should specify the component's property configurations.
-
-        Here’s an example of a login form component:
-
-        index.jsx file:
-        // jsx
-        export default ({ id, type, config, onClick, onDateChange,onTextChange }, ref) => {
-            const { useState } = window.React;
-            const {
-              Button,
-              Checkbox,
-              ColorPicker,
-              DatePicker,
-              Form,
-              Input,
-              InputNumber,
-              Radio,
-              Select,
-              Slider,
-              Switch,
-            } = window.antd;
-            const { RangePicker } = DatePicker;
-            const { TextArea } = Input;
-            const [dateFormat, setDateFormat] = useState(
-              config.props.dateFormat || 'YYYY-MM-DD HH:mm:ss'
-            );
-            const onDatePickerChange = (date, dateString) => {
-              onDateChange && onDateChange(date, dateString, dateFormat);
-            };
-            const onFinish = (values) => {
-              onClick && onClick(values);
-            };
-            return (
-              <div data-id={id} data-type={type}>
-                <Form
-                  labelCol={{ span: config.props.labelCol }}
-                  wrapperCol={{ span: config.props.wrapperCol }}
-                  layout={config.props.layout}
-                  style={{ maxWidth: config.props.maxWidth }}
-                  onFinish={onFinish}
-                >
-                  <Form.Item label="Checkbox" name="disabled" valuePropName="checked">
-                    <Checkbox>Checkbox</Checkbox>
-                  </Form.Item>
-                  <Form.Item label="Radio">
-                    <Radio.Group>
-                      <Radio value="apple"> Apple </Radio>
-                      <Radio value="pear"> Pear </Radio>
-                    </Radio.Group>
-                  </Form.Item>
-                  <Form.Item label="Input">
-                    <Input placeholder={config.props.textInput} />
-                  </Form.Item>
-                  <Form.Item label="Select">
-                    <Select>
-                      <Select.Option value="demo">Demo</Select.Option>
-                    </Select>
-                  </Form.Item>
-                  <Form.Item label="DataFormat" name="dateFormat">
-                    <Input
-                      value={dateFormat}
-                      onChange={(e) => setDateFormat(e.target.value)}
-                    />
-                  </Form.Item>
-                  <Form.Item label="DatePicker">
-                    <DatePicker onChange={onDatePickerChange} />
-                  </Form.Item>
-                  <Form.Item label="RangePicker">
-                    <RangePicker />
-                  </Form.Item>
-                  <Form.Item label="InputNumber">
-                    <InputNumber placeholder={config.props.numberInput} />
-                  </Form.Item>
-                  <Form.Item label="TextArea">
-                    <TextArea rows={config.props.textAreaRow} showCount={config.props.showCount}  onChange={onTextChange}/>
-                  </Form.Item>
-                  <Form.Item label="Switch" valuePropName="checked">
-                    <Switch />
-                  </Form.Item>
-                  <Form.Item label="Button" wrapperCol={{
-                      offset: config.props.offset,
-                      span: config.props.wrapperCol,
-                    }}>
-                    <Button block={config.props.block} type={config.props.btnType}>
-                      {config.props.loginBtn}
-                    </Button>
-                  </Form.Item>
-                  <Form.Item label="Slider">
-                    <Slider />
-                  </Form.Item>
-                  <Form.Item label="ColorPicker">
-                    <ColorPicker />
-                  </Form.Item>
-                </Form>
-              </div>
-            );
-          };
-
-
-          config.js file:
-          // config.js
-          export default {
-              // 组件属性配置JSON
-              attrs: [
-                {
-                  type: 'Title',
-                  label: '基础设置',
-                  key: 'basic',
-                },
-                {
-                  type: 'Select',
-                  label: '布局',
-                  name: ['layout'],
-                  props: {
-                    options: [
-                      { value: 'horizontal', label: 'horizontal' },
-                      { value: 'vertical', label: 'vertical' },
-                      { value: 'inline', label: 'inline' }
-                    ],
-                  },
-                },
-                {
-                  type: 'Select',
-                  label: '按钮类型',
-                  name: ['btnType'],
-                  props: {
-                    // options参数必须写完整
-                    options: [
-                      { value: 'primary', label: 'primary' },
-                      { value: 'default', label: 'default' },
-                      { value: 'ghost', label: 'ghost' },
-                      { value: 'dashed', label: 'dashed' },
-                      { value: 'text', label: 'text' },
-                      { value: 'link', label: 'link' },
-                    ],
-                  },
-                },
-                {
-                  type: 'InputNumber',
-                  label: 'labelCol',
-                  name: ['labelCol'],
-                },
-                {
-                  type: 'InputNumber',
-                  label: 'wrapperCol',
-                  name: ['wrapperCol'],
-                },
-                {
-                  type: 'InputNumber',
-                  label: 'offset',
-                  name: ['offset'],
-                },
-                {
-                  type: 'Input',
-                  label: '按钮名称',
-                  name: ['btnText'],
-                },
-                {
-                  type: 'Switch',
-                  label: '块状按钮',
-                  name: ['block'],
-                },
-                {
-                  type: 'Input',
-                  label: '初始文本',
-                  name: ['textInput'],
-                },
-                {
-                  type: 'InputNumber',
-                  label: '初始数值',
-                  name: ['numberInput'],
-                },
-                
-                {
-                  type: 'InputNumber',
-                  label: '文本框占据',
-                  name: ['textAreaRow'],
-                },
-                {
-                  type: 'Switch',
-                  label: '显示字符数',
-                  name: ['showCount'],
-                },
-              ],
-              config: {
-                // 组件默认属性值
-                props: {
-                  layout: 'horizontal',
-                  labelCol: 8,
-                  offset: 8,
-                  wrapperCol: 16,
-                  maxWidth: 500,
-                  btnType: 'primary',
-                  btnText: '按钮',
-                  textInput: '初始文本',
-                  numberInput: 12,
-                  textAreaRow: 4,
-                  showCount: true
-                },
-                style: {
-
-                },
-                events: [],
-              },
-              // 组件事件
-              events: [
-                {
-                  value: 'onClick',
-                  name: '表单提交事件',
-                },
-                {
-                  value: 'onDateChange',
-                  name: '日期时间变化事件',
-                },
-                {
-                  value: 'onTextChange',
-                  name: '文本输入事件'
-                }
-              ],
-              methods: [],
-            };   
-
-            Note: If you need to import hooks like useState and useEffect, you should import them using const { useState, useEffect } = window.React;. 
-            Similarly, Ant Design components should be imported in this way: const { Button, Form, DatePicker, Tag } = window.antd;.
-            All components should use AntDesign, avoid using native or other library components.
-            Now, based on the above structure and configuration, I need you to generate the index.jsx and config.js files for a new component. 
-            The description of this component in Chinese is #{message}. You can understand it in English and help me implement the code of the component
-            Please return only the code for both files, without any additional descirption text or markdown syntax.
-            Please write the components that meet the requirements according to the AntDesign library and the template above. Please don't try to omit the content, and be sure to return the code completely.
-        `;
-
-    const prompt = codePrompt.replace('#{message}', message);
-    return prompt;
-  }
-
-  async ApiZhipuAi(message) {
-    const prompt = await this.buildGeneratePrompt({ message });
-    const zhipuProvider = new ZhipuAI(ZHIPU_AI_KEY);
-    const params = {
-      model: 'glm-4-plus',
-      messages: [
-        {
-          role: 'user',
-          content: prompt,
-        },
-      ],
-      top_p: 0.7,
-      temperature: 0.9,
-      max_tokens: 1024,
-    };
-    try {
-      const response = await zhipuProvider.createCompletion(params);
-    } catch (error) {
-      console.error('API call failed:', error.message);
-    }
-  }
-
-  async codeGenerate(message) {
-    const modelProvider = new GlmModelProvider();
-
-    const aiRunnableAbortController = new AbortController();
-    const aiRunnable = await modelProvider.createRunnable({
-      signal: aiRunnableAbortController.signal,
-    });
-
-    const sessionId = `code_session_${Date.now()}`;
-
-    const aiRunnableConfig = {
-      configurable: {
-        sessionId,
-      },
-    };
-
-    const sessionIdHistoriesMap = await GlmModelProvider.sessionIdHistoriesMap;
-
-    const isSessionHistoryExists = !!sessionIdHistoriesMap[sessionId];
-
-    const prompt = await this.buildGeneratePrompt({ message });
-
-    const buildStream = async () => {
-      let aiStream = null;
-      if (!isSessionHistoryExists) {
-        delete sessionIdHistoriesMap[sessionId];
-        aiStream = aiRunnable.stream(
-          {
-            input: prompt,
-          },
-          aiRunnableConfig,
-        );
-      } else {
-        aiStream = aiRunnable.stream(
-          {
-            input: `
-                    continue, please do not reply with any text other than the code, and do not use markdown syntax.
-                    go continue.
-                  `,
-          },
-          aiRunnableConfig,
-        );
-      }
-      return aiStream;
-    };
-
-    let result = [];
-    const aiStream = await buildStream();
-    if (aiStream) {
-      for await (const chunk of aiStream) {
-        const text = GlmModelProvider.answerContentToText(chunk.content);
-        result.push(text);
-      }
-    }
-    const ai_stream_string = result.join('');
-    const code_array = extractCodeBlocks(ai_stream_string);
-    // 解析生成的代码
-
-    return [code_array[0], code_array[1]];
-  }
-}
-
-module.exports = new AiService();

+ 0 - 106
service/ai/provider/base/BaseModelProvider.js

@@ -1,106 +0,0 @@
-const { InMemoryChatMessageHistory } = require("@langchain/core/chat_history");
-const { BaseMessage, MessageContent } = require("@langchain/core/messages");
-const {
-  ChatPromptTemplate,
-  HumanMessagePromptTemplate,
-  MessagesPlaceholder,
-} = require("@langchain/core/prompts");
-const {
-  Runnable,
-  RunnableWithMessageHistory,
-} = require("@langchain/core/runnables");
-const { z } = require("zod");
-
-class BaseModelProvider {
-  static sessionIdHistoriesMap = {};
-
-  static answerContentToText(content) {
-    if (typeof content === "string") {
-      return content;
-    }
-
-    return content
-      .map((c) => {
-        if (c.type === "text") {
-          return c.text;
-        }
-        return "";
-      })
-      .join("");
-  }
-
-  async getModel() {
-    if (!this.model) {
-      this.model = await this.createModel();
-    }
-    return this.model;
-  }
-
-  createPrompt(options) {
-    const { useHistory = true } = options ?? {};
-    const prompt = ChatPromptTemplate.fromMessages(
-      [
-        useHistory ? new MessagesPlaceholder("history") : "",
-        HumanMessagePromptTemplate.fromTemplate("{input}"),
-      ].filter(Boolean)
-    );
-    return prompt;
-  }
-
-  async getHistory(sessionId, appendHistoryMessages) {
-    if (BaseModelProvider.sessionIdHistoriesMap[sessionId] === undefined) {
-      const messageHistory = new InMemoryChatMessageHistory();
-
-      if (appendHistoryMessages && appendHistoryMessages.length > 0) {
-        await messageHistory.addMessages(appendHistoryMessages);
-      }
-
-      BaseModelProvider.sessionIdHistoriesMap[sessionId] = messageHistory;
-    }
-    return BaseModelProvider.sessionIdHistoriesMap[sessionId];
-  }
-
-  createRunnableWithMessageHistory(chain, historyMessages) {
-    return new RunnableWithMessageHistory({
-      runnable: chain,
-      getMessageHistory: async (sessionId) =>
-        await this.getHistory(sessionId, historyMessages),
-      inputMessagesKey: "input",
-      historyMessagesKey: "history",
-    });
-  }
-
-  async createRunnable(options) {
-    const { useHistory = true, historyMessages = [], signal } = options ?? {};
-    const model = await this.getModel();
-    const prompt = await this.createPrompt({ useHistory });
-    const chain = prompt.pipe(signal ? model.bind({ signal }) : model);
-    return useHistory
-      ? await this.createRunnableWithMessageHistory(
-          chain,
-          historyMessages || []
-        )
-      : chain;
-  }
-
-  async createStructuredOutputRunnable(options) {
-    const {
-      useHistory = true,
-      historyMessages = [],
-      zodSchema,
-    } = options ?? {};
-    const model = await this.getModel();
-    const prompt = await this.createPrompt({ useHistory });
-    const chain = prompt.pipe(model);
-    return useHistory
-      ? await this.createRunnableWithMessageHistory(
-          chain,
-          historyMessages || []
-        )
-      : chain;
-  }
-}
-
-module.exports = {
-  BaseModelProvider,
-};

+ 0 - 38
service/ai/provider/base/ZhipuAPIModel.js

@@ -1,38 +0,0 @@
-const request = require("../../../../utils/request");
-const { generateToken } = require("../utils/zhiputoken");
-
-class ZhipuAI {
-    constructor(apiKey) {
-      if (!apiKey) {
-        throw new Error("API Key is required");
-      }
-      this.apiKey = apiKey;
-      this.cacheToken = true;
-      this.baseUrl = "https://open.bigmodel.cn/api/paas/v4/chat/completions";
-    }
-  
-    async createCompletion(params) {
-      if (!params.model) {
-        throw new Error("Model name is required");
-      }
-      if (!params.messages || !Array.isArray(params.messages)) {
-        throw new Error("Messages array is required");
-      }
-      const token = await generateToken(this.apiKey, this.cacheToken);
-      const headers = {
-        baseUrl: this.baseUrl,
-        Authorization: token,
-        timeout: 10000,
-      };
-  
-      try {
-        const response = await request.post(this.baseUrl, JSON.stringify(params), { headers });
-        return response.data;
-      } catch (error) {
-        console.error("Error calling ZhipuAI API:", error.response?.data || error.message);
-        throw error;
-      }
-    }
-  }
-
-module.exports = ZhipuAI;

+ 0 - 23
service/ai/provider/model/glm.js

@@ -1,23 +0,0 @@
-const { BaseModelProvider } = require('../base/BaseModelProvider');
-const { ChatZhipuAI } = require('@langchain/community/chat_models/zhipuai');
-const { ZHIPU_AI_KEY } = require('../../../../config');
-class GlmModelProvider extends BaseModelProvider {
-  async createModel() {
-    const aiKey = ZHIPU_AI_KEY;
-    const model_name = 'glm-4';
-
-    const model = new ChatZhipuAI({
-      apiKey: aiKey,
-      model: model_name,
-      temperature: 0.95, // never use 1.0, some models do not support it
-      maxRetries: 3,
-      verbose: true,
-    });
-
-    return model;
-  }
-}
-
-module.exports = {
-  GlmModelProvider,
-};

+ 0 - 17
service/ai/provider/utils/index.js

@@ -1,17 +0,0 @@
-const extractCodeBlocks = (str) => {
-  if (!str) {
-    return [];
-  }
-
-  // 正则表达式匹配所有的代码块内容
-  const matches = str.match(/```[\s\S]*?\n([\s\S]*?)\n```/g);
-
-  // 如果找到了匹配项,返回提取的内容,否则返回空数组
-  return matches
-    ? matches.map((match) =>
-        match.replace(/```[\s\S]*?\n([\s\S]*?)\n```/, "$1").trim()
-      )
-    : [];
-};
-
-module.exports = { extractCodeBlocks };

+ 0 - 40
service/ai/provider/utils/zhiputoken.js

@@ -1,40 +0,0 @@
-
-const jsonwebtoken = require("jsonwebtoken")
-
-const API_TOKEN_TTL_SECONDS = 3 * 60
-const CACHE_TTL_SECONDS = API_TOKEN_TTL_SECONDS - 30
-const tokenCache = {}
-const generateToken = (apiSecretKey, cache = true) => {
-
-    try {
-        if (tokenCache[apiSecretKey] && Date.now() - tokenCache[apiSecretKey].createAt < (CACHE_TTL_SECONDS * 1000)) {
-            return tokenCache[apiSecretKey].token
-        }
-
-        const [apiKey, secret] = apiSecretKey.split(".")
-        const payload = {
-            "api_key": apiKey,
-            "exp": Math.round(Date.now() * 1000) + API_TOKEN_TTL_SECONDS * 1000,
-            "timestamp": Math.round(Date.now() * 1000),
-        }
-        // algorithm = "HS256", headers = { "alg": "HS256", "sign_type": "SIGN" }
-        //@ts-ignore 不用管
-        const ret = jsonwebtoken.sign(payload, secret, {
-            algorithm: "HS256",
-            header: { alg: "HS256", sign_type: "SIGN" }
-        })
-        if (cache) {
-            tokenCache[apiSecretKey] = {
-                token: ret,
-                createAt: Date.now()
-            }
-        }
-        return ret
-    } catch (e) {
-        throw "invalid api_key"
-    }
-}
-
-module.exports = {
-    generateToken
-}