mirror of
				https://github.com/Yidadaa/ChatGPT-Next-Web.git
				synced 2025-10-31 05:39:20 +08:00 
			
		
		
		
	kimi support function call
This commit is contained in:
		| @@ -8,9 +8,15 @@ import { | |||||||
|   REQUEST_TIMEOUT_MS, |   REQUEST_TIMEOUT_MS, | ||||||
|   ServiceProvider, |   ServiceProvider, | ||||||
| } from "@/app/constant"; | } from "@/app/constant"; | ||||||
| import { useAccessStore, useAppConfig, useChatStore } from "@/app/store"; | import { | ||||||
|  |   useAccessStore, | ||||||
|  |   useAppConfig, | ||||||
|  |   useChatStore, | ||||||
|  |   ChatMessageTool, | ||||||
|  |   usePluginStore, | ||||||
|  | } from "@/app/store"; | ||||||
| import { collectModelsWithDefaultModel } from "@/app/utils/model"; | import { collectModelsWithDefaultModel } from "@/app/utils/model"; | ||||||
| import { preProcessImageContent } from "@/app/utils/chat"; | import { preProcessImageContent, stream } from "@/app/utils/chat"; | ||||||
| import { cloudflareAIGatewayUrl } from "@/app/utils/cloudflare"; | import { cloudflareAIGatewayUrl } from "@/app/utils/cloudflare"; | ||||||
|  |  | ||||||
| import { | import { | ||||||
| @@ -116,115 +122,67 @@ export class MoonshotApi implements LLMApi { | |||||||
|       ); |       ); | ||||||
|  |  | ||||||
|       if (shouldStream) { |       if (shouldStream) { | ||||||
|         let responseText = ""; |         const [tools, funcs] = usePluginStore | ||||||
|         let remainText = ""; |           .getState() | ||||||
|         let finished = false; |           .getAsTools( | ||||||
|  |             useChatStore.getState().currentSession().mask?.plugin as string[], | ||||||
|         // animate response to make it looks smooth |           ); | ||||||
|         function animateResponseText() { |         console.log("getAsTools", tools, funcs); | ||||||
|           if (finished || controller.signal.aborted) { |         return stream( | ||||||
|             responseText += remainText; |           chatPath, | ||||||
|             console.log("[Response Animation] finished"); |           requestPayload, | ||||||
|             if (responseText?.length === 0) { |           getHeaders(), | ||||||
|               options.onError?.(new Error("empty response from server")); |           tools as any, | ||||||
|  |           funcs, | ||||||
|  |           controller, | ||||||
|  |           // parseSSE | ||||||
|  |           (text: string, runTools: ChatMessageTool[]) => { | ||||||
|  |             // console.log("parseSSE", text, runTools); | ||||||
|  |             const json = JSON.parse(text); | ||||||
|  |             const choices = json.choices as Array<{ | ||||||
|  |               delta: { | ||||||
|  |                 content: string; | ||||||
|  |                 tool_calls: ChatMessageTool[]; | ||||||
|  |               }; | ||||||
|  |             }>; | ||||||
|  |             const tool_calls = choices[0]?.delta?.tool_calls; | ||||||
|  |             if (tool_calls?.length > 0) { | ||||||
|  |               const index = tool_calls[0]?.index; | ||||||
|  |               const id = tool_calls[0]?.id; | ||||||
|  |               const args = tool_calls[0]?.function?.arguments; | ||||||
|  |               if (id) { | ||||||
|  |                 runTools.push({ | ||||||
|  |                   id, | ||||||
|  |                   type: tool_calls[0]?.type, | ||||||
|  |                   function: { | ||||||
|  |                     name: tool_calls[0]?.function?.name as string, | ||||||
|  |                     arguments: args, | ||||||
|  |                   }, | ||||||
|  |                 }); | ||||||
|  |               } else { | ||||||
|  |                 // @ts-ignore | ||||||
|  |                 runTools[index]["function"]["arguments"] += args; | ||||||
|  |               } | ||||||
|             } |             } | ||||||
|             return; |             return choices[0]?.delta?.content; | ||||||
|           } |           }, | ||||||
|  |           // processToolMessage, include tool_calls message and tool call results | ||||||
|           if (remainText.length > 0) { |           ( | ||||||
|             const fetchCount = Math.max(1, Math.round(remainText.length / 60)); |             requestPayload: RequestPayload, | ||||||
|             const fetchText = remainText.slice(0, fetchCount); |             toolCallMessage: any, | ||||||
|             responseText += fetchText; |             toolCallResult: any[], | ||||||
|             remainText = remainText.slice(fetchCount); |           ) => { | ||||||
|             options.onUpdate?.(responseText, fetchText); |             // @ts-ignore | ||||||
|           } |             requestPayload?.messages?.splice( | ||||||
|  |               // @ts-ignore | ||||||
|           requestAnimationFrame(animateResponseText); |               requestPayload?.messages?.length, | ||||||
|         } |               0, | ||||||
|  |               toolCallMessage, | ||||||
|         // start animaion |               ...toolCallResult, | ||||||
|         animateResponseText(); |  | ||||||
|  |  | ||||||
|         const finish = () => { |  | ||||||
|           if (!finished) { |  | ||||||
|             finished = true; |  | ||||||
|             options.onFinish(responseText + remainText); |  | ||||||
|           } |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         controller.signal.onabort = finish; |  | ||||||
|  |  | ||||||
|         fetchEventSource(chatPath, { |  | ||||||
|           ...chatPayload, |  | ||||||
|           async onopen(res) { |  | ||||||
|             clearTimeout(requestTimeoutId); |  | ||||||
|             const contentType = res.headers.get("content-type"); |  | ||||||
|             console.log( |  | ||||||
|               "[OpenAI] request response content type: ", |  | ||||||
|               contentType, |  | ||||||
|             ); |             ); | ||||||
|  |  | ||||||
|             if (contentType?.startsWith("text/plain")) { |  | ||||||
|               responseText = await res.clone().text(); |  | ||||||
|               return finish(); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if ( |  | ||||||
|               !res.ok || |  | ||||||
|               !res.headers |  | ||||||
|                 .get("content-type") |  | ||||||
|                 ?.startsWith(EventStreamContentType) || |  | ||||||
|               res.status !== 200 |  | ||||||
|             ) { |  | ||||||
|               const responseTexts = [responseText]; |  | ||||||
|               let extraInfo = await res.clone().text(); |  | ||||||
|               try { |  | ||||||
|                 const resJson = await res.clone().json(); |  | ||||||
|                 extraInfo = prettyObject(resJson); |  | ||||||
|               } catch {} |  | ||||||
|  |  | ||||||
|               if (res.status === 401) { |  | ||||||
|                 responseTexts.push(Locale.Error.Unauthorized); |  | ||||||
|               } |  | ||||||
|  |  | ||||||
|               if (extraInfo) { |  | ||||||
|                 responseTexts.push(extraInfo); |  | ||||||
|               } |  | ||||||
|  |  | ||||||
|               responseText = responseTexts.join("\n\n"); |  | ||||||
|  |  | ||||||
|               return finish(); |  | ||||||
|             } |  | ||||||
|           }, |           }, | ||||||
|           onmessage(msg) { |           options, | ||||||
|             if (msg.data === "[DONE]" || finished) { |         ); | ||||||
|               return finish(); |  | ||||||
|             } |  | ||||||
|             const text = msg.data; |  | ||||||
|             try { |  | ||||||
|               const json = JSON.parse(text); |  | ||||||
|               const choices = json.choices as Array<{ |  | ||||||
|                 delta: { content: string }; |  | ||||||
|               }>; |  | ||||||
|               const delta = choices[0]?.delta?.content; |  | ||||||
|               const textmoderation = json?.prompt_filter_results; |  | ||||||
|  |  | ||||||
|               if (delta) { |  | ||||||
|                 remainText += delta; |  | ||||||
|               } |  | ||||||
|             } catch (e) { |  | ||||||
|               console.error("[Request] parse error", text, msg); |  | ||||||
|             } |  | ||||||
|           }, |  | ||||||
|           onclose() { |  | ||||||
|             finish(); |  | ||||||
|           }, |  | ||||||
|           onerror(e) { |  | ||||||
|             options.onError?.(e); |  | ||||||
|             throw e; |  | ||||||
|           }, |  | ||||||
|           openWhenHidden: true, |  | ||||||
|         }); |  | ||||||
|       } else { |       } else { | ||||||
|         const res = await fetch(chatPath, chatPayload); |         const res = await fetch(chatPath, chatPayload); | ||||||
|         clearTimeout(requestTimeoutId); |         clearTimeout(requestTimeoutId); | ||||||
|   | |||||||
| @@ -273,7 +273,11 @@ export function isDalle3(model: string) { | |||||||
| } | } | ||||||
|  |  | ||||||
| export function showPlugins(provider: ServiceProvider, model: string) { | export function showPlugins(provider: ServiceProvider, model: string) { | ||||||
|   if (provider == ServiceProvider.OpenAI || provider == ServiceProvider.Azure) { |   if ( | ||||||
|  |     provider == ServiceProvider.OpenAI || | ||||||
|  |     provider == ServiceProvider.Azure || | ||||||
|  |     provider == ServiceProvider.Moonshot | ||||||
|  |   ) { | ||||||
|     return true; |     return true; | ||||||
|   } |   } | ||||||
|   if (provider == ServiceProvider.Anthropic && !model.includes("claude-2")) { |   if (provider == ServiceProvider.Anthropic && !model.includes("claude-2")) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user