LinkToolAddin/host/Gateway.cs
2025-05-23 21:40:39 +08:00

210 lines
9.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Threading;
using System.Xml.Linq;
using LinkToolAddin.client;
using LinkToolAddin.client.prompt;
using LinkToolAddin.host.llm;
using LinkToolAddin.host.llm.entity;
using LinkToolAddin.host.mcp;
using LinkToolAddin.host.prompt;
using LinkToolAddin.message;
using ModelContextProtocol.Protocol.Types;
using Newtonsoft.Json;
namespace LinkToolAddin.host;
public class Gateway
{
public static async void SendMessage(string message, string model, string gdbPath, Action<MessageListItem> callback)
{
Llm bailian = new Bailian
{
api_key = "sk-db177155677e438f832860e7f4da6afc"
};
List<Message> messages = new List<Message>();
messages.Add(new Message
{
Role = "system",
Content = SystemPrompt.SysPromptTemplate
});
messages.Add(new Message
{
Role = "user",
Content = message
});
bool goOn = true;
string pattern = "<tool_use>[\\s\\S]*?<\\/tool_use>";
string promptPattern = "<prompt>[\\s\\S]*?<\\/prompt>";
Dictionary<string,McpServer> servers = new Dictionary<string, McpServer>();
while (goOn)
{
string reponse = await bailian.SendChatAsync(new LlmJsonContent()
{
Model = model,
Messages = messages,
Temperature = 0.7,
TopP = 1,
MaxTokens = 1000,
});
messages.Add(new Message
{
Role = "assistant",
Content = reponse
});
if (Regex.IsMatch(reponse, pattern))
{
//工具类型的消息
XElement toolUse = XElement.Parse(reponse);
string fullToolName = toolUse.Element("name")?.Value;
string toolArgs = toolUse.Element("arguments")?.Value;
Dictionary<string, object> toolParams = JsonConvert.DeserializeObject<Dictionary<string, object>>(toolArgs);
string serverName = fullToolName.Contains(":") ? fullToolName.Split(':')[0] : fullToolName;
string toolName = fullToolName.Contains(":") ? fullToolName.Split(':')[1] : fullToolName;
McpServer mcpServer = servers[serverName];
if (mcpServer is SseMcpServer)
{
SseMcpServer sseMcpServer = mcpServer as SseMcpServer;
SseMcpClient client = new SseMcpClient(sseMcpServer.BaseUrl);
CallToolResponse toolResponse = await client.CallToolAsync(toolName,toolParams);
MessageListItem toolMessageItem = new ToolMessageItem
{
toolName = toolName,
toolParams = toolParams,
type = MessageType.TOOL_MESSAGE,
status = toolResponse.IsError ? "fail" : "success",
content = toolResponse.Content.ToString()
};
messages.Add(new Message
{
Role = "user",
Content = toolResponse.IsError ? SystemPrompt.ErrorPromptTemplate : SystemPrompt.ContinuePromptTemplate
});
messages.Add(new Message
{
Role = "user",
Content = JsonConvert.SerializeObject(toolResponse)
});
callback?.Invoke(toolMessageItem);
}else if (mcpServer is StdioMcpServer)
{
StdioMcpServer stdioMcpServer = mcpServer as StdioMcpServer;
StdioMcpClient client = new StdioMcpClient(stdioMcpServer.Command, stdioMcpServer.Args);
CallToolResponse toolResponse = await client.CallToolAsync(toolName,toolParams);
MessageListItem toolMessageItem = new ToolMessageItem
{
toolName = toolName,
toolParams = toolParams,
type = MessageType.TOOL_MESSAGE,
status = toolResponse.IsError ? "fail" : "success",
content = toolResponse.Content.ToString()
};
messages.Add(new Message
{
Role = "user",
Content = toolResponse.IsError ? SystemPrompt.ErrorPromptTemplate : SystemPrompt.ContinuePromptTemplate
});
messages.Add(new Message
{
Role = "user",
Content = JsonConvert.SerializeObject(toolResponse)
});
callback?.Invoke(toolMessageItem);
}
}
else if (Regex.IsMatch(reponse, promptPattern))
{
XElement prompt = XElement.Parse(reponse);
string fullPromptName = prompt.Element("name")?.Value;
string promptArgs = prompt.Element("arguments")?.Value;
Dictionary<string, object> promptParams = JsonConvert.DeserializeObject<Dictionary<string, object>>(promptArgs);
string serverName = fullPromptName.Contains(":") ? fullPromptName.Split(':')[0] : fullPromptName;
string promptName = fullPromptName.Contains(":") ? fullPromptName.Split(':')[1] : fullPromptName;
string promptRes = DynamicPrompt.GetPrompt(promptName, promptParams);
messages.Add(new Message
{
Role = "user",
Content = promptRes
});
}
else
{
MessageListItem chatMessageListItem = new ChatMessageItem()
{
content = reponse,
role = "assistant",
type = MessageType.CHAT_MESSAGE
};
callback?.Invoke(chatMessageListItem);
}
if (reponse == "[DONE]")
{
goOn = false;
}
}
}
public static async void TestChatMessage(string message, string model, string gdbPath,//messageqwen-max传个空字符串传一个方法回调,用来调用方法1
Action<MessageListItem> callback)
{
MessageListItem chatListItem = new ChatMessageItem//返回的东西1
{
content = message,
role = "assistant",//角色assistant是ai的回答user用户的回答sistant系统提示词1
type = MessageType.CHAT_MESSAGE,//根据type判断是工具卡还是聊天卡1
id = "testmsg12345"//琅哥虚构的定位可以用引用选中凭id找1
};
callback?.Invoke(chatListItem);
}
public static async void TestToolMessage(string message, string model, string gdbPath, Action<MessageListItem> callback)//同上1
{
MessageListItem toolListItem = new ToolMessageItem
{
content = message,//大模型生成的信息正常来说是个x啥1
type = MessageType.TOOL_MESSAGE,
toolName = "arcgis_pro.executeTool",//要调用的工具名称大模型工具不是arcgis工具调⽤ArcGIS Pro.GP工具调用1
toolParams = new Dictionary<string, object>
{
{"gp_name","analysis.Buffer"},//传参要传Arcgis的工具名
{"gp_params","[\"C:\\test.gdb\\river\",\"30 Meters\"]"}//工具参数数组字符串要转成数组前端要调用OpenTrueDialog没听懂1
},
id = "testtool123456",
status = "success",//显示勾
role = "user",
result = "成功创建缓冲区"
};
callback?.Invoke(toolListItem);//这些调用结果显示在前端显示点后面的工具名称用户点的时候展开1
}
public static async void TestWorkflow(string message, string model, string gdbPath, Action<MessageListItem> callback)
{
Thread.Sleep(2000);
MessageListItem chatListItem = new ChatMessageItem
{
content = message,
role = "assistant",
type = MessageType.CHAT_MESSAGE,
id = "testid12345"
};
callback?.Invoke(chatListItem);
Thread.Sleep(1500);
MessageListItem toolListItem = new ToolMessageItem
{
content = message,
type = MessageType.TOOL_MESSAGE,
toolName = "arcgis_pro.executeTool",
toolParams = new Dictionary<string, object>
{
{"gp_name","analysis.Buffer"},
{"gp_params","[\"C:\\test.gdb\\river\",\"30 Meters\"]"}
},
id = "testtool123456",
status = "success",
role = "user",
result = "成功创建缓冲区"
};
callback?.Invoke(toolListItem);
}
}