From a3cfcb90e3a23429afe42a539ea6d608158299fe Mon Sep 17 00:00:00 2001 From: PeterZhong Date: Fri, 16 May 2025 00:27:50 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E5=B7=A5=E4=BD=9C=E6=B5=81?= =?UTF-8?q?=E6=8E=A7=E5=88=B6=E9=9D=A2=EF=BC=8C=E9=A2=84=E7=95=99=E5=89=8D?= =?UTF-8?q?=E7=AB=AF=E6=8E=A5=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Config.daml | 13 +- LinkToolAddin.csproj | 1 - Properties/launchSettings.json | 6 +- .../{PythonMcpClient.cs => StdioMcpClient.cs} | 0 client/prompt/DynamicPrompt.cs | 18 ++ client/prompt/PromptTemplates.cs | 20 +++ host/Gateway.cs | 146 ++++++++++++++++ host/ToolRequest.cs | 6 + host/mcp/McpServer.cs | 24 +++ host/mcp/SseMcpServer.cs | 30 ++++ host/mcp/StdioMcpServer.cs | 30 ++++ host/prompt/SystemPrompt.cs | 11 ++ host/prompt/UserPrompt.cs | 6 + server/ArcGISProMcpServer.cs | 37 +++++ ui/dockpane/DialogDockpane.xaml.cs | 65 +------- ui/dockpane/TestDockpane.xaml | 28 ++++ ui/dockpane/TestDockpane.xaml.cs | 157 ++++++++++++++++++ ui/dockpane/TestDockpaneViewModel.cs | 62 +++++++ ui/message/ChatMessageItem.cs | 9 + ui/message/MessageListItem.cs | 8 + ui/message/ToolMessageItem.cs | 15 ++ 21 files changed, 624 insertions(+), 68 deletions(-) rename client/{PythonMcpClient.cs => StdioMcpClient.cs} (100%) create mode 100644 client/prompt/DynamicPrompt.cs create mode 100644 client/prompt/PromptTemplates.cs create mode 100644 host/Gateway.cs create mode 100644 host/ToolRequest.cs create mode 100644 host/mcp/McpServer.cs create mode 100644 host/mcp/SseMcpServer.cs create mode 100644 host/mcp/StdioMcpServer.cs create mode 100644 host/prompt/SystemPrompt.cs create mode 100644 host/prompt/UserPrompt.cs create mode 100644 server/ArcGISProMcpServer.cs create mode 100644 ui/dockpane/TestDockpane.xaml create mode 100644 ui/dockpane/TestDockpane.xaml.cs create mode 100644 ui/dockpane/TestDockpaneViewModel.cs create mode 100644 ui/message/ChatMessageItem.cs create mode 100644 ui/message/ToolMessageItem.cs diff --git a/Config.daml b/Config.daml index 9147f6f..18a04f2 100644 --- a/Config.daml +++ b/Config.daml @@ -23,9 +23,10 @@ - + + + + diff --git a/LinkToolAddin.csproj b/LinkToolAddin.csproj index f683eae..e0d0d0e 100644 --- a/LinkToolAddin.csproj +++ b/LinkToolAddin.csproj @@ -99,7 +99,6 @@ - diff --git a/Properties/launchSettings.json b/Properties/launchSettings.json index 42da189..5a2c881 100644 --- a/Properties/launchSettings.json +++ b/Properties/launchSettings.json @@ -2,7 +2,11 @@ "profiles": { "LinkToolAddin": { "commandName": "Executable", - "executablePath": "C:\\Program Files\\ArcGIS\\Pro\\bin\\ArcGISPro.exe" + "executablePath": "C:\\Program Files\\ArcGIS\\Pro\\bin\\ArcGISPro.exe", + "applicationUrl": "https://localhost:5001", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } } } } \ No newline at end of file diff --git a/client/PythonMcpClient.cs b/client/StdioMcpClient.cs similarity index 100% rename from client/PythonMcpClient.cs rename to client/StdioMcpClient.cs diff --git a/client/prompt/DynamicPrompt.cs b/client/prompt/DynamicPrompt.cs new file mode 100644 index 0000000..2a342e7 --- /dev/null +++ b/client/prompt/DynamicPrompt.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; + +namespace LinkToolAddin.client.prompt; + +public class DynamicPrompt +{ + public static string GetPrompt(string name,Dictionary args) + { + PromptTemplates promptTemplate = new PromptTemplates(); + string template = promptTemplate.GetPrompt(name); + foreach (KeyValuePair pair in args) + { + string replaceKey = "{{"+pair.Key+"}}"; + template.Replace(replaceKey, pair.Value.ToString()); + } + return template; + } +} \ No newline at end of file diff --git a/client/prompt/PromptTemplates.cs b/client/prompt/PromptTemplates.cs new file mode 100644 index 0000000..3992482 --- /dev/null +++ b/client/prompt/PromptTemplates.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; + +namespace LinkToolAddin.client.prompt; + +public class PromptTemplates +{ + private Dictionary prompts = new Dictionary(); + + public PromptTemplates() + { + prompts.Add("plan", "请根据用户所提问题进行工具规划"); + prompts.Add("param", "根据帮助文档填写工具参数"); + prompts.Add("code", "现在需要生成代码,要求语法正确"); + } + + public string GetPrompt(string name) + { + return prompts[name]; + } +} \ No newline at end of file diff --git a/host/Gateway.cs b/host/Gateway.cs new file mode 100644 index 0000000..8237927 --- /dev/null +++ b/host/Gateway.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +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 callback) + { + Llm bailian = new Bailian + { + api_key = "sk-db177155677e438f832860e7f4da6afc" + }; + List messages = new List(); + messages.Add(new Message + { + Role = "system", + Content = SystemPrompt.SysPromptTemplate + }); + messages.Add(new Message + { + Role = "user", + Content = message + }); + bool goOn = true; + string pattern = "[\\s\\S]*?<\\/tool_use>"; + string promptPattern = "[\\s\\S]*?<\\/prompt>"; + Dictionary servers = new Dictionary(); + 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 toolParams = JsonConvert.DeserializeObject>(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 promptParams = JsonConvert.DeserializeObject>(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; + } + } + } +} \ No newline at end of file diff --git a/host/ToolRequest.cs b/host/ToolRequest.cs new file mode 100644 index 0000000..944026a --- /dev/null +++ b/host/ToolRequest.cs @@ -0,0 +1,6 @@ +namespace LinkToolAddin.host; + +public class ToolRequest +{ + +} \ No newline at end of file diff --git a/host/mcp/McpServer.cs b/host/mcp/McpServer.cs new file mode 100644 index 0000000..616798c --- /dev/null +++ b/host/mcp/McpServer.cs @@ -0,0 +1,24 @@ +namespace LinkToolAddin.host.mcp +{ + using System; + using System.Collections.Generic; + + using System.Globalization; + using Newtonsoft.Json; + using Newtonsoft.Json.Converters; + + public partial class McpServer + { + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("type")] + public string Type { get; set; } + + [JsonProperty("description")] + public string Description { get; set; } + + [JsonProperty("isActive")] + public bool IsActive { get; set; } + } +} \ No newline at end of file diff --git a/host/mcp/SseMcpServer.cs b/host/mcp/SseMcpServer.cs new file mode 100644 index 0000000..cd2525e --- /dev/null +++ b/host/mcp/SseMcpServer.cs @@ -0,0 +1,30 @@ +namespace LinkToolAddin.host.mcp +{ + using System; + using System.Collections.Generic; + + using System.Globalization; + using Newtonsoft.Json; + using Newtonsoft.Json.Converters; + + public partial class SseMcpServer : McpServer + { + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("type")] + public string Type { get; set; } + + [JsonProperty("description")] + public string Description { get; set; } + + [JsonProperty("isActive")] + public bool IsActive { get; set; } + + [JsonProperty("baseUrl")] + public string BaseUrl { get; set; } + + [JsonProperty("headers")] + public Dictionary Headers { get; set; } + } +} \ No newline at end of file diff --git a/host/mcp/StdioMcpServer.cs b/host/mcp/StdioMcpServer.cs new file mode 100644 index 0000000..a70ce40 --- /dev/null +++ b/host/mcp/StdioMcpServer.cs @@ -0,0 +1,30 @@ +namespace LinkToolAddin.host.mcp +{ + using System; + using System.Collections.Generic; + + using System.Globalization; + using Newtonsoft.Json; + using Newtonsoft.Json.Converters; + + public partial class StdioMcpServer : McpServer + { + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("type")] + public string Type { get; set; } + + [JsonProperty("isActive")] + public bool IsActive { get; set; } + + [JsonProperty("registryUrl")] + public string RegistryUrl { get; set; } + + [JsonProperty("command")] + public string Command { get; set; } + + [JsonProperty("args")] + public List Args { get; set; } + } +} \ No newline at end of file diff --git a/host/prompt/SystemPrompt.cs b/host/prompt/SystemPrompt.cs new file mode 100644 index 0000000..bcd3768 --- /dev/null +++ b/host/prompt/SystemPrompt.cs @@ -0,0 +1,11 @@ +namespace LinkToolAddin.host.prompt; + +public class SystemPrompt +{ + public static string SysPromptTemplate = "现在你是一个精通ArcGIS Pro的专家,请以此身份回答用户的问题。"; + + public static string ContinuePromptTemplate = "上一个工具执行的结果如下,请据此继续执行"; + + public static string ErrorPromptTemplate = "执行上一个工具的时候出现以下错误,请根据报错信息重试"; + +} \ No newline at end of file diff --git a/host/prompt/UserPrompt.cs b/host/prompt/UserPrompt.cs new file mode 100644 index 0000000..128de5b --- /dev/null +++ b/host/prompt/UserPrompt.cs @@ -0,0 +1,6 @@ +namespace LinkToolAddin.host.prompt; + +public class UserPrompt +{ + +} \ No newline at end of file diff --git a/server/ArcGISProMcpServer.cs b/server/ArcGISProMcpServer.cs new file mode 100644 index 0000000..7aa94f7 --- /dev/null +++ b/server/ArcGISProMcpServer.cs @@ -0,0 +1,37 @@ +using System; +using System.ComponentModel; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using ModelContextProtocol.Server; + +namespace LinkToolAddin.server; + +public class ArcGISProMcpServer +{ + public static async void TestMcpServer() + { + var builder = WebApplication.CreateBuilder(); + builder.Logging.AddConsole(options => + { + options.LogToStandardErrorThreshold = LogLevel.Trace; + });; + builder.Services.AddMcpServer().WithHttpTransport().WithToolsFromAssembly(); + var app = builder.Build(); + app.MapMcp("/sse"); + app.MapGet("/", () => "MCP Server is running!"); + Console.WriteLine("About to start server..."); + await app.RunAsync(); + } +} + +[McpServerToolType] +public static class EchoTool +{ + [McpServerTool, Description("Echoes the message back to the client.")] + public static string Echo(string message) + { + Console.WriteLine($"received message: {message}"); + return $"hello {message}"; + } +} \ No newline at end of file diff --git a/ui/dockpane/DialogDockpane.xaml.cs b/ui/dockpane/DialogDockpane.xaml.cs index 3487472..aa2ea7f 100644 --- a/ui/dockpane/DialogDockpane.xaml.cs +++ b/ui/dockpane/DialogDockpane.xaml.cs @@ -17,6 +17,7 @@ using LinkToolAddin.client; using LinkToolAddin.host.llm; using LinkToolAddin.host.llm.entity; using LinkToolAddin.resource; +using LinkToolAddin.server; using log4net; using log4net.Appender; using log4net.Config; @@ -40,72 +41,10 @@ namespace LinkToolAddin.ui.dockpane InitLogger(); InitializeComponent(); } - - public void CallBack(string str,object obj) - { - log.Info($"CallBack {str}"); - } private async void TestServer_OnClick(object sender, RoutedEventArgs e) { log.Info("TestServer Clicked"); - List args = new List(); - args.Add("mcp-server-time"); - args.Add("--local-timezone=America/New_York"); - McpClient stdioMcpClient = new StdioMcpClient("uvx",args); - IList tools = await stdioMcpClient.GetToolListAsync(); - foreach (McpClientTool tool in tools) - { - log.Info(tool.JsonSchema.ToString()); - } - CallToolResponse response = await stdioMcpClient.CallToolAsync("get_current_time", - new Dictionary { { "timezone", "America/New_York" } }); - log.Info(JsonConvert.SerializeObject(response)); - } - - private async void SseMcp_test() - { - SseMcpClient client = new SseMcpClient("https://mcp.amap.com/sse?key=ed418512c94ade8f83d42c37b77d2bb2"); - IList tools = await client.GetToolListAsync(); - foreach (McpClientTool tool in tools) - { - log.Info(tool.JsonSchema.ToString()); - } - } - - private async void Retrieve_Test() - { - log.Info("TestServer Clicked"); - // string jsonRpcString = @"{""jsonrpc"":""2.0"",""method"":""CallArcGISPro.CallArcGISProTool"",""params"":{""toolName"":""analysis.Buffer"",""toolParams"":""[\""D:/01_Development/02_ArcGIS_Pro_Project/20250319_GisAi/Test.gdb/河流\"",\""D:/01_Development/02_ArcGIS_Pro_Project/20250319_GisAi/Test.gdb/河流buffer\"",\""100\""]""},""id"":1}"; - DocDb docDb = new DocDb("sk-db177155677e438f832860e7f4da6afc", DocDb.KnowledgeBase.ArcGISProHelpDoc); - string query = "缓冲区"; - KnowledgeResult knowledgeResult = await docDb.Retrieve(query); - log.Info(JsonConvert.SerializeObject(knowledgeResult.ChunkList)); - } - - private async void Request_Bailian_Test() - { - Llm bailian = new Bailian - { - api_key = "sk-db177155677e438f832860e7f4da6afc", - app_id = "6a77c5a68de64f469b79fcdcde9d5001", - }; - string reponse = await bailian.SendChatAsync(new LlmJsonContent() - { - Model = "qwen-max", - Messages = new List() - { - new Message() - { - Role = "user", - Content = "你是谁" - } - }, - Temperature = 0.7, - TopP = 1, - MaxTokens = 1000, - }); - log.Info(reponse); } protected void InitLogger() @@ -121,7 +60,7 @@ namespace LinkToolAddin.ui.dockpane // 2. 创建文件滚动输出器(按大小滚动) var fileAppender = new RollingFileAppender { - File = Path.Combine("Logs", "linktool_app.log"), // 日志文件路径 + File = Path.Combine("Logs", "D:\\linktool_app.log"), // 日志文件路径 AppendToFile = true, // 追加模式 RollingStyle = RollingFileAppender.RollingMode.Size, // 按文件大小滚动 MaxSizeRollBackups = 10, // 保留 10 个历史文件 diff --git a/ui/dockpane/TestDockpane.xaml b/ui/dockpane/TestDockpane.xaml new file mode 100644 index 0000000..4782989 --- /dev/null +++ b/ui/dockpane/TestDockpane.xaml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ui/dockpane/TestDockpane.xaml.cs b/ui/dockpane/TestDockpane.xaml.cs new file mode 100644 index 0000000..6f33bb6 --- /dev/null +++ b/ui/dockpane/TestDockpane.xaml.cs @@ -0,0 +1,157 @@ +using System.Collections.Generic; +using System.Windows; +using System.Windows.Controls; +using LinkToolAddin.client; +using LinkToolAddin.host; +using LinkToolAddin.host.llm; +using LinkToolAddin.host.llm.entity; +using LinkToolAddin.message; +using LinkToolAddin.resource; +using LinkToolAddin.server; +using log4net; +using log4net.Appender; +using log4net.Config; +using log4net.Layout; +using ModelContextProtocol.Client; +using ModelContextProtocol.Protocol.Types; +using Newtonsoft.Json; + + +namespace LinkToolAddin.ui.dockpane +{ + /// + /// Interaction logic for TestDockpaneView.xaml + /// + public partial class TestDockpaneView : UserControl + { + private static ILog log = LogManager.GetLogger(typeof(TestDockpaneView)); + + public TestDockpaneView() + { + InitLogger(); + InitializeComponent(); + } + + protected void InitLogger() + { + // 1. 创建控制台输出器(Appender) + var consoleAppender = new ConsoleAppender + { + Layout = new PatternLayout("%date [%thread] %-5level %logger - %message%newline"), + Threshold = log4net.Core.Level.Info // 仅输出 Info 及以上级别 + }; + consoleAppender.ActivateOptions(); // 激活配置 + + // 2. 创建文件滚动输出器(按大小滚动) + var fileAppender = new RollingFileAppender + { + File = System.IO.Path.Combine("Logs", "linktool_app.log"), // 日志文件路径 + AppendToFile = true, // 追加模式 + RollingStyle = RollingFileAppender.RollingMode.Size, // 按文件大小滚动 + MaxSizeRollBackups = 10, // 保留 10 个历史文件 + MaximumFileSize = "1MB", // 单个文件最大 1MB + StaticLogFileName = true, // 固定文件名(否则自动追加序号) + Layout = new PatternLayout("%date [%thread] %-5level %logger - %message%newline"), + Threshold = log4net.Core.Level.Info // 仅输出 Info 及以上级别 + }; + fileAppender.ActivateOptions(); // 激活配置 + + // 3. 直接通过 BasicConfigurator 注册 Appender + BasicConfigurator.Configure(consoleAppender, fileAppender); + + log = LogManager.GetLogger(typeof(DialogDockpaneView)); + + // 测试日志输出 + log.Debug("Debug 日志(控制台可见)"); + log.Info("Info 日志(控制台和文件可见)"); + log.Error("Error 日志(严重问题)"); + } + + public void CallBack(string str,object obj) + { + log.Info($"CallBack {str}"); + } + + private async void TestServer_OnClick(object sender, RoutedEventArgs e) + { + log.Info("TestServer Clicked"); + ArcGISProMcpServer.TestMcpServer(); + } + + private async void StdioMcp_test() + { + List args = new List(); + args.Add("mcp-server-time"); + args.Add("--local-timezone=America/New_York"); + McpClient stdioMcpClient = new StdioMcpClient("uvx",args); + IList tools = await stdioMcpClient.GetToolListAsync(); + foreach (McpClientTool tool in tools) + { + log.Info(tool.JsonSchema.ToString()); + } + CallToolResponse response = await stdioMcpClient.CallToolAsync("get_current_time", + new Dictionary { { "timezone", "America/New_York" } }); + log.Info(JsonConvert.SerializeObject(response)); + } + + private async void SseMcp_test() + { + SseMcpClient client = new SseMcpClient("https://mcp.amap.com/sse?key=ed418512c94ade8f83d42c37b77d2bb2"); + IList tools = await client.GetToolListAsync(); + foreach (McpClientTool tool in tools) + { + log.Info(tool.JsonSchema.ToString()); + } + } + + private async void Retrieve_Test() + { + log.Info("TestServer Clicked"); + // string jsonRpcString = @"{""jsonrpc"":""2.0"",""method"":""CallArcGISPro.CallArcGISProTool"",""params"":{""toolName"":""analysis.Buffer"",""toolParams"":""[\""D:/01_Development/02_ArcGIS_Pro_Project/20250319_GisAi/Test.gdb/河流\"",\""D:/01_Development/02_ArcGIS_Pro_Project/20250319_GisAi/Test.gdb/河流buffer\"",\""100\""]""},""id"":1}"; + DocDb docDb = new DocDb("sk-db177155677e438f832860e7f4da6afc", DocDb.KnowledgeBase.ArcGISProHelpDoc); + string query = "缓冲区"; + KnowledgeResult knowledgeResult = await docDb.Retrieve(query); + log.Info(JsonConvert.SerializeObject(knowledgeResult.ChunkList)); + } + + private async void Request_Bailian_Test() + { + Llm bailian = new Bailian + { + api_key = "sk-db177155677e438f832860e7f4da6afc", + app_id = "6a77c5a68de64f469b79fcdcde9d5001", + }; + string reponse = await bailian.SendChatAsync(new LlmJsonContent() + { + Model = "qwen-max", + Messages = new List() + { + new Message() + { + Role = "user", + Content = "你是谁" + } + }, + Temperature = 0.7, + TopP = 1, + MaxTokens = 1000, + }); + log.Info(reponse); + } + + private void TestButton_OnClick(object sender, RoutedEventArgs e) + { + throw new System.NotImplementedException(); + } + + private void TestWorkflow_OnClick(object sender, RoutedEventArgs e) + { + Gateway.SendMessage("你好","qwen-max","test.gdb",ShowMessage); + } + + public void ShowMessage(MessageListItem msg) + { + log.Info(msg.content); + } + } +} diff --git a/ui/dockpane/TestDockpaneViewModel.cs b/ui/dockpane/TestDockpaneViewModel.cs new file mode 100644 index 0000000..0661d9c --- /dev/null +++ b/ui/dockpane/TestDockpaneViewModel.cs @@ -0,0 +1,62 @@ +using ArcGIS.Core.CIM; +using ArcGIS.Core.Data; +using ArcGIS.Core.Geometry; +using ArcGIS.Desktop.Catalog; +using ArcGIS.Desktop.Core; +using ArcGIS.Desktop.Editing; +using ArcGIS.Desktop.Extensions; +using ArcGIS.Desktop.Framework; +using ArcGIS.Desktop.Framework.Contracts; +using ArcGIS.Desktop.Framework.Dialogs; +using ArcGIS.Desktop.Framework.Threading.Tasks; +using ArcGIS.Desktop.KnowledgeGraph; +using ArcGIS.Desktop.Layouts; +using ArcGIS.Desktop.Mapping; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LinkToolAddin.ui.dockpane +{ + internal class TestDockpaneViewModel : DockPane + { + private const string _dockPaneID = "LinkToolAddin_ui_dockpane_TestDockpane"; + + protected TestDockpaneViewModel() { } + + /// + /// Show the DockPane. + /// + internal static void Show() + { + DockPane pane = FrameworkApplication.DockPaneManager.Find(_dockPaneID); + if (pane == null) + return; + + pane.Activate(); + } + + /// + /// Text shown near the top of the DockPane. + /// + private string _heading = "My DockPane"; + public string Heading + { + get => _heading; + set => SetProperty(ref _heading, value); + } + } + + /// + /// Button implementation to show the DockPane. + /// + internal class TestDockpane_ShowButton : Button + { + protected override void OnClick() + { + TestDockpaneViewModel.Show(); + } + } +} diff --git a/ui/message/ChatMessageItem.cs b/ui/message/ChatMessageItem.cs new file mode 100644 index 0000000..2c35847 --- /dev/null +++ b/ui/message/ChatMessageItem.cs @@ -0,0 +1,9 @@ +namespace LinkToolAddin.message; + +public class ChatMessageItem : MessageListItem +{ + public string id { get; set; } + public string role { get; set; } + public string content { get; set; } + public MessageType type { get; set; } +} \ No newline at end of file diff --git a/ui/message/MessageListItem.cs b/ui/message/MessageListItem.cs index 0de3b34..1c58cbd 100644 --- a/ui/message/MessageListItem.cs +++ b/ui/message/MessageListItem.cs @@ -1,7 +1,15 @@ namespace LinkToolAddin.message; +public enum MessageType +{ + TOOL_MESSAGE, + CHAT_MESSAGE, +} + public interface MessageListItem { + string id { get; set; } string role { get; set; } string content { get; set; } + MessageType type { get; set; } } \ No newline at end of file diff --git a/ui/message/ToolMessageItem.cs b/ui/message/ToolMessageItem.cs new file mode 100644 index 0000000..211a4db --- /dev/null +++ b/ui/message/ToolMessageItem.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; + +namespace LinkToolAddin.message; + +public class ToolMessageItem : MessageListItem +{ + public string id { get; set; } + public string role { get; set; } + public string content { get; set; } + public string toolName { get; set; } + public Dictionary toolParams { get; set; } + public MessageType type { get; set; } + public string status { get; set; } + public string result { get; set; } +} \ No newline at end of file