From 5107fc2f1da7b2fbb42f50035aae19535ac336ff Mon Sep 17 00:00:00 2001 From: PeterZhong Date: Wed, 14 May 2025 00:54:06 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8E=A5=E5=85=A5=E9=AB=98=E5=BE=B7MCP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LinkToolAddin.csproj | 4 + client/CallArcGISPro.cs | 18 +++ client/PythonMcpClient.cs | 6 + client/SseMcpClient.cs | 56 +++++++++ common/HttpRequest.cs | 21 ++++ host/CallMcp.cs | 28 +++++ host/llm/Bailian.cs | 45 +++++++ host/llm/Llm.cs | 4 + host/llm/entity/ApplicationOutput.cs | 51 ++++++++ host/llm/entity/CommonInput.cs | 31 +++++ host/llm/entity/KnowldgeResult.cs | 42 +++++++ host/llm/entity/LlmChat.cs | 69 +++++++++++ host/llm/entity/LlmJsonContent.cs | 38 ++++++ resource/DocDb.cs | 54 +++++++++ resource/GpToolDb.cs | 9 ++ resource/PromptDb.cs | 8 ++ server/CallArcGISPro.cs | 23 ++++ server/JsonRpcEntity.cs | 25 ++++ server/JsonRpcErrorEntity.cs | 25 ++++ server/JsonRpcResultEntity.cs | 15 +++ server/JsonRpcSuccessEntity.cs | 16 +++ ui/dockpane/DialogDockpane.xaml | 9 +- ui/dockpane/DialogDockpane.xaml.cs | 162 +++++++++++++++---------- ui/dockpane/DialogDockpaneViewModel.cs | 5 + 24 files changed, 693 insertions(+), 71 deletions(-) create mode 100644 client/CallArcGISPro.cs create mode 100644 client/PythonMcpClient.cs create mode 100644 client/SseMcpClient.cs create mode 100644 common/HttpRequest.cs create mode 100644 host/CallMcp.cs create mode 100644 host/llm/Bailian.cs create mode 100644 host/llm/entity/ApplicationOutput.cs create mode 100644 host/llm/entity/CommonInput.cs create mode 100644 host/llm/entity/KnowldgeResult.cs create mode 100644 host/llm/entity/LlmChat.cs create mode 100644 host/llm/entity/LlmJsonContent.cs create mode 100644 resource/DocDb.cs create mode 100644 resource/GpToolDb.cs create mode 100644 resource/PromptDb.cs create mode 100644 server/CallArcGISPro.cs create mode 100644 server/JsonRpcEntity.cs create mode 100644 server/JsonRpcErrorEntity.cs create mode 100644 server/JsonRpcResultEntity.cs create mode 100644 server/JsonRpcSuccessEntity.cs diff --git a/LinkToolAddin.csproj b/LinkToolAddin.csproj index d730a4a..6bd5b78 100644 --- a/LinkToolAddin.csproj +++ b/LinkToolAddin.csproj @@ -104,6 +104,10 @@ + + + + diff --git a/client/CallArcGISPro.cs b/client/CallArcGISPro.cs new file mode 100644 index 0000000..a3c00e4 --- /dev/null +++ b/client/CallArcGISPro.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using LinkToolAddin.server; +using Newtonsoft.Json; + +namespace LinkToolAddin.client; + +public class CallArcGISPro +{ + public async static Task CallArcGISProTool(Dictionary parameters) + { + // Call the ArcGIS Pro method and get the result + var result = await server.CallArcGISPro.CallArcGISProTool(parameters["toolName"], JsonConvert.DeserializeObject>(parameters["toolParams"])); + + // Serialize the result back to a JSON string + return JsonConvert.SerializeObject(result); + } +} \ No newline at end of file diff --git a/client/PythonMcpClient.cs b/client/PythonMcpClient.cs new file mode 100644 index 0000000..e25e7d8 --- /dev/null +++ b/client/PythonMcpClient.cs @@ -0,0 +1,6 @@ +namespace LinkToolAddin.client; + +public class PythonMcpClient +{ + +} \ No newline at end of file diff --git a/client/SseMcpClient.cs b/client/SseMcpClient.cs new file mode 100644 index 0000000..471af60 --- /dev/null +++ b/client/SseMcpClient.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using ModelContextProtocol.Client; +using ModelContextProtocol.Protocol.Transport; +using Newtonsoft.Json; + +namespace LinkToolAddin.client; + +public class SseMcpClient +{ + public static async Task testGaodeMcp() + { + Console.WriteLine("Connecting to 高德 MCP Server via SSE..."); + + // 创建 MCP Server 配置 + SseClientTransportOptions options = new SseClientTransportOptions + { + Endpoint = new Uri("https://mcp.amap.com/sse?key=ed418512c94ade8f83d42c37b77d2bb2"), + }; + + IClientTransport transport = new SseClientTransport(options);; + + // 创建 MCP Client + var client = await McpClientFactory.CreateAsync(transport); + Console.WriteLine("Connected to 高德 MCP Server"); + + try + { + // 获取可用工具列表 + var tools = await client.ListToolsAsync(); + Console.WriteLine("\nAvailable Tools:"); + foreach (var tool in tools) + { + Console.WriteLine($"- {tool.Name}: {tool.Description}"); + } + + // 示例调用:获取当前定位 + var result = await client.CallToolAsync("amap.maps_weather", new Dictionary{{"city","北京"}}); + Console.WriteLine("\n[amap.get_location] Result:"); + Console.WriteLine(result); + return JsonConvert.SerializeObject(result); + } + catch (Exception ex) + { + Console.WriteLine($"Error occurred: {ex.Message}"); + } + finally + { + await client.DisposeAsync(); + } + + Console.WriteLine("Client closed."); + return "failed"; + } +} \ No newline at end of file diff --git a/common/HttpRequest.cs b/common/HttpRequest.cs new file mode 100644 index 0000000..a38807c --- /dev/null +++ b/common/HttpRequest.cs @@ -0,0 +1,21 @@ +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; +using System.Threading.Tasks; +using LinkToolAddin.host.llm.entity; +using Newtonsoft.Json; + +namespace LinkToolAddin.common; + +public class HttpRequest +{ + public static async Task SendPostRequestAsync(string url, string jsonContent, string apiKey) + { + using var httpClient = new HttpClient(); + httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey); + var response = await httpClient.PostAsync(url, new StringContent(jsonContent, Encoding.UTF8, "application/json")); + response.EnsureSuccessStatusCode(); + var responseBody = await response.Content.ReadAsStringAsync(); + return responseBody; + } +} \ No newline at end of file diff --git a/host/CallMcp.cs b/host/CallMcp.cs new file mode 100644 index 0000000..a98488d --- /dev/null +++ b/host/CallMcp.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using LinkToolAddin.server; +using log4net; +using Newtonsoft.Json; + +namespace LinkToolAddin.host +{ + public class CallMcp + { + private static readonly ILog log = LogManager.GetLogger(typeof(CallMcp)); + public static async Task CallInnerMcpTool(string jsonRpcString) + { + log.Info("通过反射调用内部MCP工具"); + var jsonRpcEntity = JsonConvert.DeserializeObject(jsonRpcString); + + Type type = Type.GetType("LinkToolAddin.client."+jsonRpcEntity.Method.Split('.')[0]); + MethodInfo method = type.GetMethod(jsonRpcEntity.Method.Split('.')[1],BindingFlags.Public | BindingFlags.Static); + var task = method.Invoke(null, new object[] { jsonRpcEntity.Params }) as Task; + JsonRpcResultEntity result = await task; + return JsonConvert.SerializeObject(result); + } + } +} \ No newline at end of file diff --git a/host/llm/Bailian.cs b/host/llm/Bailian.cs new file mode 100644 index 0000000..bd444c7 --- /dev/null +++ b/host/llm/Bailian.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; +using System.Threading.Tasks; +using LinkToolAddin.common; +using LinkToolAddin.host.llm.entity; +using Newtonsoft.Json; + +namespace LinkToolAddin.host.llm; + +public class Bailian : Llm +{ + public string model { get; set; } = "qwen-max"; + public string temperature { get; set; } + public string top_p { get; set; } + public string max_tokens { get; set; } + public string app_id { get; set; } + public string api_key { get; set; } + public IAsyncEnumerable SendChatStreamAsync(string message) + { + throw new System.NotImplementedException(); + } + + public IAsyncEnumerable SendApplicationStreamAsync(string message) + { + throw new System.NotImplementedException(); + } + + public async Task SendChatAsync(LlmJsonContent jsonContent) + { + string url = "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions"; + string responseBody = await HttpRequest.SendPostRequestAsync(url, JsonConvert.SerializeObject(jsonContent), api_key); + LlmChat result = JsonConvert.DeserializeObject(responseBody); + return result.Choices[0].Message.Content; + } + + public async Task SendApplicationAsync(CommonInput commonInput) + { + string url = $"https://dashscope.aliyuncs.com/api/v1/apps/{app_id}/completion"; + string responseBody = await HttpRequest.SendPostRequestAsync(url, JsonConvert.SerializeObject(commonInput), api_key); + ApplicationOutput result = JsonConvert.DeserializeObject(responseBody); + return responseBody; + } +} \ No newline at end of file diff --git a/host/llm/Llm.cs b/host/llm/Llm.cs index 95e11c4..62a11f4 100644 --- a/host/llm/Llm.cs +++ b/host/llm/Llm.cs @@ -1,4 +1,6 @@ using System.Collections.Generic; +using System.Threading.Tasks; +using LinkToolAddin.host.llm.entity; namespace LinkToolAddin.host.llm; @@ -11,4 +13,6 @@ public interface Llm public IAsyncEnumerable SendChatStreamAsync(string message); public IAsyncEnumerable SendApplicationStreamAsync(string message); + public Task SendChatAsync(LlmJsonContent jsonContent); + public Task SendApplicationAsync(CommonInput commonInput); } \ No newline at end of file diff --git a/host/llm/entity/ApplicationOutput.cs b/host/llm/entity/ApplicationOutput.cs new file mode 100644 index 0000000..94405fa --- /dev/null +++ b/host/llm/entity/ApplicationOutput.cs @@ -0,0 +1,51 @@ +namespace LinkToolAddin.host.llm.entity +{ + using System; + using System.Collections.Generic; + + using System.Globalization; + using Newtonsoft.Json; + using Newtonsoft.Json.Converters; + + public partial class ApplicationOutput + { + [JsonProperty("output")] + public Output Output { get; set; } + + [JsonProperty("usage")] + public Usage Usage { get; set; } + + [JsonProperty("request_id")] + public Guid RequestId { get; set; } + } + + public partial class Output + { + [JsonProperty("finish_reason")] + public string FinishReason { get; set; } + + [JsonProperty("session_id")] + public string SessionId { get; set; } + + [JsonProperty("text")] + public string Text { get; set; } + } + + public partial class Usage + { + [JsonProperty("models")] + public List Models { get; set; } + } + + public partial class Model + { + [JsonProperty("output_tokens")] + public long OutputTokens { get; set; } + + [JsonProperty("model_id")] + public string ModelId { get; set; } + + [JsonProperty("input_tokens")] + public long InputTokens { get; set; } + } +} \ No newline at end of file diff --git a/host/llm/entity/CommonInput.cs b/host/llm/entity/CommonInput.cs new file mode 100644 index 0000000..6d1da54 --- /dev/null +++ b/host/llm/entity/CommonInput.cs @@ -0,0 +1,31 @@ +namespace LinkToolAddin.host.llm.entity +{ + using System; + using System.Collections.Generic; + + using System.Globalization; + using Newtonsoft.Json; + using Newtonsoft.Json.Converters; + + public partial class CommonInput + { + [JsonProperty("input")] + public Input Input { get; set; } + + [JsonProperty("parameters")] + public Debug Parameters { get; set; } + + [JsonProperty("debug")] + public Debug Debug { get; set; } + } + + public partial class Debug + { + } + + public partial class Input + { + [JsonProperty("prompt")] + public string Prompt { get; set; } + } +} \ No newline at end of file diff --git a/host/llm/entity/KnowldgeResult.cs b/host/llm/entity/KnowldgeResult.cs new file mode 100644 index 0000000..0937e30 --- /dev/null +++ b/host/llm/entity/KnowldgeResult.cs @@ -0,0 +1,42 @@ +namespace LinkToolAddin.host.llm.entity +{ + using System; + using System.Collections.Generic; + + using System.Globalization; + using Newtonsoft.Json; + using Newtonsoft.Json.Converters; + + public partial class KnowledgeResult + { + [JsonProperty("rewriteQuery")] + public string RewriteQuery { get; set; } + + [JsonProperty("chunkList")] + public List ChunkList { get; set; } + } + + public partial class ChunkList + { + [JsonProperty("score")] + public double Score { get; set; } + + [JsonProperty("imagesUrl")] + public List ImagesUrl { get; set; } + + [JsonProperty("documentName")] + public string DocumentName { get; set; } + + [JsonProperty("titcontent", NullValueHandling = NullValueHandling.Ignore)] + public string Titcontent { get; set; } + + [JsonProperty("title", NullValueHandling = NullValueHandling.Ignore)] + public string Title { get; set; } + + [JsonProperty("content", NullValueHandling = NullValueHandling.Ignore)] + public string Content { get; set; } + + [JsonProperty("conten_score_with_weight", NullValueHandling = NullValueHandling.Ignore)] + public string ContenScoreWithWeight { get; set; } + } +} diff --git a/host/llm/entity/LlmChat.cs b/host/llm/entity/LlmChat.cs new file mode 100644 index 0000000..d354865 --- /dev/null +++ b/host/llm/entity/LlmChat.cs @@ -0,0 +1,69 @@ +namespace LinkToolAddin.host.llm.entity +{ + using System; + using System.Collections.Generic; + + using System.Globalization; + using Newtonsoft.Json; + using Newtonsoft.Json.Converters; + + public partial class LlmChat + { + [JsonProperty("choices")] + public List Choices { get; set; } + + [JsonProperty("object")] + public string Object { get; set; } + + [JsonProperty("usage")] + public Usage Usage { get; set; } + + [JsonProperty("created")] + public long Created { get; set; } + + [JsonProperty("system_fingerprint")] + public object SystemFingerprint { get; set; } + + [JsonProperty("model")] + public string Model { get; set; } + + [JsonProperty("id")] + public string Id { get; set; } + } + + public partial class Choice + { + [JsonProperty("message")] + public Message Message { get; set; } + + [JsonProperty("finish_reason")] + public string FinishReason { get; set; } + + [JsonProperty("index")] + public long Index { get; set; } + + [JsonProperty("logprobs")] + public object Logprobs { get; set; } + } + + public partial class Usage + { + [JsonProperty("prompt_tokens")] + public long PromptTokens { get; set; } + + [JsonProperty("completion_tokens")] + public long CompletionTokens { get; set; } + + [JsonProperty("total_tokens")] + public long TotalTokens { get; set; } + + [JsonProperty("prompt_tokens_details")] + public PromptTokensDetails PromptTokensDetails { get; set; } + } + + public partial class PromptTokensDetails + { + [JsonProperty("cached_tokens")] + public long CachedTokens { get; set; } + } +} \ No newline at end of file diff --git a/host/llm/entity/LlmJsonContent.cs b/host/llm/entity/LlmJsonContent.cs new file mode 100644 index 0000000..5b53edf --- /dev/null +++ b/host/llm/entity/LlmJsonContent.cs @@ -0,0 +1,38 @@ +namespace LinkToolAddin.host.llm.entity +{ + using System.Collections.Generic; + using Newtonsoft.Json; + + public partial class LlmJsonContent + { + [JsonProperty("model")] + public string Model { get; set; } + + [JsonProperty("messages")] + public List Messages { get; set; } + + [JsonProperty("stream")] + public bool Stream { get; set; } = false; + + [JsonProperty("temperature")] + public double Temperature { get; set; } = 0.7; + + [JsonProperty("top_p")] + public double TopP { get; set; } = 1.0; + + [JsonProperty("max_tokens")] + public int MaxTokens { get; set; } = 2048; + + [JsonProperty("top_k")] + public int TopK { get; set; } = 40; + } + + public partial class Message + { + [JsonProperty("role")] + public string Role { get; set; } + + [JsonProperty("content")] + public string Content { get; set; } + } +} \ No newline at end of file diff --git a/resource/DocDb.cs b/resource/DocDb.cs new file mode 100644 index 0000000..1487b5e --- /dev/null +++ b/resource/DocDb.cs @@ -0,0 +1,54 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using LinkToolAddin.host.llm; +using LinkToolAddin.host.llm.entity; +using Newtonsoft.Json; + +namespace LinkToolAddin.resource; + +public class DocDb +{ + public string appId {get;set;} + public string apiKey {get;set;} + + public DocDb(string apiKey,KnowledgeBase knowledgeBaseEnum) + { + this.apiKey = apiKey; + appId = knowledgeBase[knowledgeBaseEnum]; + } + + public enum KnowledgeBase + { + ArcGISProHelpDoc, + ArcGISProToolDoc, + TaskPlanningDoc, + ArcGISProApplicantExample + } + + public Dictionary knowledgeBase = new Dictionary + { + {KnowledgeBase.ArcGISProHelpDoc,"6a77c5a68de64f469b79fcdcde9d5001"} + }; + + public async Task Retrieve(string query) + { + Llm bailian = new Bailian + { + api_key = apiKey, + app_id = appId, + }; + var commonInput = new CommonInput + { + Input = new Input + { + Prompt = query + }, + Parameters = new Debug(), + Debug = new Debug() + }; + string responseBody = await bailian.SendApplicationAsync(commonInput); + ApplicationOutput result = JsonConvert.DeserializeObject(responseBody); + KnowledgeResult knowledgeResult = JsonConvert.DeserializeObject(result.Output.Text); + return knowledgeResult; + } +} \ No newline at end of file diff --git a/resource/GpToolDb.cs b/resource/GpToolDb.cs new file mode 100644 index 0000000..3706c8d --- /dev/null +++ b/resource/GpToolDb.cs @@ -0,0 +1,9 @@ +namespace LinkToolAddin.resource; + +public class GpToolDb +{ + public string toolName { get; set; } + public string toolDescription { get; set; } + public string exeName { get; set; } + public string toolParma { get; set; } +} \ No newline at end of file diff --git a/resource/PromptDb.cs b/resource/PromptDb.cs new file mode 100644 index 0000000..6b6e6d3 --- /dev/null +++ b/resource/PromptDb.cs @@ -0,0 +1,8 @@ +namespace LinkToolAddin.resource; + +public class PromptDb +{ + public string promptName { get; set; } + public string promptDescription { get; set; } + public string promptContent { get; set; } +} \ No newline at end of file diff --git a/server/CallArcGISPro.cs b/server/CallArcGISPro.cs new file mode 100644 index 0000000..39f5ef0 --- /dev/null +++ b/server/CallArcGISPro.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using ArcGIS.Desktop.Core.Geoprocessing; +using ArcGIS.Desktop.Framework.Dialogs; +using ArcGIS.Desktop.Framework.Threading.Tasks; + +namespace LinkToolAddin.server; + +public class CallArcGISPro +{ + private static readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(CallArcGISPro)); + public async static Task CallArcGISProTool(string toolName, List toolParams) + { + var results = await Geoprocessing.ExecuteToolAsync(toolName, toolParams); + log.Info($"CallArcGISProTool: {toolName} | {toolParams}"); + return new JsonRpcSuccessEntity() + { + Id = 1, + Result = results.ToString() + }; + } +} \ No newline at end of file diff --git a/server/JsonRpcEntity.cs b/server/JsonRpcEntity.cs new file mode 100644 index 0000000..01a91e3 --- /dev/null +++ b/server/JsonRpcEntity.cs @@ -0,0 +1,25 @@ +using System.Text.Json.Serialization; +using Newtonsoft.Json; + +namespace LinkToolAddin.server +{ + using System; + using System.Collections.Generic; + + using System.Globalization; + + public partial class JsonRpcEntity + { + [JsonProperty("jsonrpc")] + public string Jsonrpc { get; set; } + + [JsonProperty("method")] + public string Method { get; set; } + + [JsonProperty("params")] + public Dictionary Params { get; set; } + + [JsonProperty("id")] + public long Id { get; set; } + } +} \ No newline at end of file diff --git a/server/JsonRpcErrorEntity.cs b/server/JsonRpcErrorEntity.cs new file mode 100644 index 0000000..46381de --- /dev/null +++ b/server/JsonRpcErrorEntity.cs @@ -0,0 +1,25 @@ +namespace LinkToolAddin.server +{ + using Newtonsoft.Json; + + public partial class JsonRpcErrorEntity + { + [JsonProperty("jsonrpc")] + public string Jsonrpc { get; set; } + + [JsonProperty("error")] + public Error Error { get; set; } + + [JsonProperty("id")] + public long Id { get; set; } + } + + public partial class Error + { + [JsonProperty("code")] + public long Code { get; set; } + + [JsonProperty("message")] + public string Message { get; set; } + } +} \ No newline at end of file diff --git a/server/JsonRpcResultEntity.cs b/server/JsonRpcResultEntity.cs new file mode 100644 index 0000000..5d80803 --- /dev/null +++ b/server/JsonRpcResultEntity.cs @@ -0,0 +1,15 @@ +using Newtonsoft.Json; + +namespace LinkToolAddin.server +{ + using Newtonsoft.Json; + + public partial class JsonRpcResultEntity + { + [JsonProperty("jsonrpc")] + public string Jsonrpc { get; set; } + + [JsonProperty("id")] + public long Id { get; set; } + } +} \ No newline at end of file diff --git a/server/JsonRpcSuccessEntity.cs b/server/JsonRpcSuccessEntity.cs new file mode 100644 index 0000000..a37985f --- /dev/null +++ b/server/JsonRpcSuccessEntity.cs @@ -0,0 +1,16 @@ +namespace LinkToolAddin.server +{ + using Newtonsoft.Json; + + public partial class JsonRpcSuccessEntity : JsonRpcResultEntity + { + [JsonProperty("jsonrpc")] + public string Jsonrpc { get; set; } + + [JsonProperty("result")] + public string Result { get; set; } + + [JsonProperty("id")] + public long Id { get; set; } + } +} \ No newline at end of file diff --git a/ui/dockpane/DialogDockpane.xaml b/ui/dockpane/DialogDockpane.xaml index 3b8967b..84e7de1 100644 --- a/ui/dockpane/DialogDockpane.xaml +++ b/ui/dockpane/DialogDockpane.xaml @@ -22,14 +22,7 @@ - - - - - - - - + \ No newline at end of file diff --git a/ui/dockpane/DialogDockpane.xaml.cs b/ui/dockpane/DialogDockpane.xaml.cs index 0a6ce23..a939189 100644 --- a/ui/dockpane/DialogDockpane.xaml.cs +++ b/ui/dockpane/DialogDockpane.xaml.cs @@ -1,9 +1,27 @@ -using System; +using System; using System.Collections.Generic; -using System.Text.Json; +using System.ComponentModel; +using System.IO; +using System.Net.Http; +using System.Net.Http.Headers; using System.Windows; using System.Windows.Controls; - +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using System.Text.Json; +using System.Threading; +using ArcGIS.Desktop.Core.Geoprocessing; +using LinkToolAddin.client; +using LinkToolAddin.host.llm; +using LinkToolAddin.host.llm.entity; +using LinkToolAddin.resource; +using log4net; +using log4net.Appender; +using log4net.Config; +using log4net.Layout; +using ModelContextProtocol.Server; +using Newtonsoft.Json; namespace LinkToolAddin.ui.dockpane { @@ -12,76 +30,94 @@ namespace LinkToolAddin.ui.dockpane /// public partial class DialogDockpaneView : UserControl { + private static ILog log = LogManager.GetLogger(typeof(DialogDockpaneView)); + public DialogDockpaneView() { + InitLogger(); InitializeComponent(); } - - private void TestButton_OnClick(object sender, RoutedEventArgs e) + + public void CallBack(string str,object obj) { - string originalJson = @"{ - ""name"": ""Alice"", - ""age"": 30, - ""isStudent"": false, - ""hobbies"": [ - ""reading"", - ""swimming"", - ""hiking"" - ], - ""address"": { - ""street"": ""123 Main St"", - ""city"": ""Anytown"", - ""postalCode"": ""12345"" - } -}"; + log.Info($"CallBack {str}"); + } - try + private async void TestServer_OnClick(object sender, RoutedEventArgs e) + { + log.Info("TestServer Clicked"); + string res = await SseMcpClient.testGaodeMcp(); + log.Info(res); + } + + 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 { - // 反序列化 JSON 到对象 - Person? person = JsonSerializer.Deserialize(originalJson); - - if (person != null) + api_key = "sk-db177155677e438f832860e7f4da6afc", + app_id = "6a77c5a68de64f469b79fcdcde9d5001", + }; + string reponse = await bailian.SendChatAsync(new LlmJsonContent() + { + Model = "qwen-max", + Messages = new List() { - // 序列化对象回 JSON 字符串 - string serializedJson = JsonSerializer.Serialize(person, new JsonSerializerOptions + new Message() { - WriteIndented = true // 格式化输出 - }); + Role = "user", + Content = "你是谁" + } + }, + Temperature = 0.7, + TopP = 1, + MaxTokens = 1000, + }); + log.Info(reponse); + } + + 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(); // 激活配置 - Console.WriteLine("序列化后的 JSON:"); - Console.WriteLine(serializedJson); - ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show(serializedJson); - } - else - { - Console.WriteLine("反序列化失败,对象为 null。"); - } - } - catch (JsonException ex) + // 2. 创建文件滚动输出器(按大小滚动) + var fileAppender = new RollingFileAppender { - Console.WriteLine($"JSON 处理错误: {ex.Message}"); - } - catch (Exception ex) - { - Console.WriteLine($"发生错误: {ex.Message}"); - } + File = 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 class Person - { - public string? Name { get; set; } - public int Age { get; set; } - public bool IsStudent { get; set; } - public List? Hobbies { get; set; } - public Address? Address { get; set; } - } - - public class Address - { - public string? Street { get; set; } - public string? City { get; set; } - public string? PostalCode { get; set; } - } -} \ No newline at end of file +} diff --git a/ui/dockpane/DialogDockpaneViewModel.cs b/ui/dockpane/DialogDockpaneViewModel.cs index 5871201..1d7a4e5 100644 --- a/ui/dockpane/DialogDockpaneViewModel.cs +++ b/ui/dockpane/DialogDockpaneViewModel.cs @@ -17,6 +17,10 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Console; namespace LinkToolAddin.ui.dockpane { @@ -56,6 +60,7 @@ namespace LinkToolAddin.ui.dockpane { protected override void OnClick() { + DialogDockpaneViewModel.Show(); } }