0235967 3 săptămâni în urmă
părinte
comite
2a27e2cd78
1 a modificat fișierele cu 170 adăugiri și 0 ștergeri
  1. 170 0
      travel-web/src/lib/completion.ts

+ 170 - 0
travel-web/src/lib/completion.ts

@@ -0,0 +1,170 @@
+
+export interface TestMessage{
+    role:string
+    content:string
+}
+
+export class TestCompletion{
+    token:string = "r:60abef69e7cd8181b146ceaba1fdbf02"
+    messageList:any = []
+    stream:boolean = true;
+    constructor(messageList:any){
+        this.messageList = messageList || this.messageList
+    }
+    async sendMessage(messageList?:null|Array<TestMessage>,onMessage?: (content: string) => void):Promise<any>{
+        
+        this.messageList = messageList || this.messageList
+        let body = {
+            "messages": this.messageList,
+            "stream": this.stream,
+            "model": "fmode-4.5-128k",
+            "temperature": 0.5,
+            "presence_penalty": 0,
+            "frequency_penalty": 0,
+            "token": "Bearer "+this.token
+        }
+
+        let response = await fetch("https://server.fmode.cn/api/apig/aigc/gpt/v1/chat/completions", {
+            "headers": {
+            },
+            "body": JSON.stringify(body),
+            "method": "POST",
+            "mode": "cors",
+            "credentials": "omit"
+        });
+
+        
+        /** 单次响应 HTTP短连接请求
+         {"choices":[{"finish_reason":"stop","index":0,"logprobs":null,"message":{"annotations":[],"content":"您好!我是一个人工智能助手,旨在帮助您回答问题、提供信息和解决各种问题。我可以处理许多主题,包括科技、历史、文化、语言学习等。如果您有任何具体的问题或需要了解的内容,请随时告诉我!","refusal":null,"role":"assistant"}}],"created":1751509370,"id":"chatcmpl-Bp3t41MP4pb2NR38n1ylrJw922SBZ","model":"gpt-4o-mini-2024-07-18","object":"chat.completion","system_fingerprint":"fp_efad92c60b","usage":{"completion_tokens":55,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":15,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":70}}
+        */
+        if(this.stream == false){
+            let data = await response.json()
+            console.log(data)
+            let lastContent = data?.choices?.[0]?.message?.content
+            return lastContent
+        }
+        /**
+         * 流式加载 HTTP Event Stream 模式 长连接获取
+         */
+        
+        // Stream mode handling
+        if (!response.body) {
+            throw new Error("No response body in stream mode");
+        }
+
+        const reader = response.body.getReader();
+        const decoder = new TextDecoder("utf-8");
+        let accumulatedContent = "";
+        try {
+            while (true) {
+                const { done, value } = await reader.read();
+                if (done) break;
+
+                const chunk = decoder.decode(value, { stream: true });
+                const lines = chunk.split('\n').filter(line => line.trim() !== '');
+
+                for (const line of lines) {
+                    if (line.startsWith('data:') && !line.includes('[DONE]')) {
+                        try {
+                            const jsonStr = line.substring(5).trim();
+                            const data = JSON.parse(jsonStr);
+                            const content = data?.choices?.[0]?.delta?.content || '';
+                            
+                            if (content) {
+                                accumulatedContent += content;
+                                if (onMessage) {
+                                    onMessage(accumulatedContent);
+                                }
+                            }
+                        } catch (e) {
+                            console.error("Error parsing stream data:", e);
+                        }
+                    }
+                }
+            }
+        } finally {
+            reader.releaseLock();
+        }
+
+        return accumulatedContent;
+    }
+}
+
+/**
+ * 使用AI生成符合指定结构的JSON数据
+ * @param prompt 任务要求的整体提示词
+ * @param jsonSchema 期望的JSON结构描述(用于提示词)
+ * @param example 可选的JSON示例(帮助AI理解格式)
+ * @param onMessage 实时生成内容回调
+ * @returns 解析后的JSON对象
+ */
+export async function completionJSON(
+    prompt:string,
+  jsonSchema: string,
+  example: object | null = null,
+  onMessage?: (content: string) => void
+): Promise<any> {
+  // 1. 构建提示词
+  const JsonResultParsePrompt = `请严格按照以下要求生成JSON数据:
+- 数据结构要求:${jsonSchema}
+- 只能返回一个完整的JSON对象 确保JSON格式正确
+- 注意返回的JSON格式每个KEY都有""包裹和Value之间都有:`;
+// ${example ? `2. 参考示例格式:\n${JSON.stringify(example, null, 2)}` : ''}
+
+  // 2. 初始化消息列表
+  const messages: TestMessage[] = [
+    {
+      role: "user",
+      content: prompt+JsonResultParsePrompt
+    }
+  ];
+
+  // 3. 创建TestCompletion实例
+  const completion = new TestCompletion(messages);
+  
+  // 4. 存储累积内容和JSON对象
+  let fullContent = "";
+  let jsonObject: any = null;
+  
+  // 5. 发送请求并处理流式响应
+  const result = await completion.sendMessage(null, (content) => {
+    fullContent = content;
+  });
+  console.log("fullContent",fullContent)
+  // 6. 最终JSON提取(确保获取完整内容)
+  try {
+    // 再次尝试从完整内容中提取JSON
+      jsonObject = extractJSON(fullContent);
+  } catch (e) {
+    console.error("JSON解析失败:", e);
+    console.log("原始内容:", fullContent);
+    throw new Error("生成的响应不符合JSON格式");
+  }
+  
+  return jsonObject;
+}
+
+function extractJSON(str:string){
+  let stack = 0;
+  let startIndex = -1;
+  let result = null;
+
+  for (let i = 0; i < str.length; i++) {
+    if (str[i] === '{') {
+      if (stack === 0) startIndex = i;
+      stack++;
+    } else if (str[i] === '}') {
+      stack--;
+      if (stack === 0 && startIndex !== -1) {
+        try {
+          result = JSON.parse(str.slice(startIndex, i + 1));
+          break;
+        } catch (e) {
+          // 继续尝试下一个可能的 JSON
+          startIndex = -1;
+        }
+      }
+    }
+  }
+  return result;
+};