完成工作流控制面,预留前端接入
This commit is contained in:
parent
792c458f6c
commit
a3cfcb90e3
13
Config.daml
13
Config.daml
@ -23,9 +23,10 @@
|
|||||||
<!-- comment this out if you have no controls on the Addin tab to avoid
|
<!-- comment this out if you have no controls on the Addin tab to avoid
|
||||||
an empty group-->
|
an empty group-->
|
||||||
<group id="CoreGroup" caption="核心功能" appearsOnAddInTab="false">
|
<group id="CoreGroup" caption="核心功能" appearsOnAddInTab="false">
|
||||||
<button refID="DialogDockpane_ShowButton" size="large" />
|
<button refID="DialogDockpane_ShowButton" size="large" />
|
||||||
<button refID="Version_Button" size="large" />
|
<button refID="Version_Button" size="large" />
|
||||||
</group>
|
<button refID="LinkToolAddin_ui_dockpane_TestDockpane_ShowButton" size="large" />
|
||||||
|
</group>
|
||||||
<group id="PreferenceGroup" caption="设置项" appearsOnAddInTab="false">
|
<group id="PreferenceGroup" caption="设置项" appearsOnAddInTab="false">
|
||||||
<button refID="Preference_Button" size="large" />
|
<button refID="Preference_Button" size="large" />
|
||||||
</group>
|
</group>
|
||||||
@ -40,11 +41,17 @@
|
|||||||
<button id="DialogDockpane_ShowButton" caption="对话面板" className="LinkToolAddin.ui.dockpane.DialogDockpane_ShowButton" loadOnClick="true" smallImage="GenericButtonPurple16" largeImage="GenericButtonPurple32">
|
<button id="DialogDockpane_ShowButton" caption="对话面板" className="LinkToolAddin.ui.dockpane.DialogDockpane_ShowButton" loadOnClick="true" smallImage="GenericButtonPurple16" largeImage="GenericButtonPurple32">
|
||||||
<tooltip heading="对话面板">打开AI对话面板<disabledText /></tooltip>
|
<tooltip heading="对话面板">打开AI对话面板<disabledText /></tooltip>
|
||||||
</button>
|
</button>
|
||||||
|
<button id="LinkToolAddin_ui_dockpane_TestDockpane_ShowButton" caption="测试面板" className="LinkToolAddin.ui.dockpane.TestDockpane_ShowButton" loadOnClick="true" smallImage="GenericButtonPurple16" largeImage="GenericButtonPurple32">
|
||||||
|
<tooltip heading="测试面板">打开测试面板<disabledText /></tooltip>
|
||||||
|
</button>
|
||||||
</controls>
|
</controls>
|
||||||
<dockPanes>
|
<dockPanes>
|
||||||
<dockPane id="DialogDockpane" caption="LinkTool" className="LinkToolAddin.ui.dockpane.DialogDockpaneViewModel" dock="group" dockWith="esri_core_projectDockPane">
|
<dockPane id="DialogDockpane" caption="LinkTool" className="LinkToolAddin.ui.dockpane.DialogDockpaneViewModel" dock="group" dockWith="esri_core_projectDockPane">
|
||||||
<content className="LinkToolAddin.ui.dockpane.DialogDockpaneView" />
|
<content className="LinkToolAddin.ui.dockpane.DialogDockpaneView" />
|
||||||
</dockPane>
|
</dockPane>
|
||||||
|
<dockPane id="LinkToolAddin_ui_dockpane_TestDockpane" caption="TestDockpane" className="LinkToolAddin.ui.dockpane.TestDockpaneViewModel" dock="group" dockWith="esri_core_projectDockPane">
|
||||||
|
<content className="LinkToolAddin.ui.dockpane.TestDockpaneView" />
|
||||||
|
</dockPane>
|
||||||
</dockPanes>
|
</dockPanes>
|
||||||
</insertModule>
|
</insertModule>
|
||||||
</modules>
|
</modules>
|
||||||
|
|||||||
@ -99,7 +99,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="resource\" />
|
<Folder Include="resource\" />
|
||||||
<Folder Include="server\" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Esri.ArcGISPro.Extensions30" Version="3.4.1.55405" />
|
<PackageReference Include="Esri.ArcGISPro.Extensions30" Version="3.4.1.55405" />
|
||||||
|
|||||||
@ -2,7 +2,11 @@
|
|||||||
"profiles": {
|
"profiles": {
|
||||||
"LinkToolAddin": {
|
"LinkToolAddin": {
|
||||||
"commandName": "Executable",
|
"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"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
18
client/prompt/DynamicPrompt.cs
Normal file
18
client/prompt/DynamicPrompt.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace LinkToolAddin.client.prompt;
|
||||||
|
|
||||||
|
public class DynamicPrompt
|
||||||
|
{
|
||||||
|
public static string GetPrompt(string name,Dictionary<string,object> args)
|
||||||
|
{
|
||||||
|
PromptTemplates promptTemplate = new PromptTemplates();
|
||||||
|
string template = promptTemplate.GetPrompt(name);
|
||||||
|
foreach (KeyValuePair<string,object> pair in args)
|
||||||
|
{
|
||||||
|
string replaceKey = "{{"+pair.Key+"}}";
|
||||||
|
template.Replace(replaceKey, pair.Value.ToString());
|
||||||
|
}
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
}
|
||||||
20
client/prompt/PromptTemplates.cs
Normal file
20
client/prompt/PromptTemplates.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace LinkToolAddin.client.prompt;
|
||||||
|
|
||||||
|
public class PromptTemplates
|
||||||
|
{
|
||||||
|
private Dictionary<string, string> prompts = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
public PromptTemplates()
|
||||||
|
{
|
||||||
|
prompts.Add("plan", "请根据用户所提问题进行工具规划");
|
||||||
|
prompts.Add("param", "根据帮助文档填写工具参数");
|
||||||
|
prompts.Add("code", "现在需要生成代码,要求语法正确");
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetPrompt(string name)
|
||||||
|
{
|
||||||
|
return prompts[name];
|
||||||
|
}
|
||||||
|
}
|
||||||
146
host/Gateway.cs
Normal file
146
host/Gateway.cs
Normal file
@ -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<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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
6
host/ToolRequest.cs
Normal file
6
host/ToolRequest.cs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
namespace LinkToolAddin.host;
|
||||||
|
|
||||||
|
public class ToolRequest
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
24
host/mcp/McpServer.cs
Normal file
24
host/mcp/McpServer.cs
Normal file
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
30
host/mcp/SseMcpServer.cs
Normal file
30
host/mcp/SseMcpServer.cs
Normal file
@ -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<string,string> Headers { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
30
host/mcp/StdioMcpServer.cs
Normal file
30
host/mcp/StdioMcpServer.cs
Normal file
@ -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<string> Args { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
11
host/prompt/SystemPrompt.cs
Normal file
11
host/prompt/SystemPrompt.cs
Normal file
@ -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 = "执行上一个工具的时候出现以下错误,请根据报错信息重试";
|
||||||
|
|
||||||
|
}
|
||||||
6
host/prompt/UserPrompt.cs
Normal file
6
host/prompt/UserPrompt.cs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
namespace LinkToolAddin.host.prompt;
|
||||||
|
|
||||||
|
public class UserPrompt
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
37
server/ArcGISProMcpServer.cs
Normal file
37
server/ArcGISProMcpServer.cs
Normal file
@ -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}";
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -17,6 +17,7 @@ using LinkToolAddin.client;
|
|||||||
using LinkToolAddin.host.llm;
|
using LinkToolAddin.host.llm;
|
||||||
using LinkToolAddin.host.llm.entity;
|
using LinkToolAddin.host.llm.entity;
|
||||||
using LinkToolAddin.resource;
|
using LinkToolAddin.resource;
|
||||||
|
using LinkToolAddin.server;
|
||||||
using log4net;
|
using log4net;
|
||||||
using log4net.Appender;
|
using log4net.Appender;
|
||||||
using log4net.Config;
|
using log4net.Config;
|
||||||
@ -40,72 +41,10 @@ namespace LinkToolAddin.ui.dockpane
|
|||||||
InitLogger();
|
InitLogger();
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CallBack(string str,object obj)
|
|
||||||
{
|
|
||||||
log.Info($"CallBack {str}");
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void TestServer_OnClick(object sender, RoutedEventArgs e)
|
private async void TestServer_OnClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
log.Info("TestServer Clicked");
|
log.Info("TestServer Clicked");
|
||||||
List<string> args = new List<string>();
|
|
||||||
args.Add("mcp-server-time");
|
|
||||||
args.Add("--local-timezone=America/New_York");
|
|
||||||
McpClient stdioMcpClient = new StdioMcpClient("uvx",args);
|
|
||||||
IList<McpClientTool> tools = await stdioMcpClient.GetToolListAsync();
|
|
||||||
foreach (McpClientTool tool in tools)
|
|
||||||
{
|
|
||||||
log.Info(tool.JsonSchema.ToString());
|
|
||||||
}
|
|
||||||
CallToolResponse response = await stdioMcpClient.CallToolAsync("get_current_time",
|
|
||||||
new Dictionary<string, object> { { "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<McpClientTool> 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<Message>()
|
|
||||||
{
|
|
||||||
new Message()
|
|
||||||
{
|
|
||||||
Role = "user",
|
|
||||||
Content = "你是谁"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Temperature = 0.7,
|
|
||||||
TopP = 1,
|
|
||||||
MaxTokens = 1000,
|
|
||||||
});
|
|
||||||
log.Info(reponse);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void InitLogger()
|
protected void InitLogger()
|
||||||
@ -121,7 +60,7 @@ namespace LinkToolAddin.ui.dockpane
|
|||||||
// 2. 创建文件滚动输出器(按大小滚动)
|
// 2. 创建文件滚动输出器(按大小滚动)
|
||||||
var fileAppender = new RollingFileAppender
|
var fileAppender = new RollingFileAppender
|
||||||
{
|
{
|
||||||
File = Path.Combine("Logs", "linktool_app.log"), // 日志文件路径
|
File = Path.Combine("Logs", "D:\\linktool_app.log"), // 日志文件路径
|
||||||
AppendToFile = true, // 追加模式
|
AppendToFile = true, // 追加模式
|
||||||
RollingStyle = RollingFileAppender.RollingMode.Size, // 按文件大小滚动
|
RollingStyle = RollingFileAppender.RollingMode.Size, // 按文件大小滚动
|
||||||
MaxSizeRollBackups = 10, // 保留 10 个历史文件
|
MaxSizeRollBackups = 10, // 保留 10 个历史文件
|
||||||
|
|||||||
28
ui/dockpane/TestDockpane.xaml
Normal file
28
ui/dockpane/TestDockpane.xaml
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<UserControl x:Class="LinkToolAddin.ui.dockpane.TestDockpaneView"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:ui="clr-namespace:LinkToolAddin.ui.dockpane"
|
||||||
|
xmlns:extensions="clr-namespace:ArcGIS.Desktop.Extensions;assembly=ArcGIS.Desktop.Extensions"
|
||||||
|
xmlns:controls="clr-namespace:ArcGIS.Desktop.Framework.Controls;assembly=ArcGIS.Desktop.Framework"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignHeight="300" d:DesignWidth="300"
|
||||||
|
d:DataContext="{Binding Path=ui.TestDockpaneViewModel}">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<extensions:DesignOnlyResourceDictionary Source="pack://application:,,,/ArcGIS.Desktop.Framework;component\Themes\Default.xaml"/>
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
</ResourceDictionary>
|
||||||
|
</UserControl.Resources>
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<DockPanel Grid.Row="0" LastChildFill="true" KeyboardNavigation.TabNavigation="Local" Height="30">
|
||||||
|
<Button Content="Test Workflow" Name="TestWorkflow" Click="TestWorkflow_OnClick"></Button>
|
||||||
|
</DockPanel>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
157
ui/dockpane/TestDockpane.xaml.cs
Normal file
157
ui/dockpane/TestDockpane.xaml.cs
Normal file
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for TestDockpaneView.xaml
|
||||||
|
/// </summary>
|
||||||
|
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<string> args = new List<string>();
|
||||||
|
args.Add("mcp-server-time");
|
||||||
|
args.Add("--local-timezone=America/New_York");
|
||||||
|
McpClient stdioMcpClient = new StdioMcpClient("uvx",args);
|
||||||
|
IList<McpClientTool> tools = await stdioMcpClient.GetToolListAsync();
|
||||||
|
foreach (McpClientTool tool in tools)
|
||||||
|
{
|
||||||
|
log.Info(tool.JsonSchema.ToString());
|
||||||
|
}
|
||||||
|
CallToolResponse response = await stdioMcpClient.CallToolAsync("get_current_time",
|
||||||
|
new Dictionary<string, object> { { "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<McpClientTool> 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<Message>()
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
62
ui/dockpane/TestDockpaneViewModel.cs
Normal file
62
ui/dockpane/TestDockpaneViewModel.cs
Normal file
@ -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() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Show the DockPane.
|
||||||
|
/// </summary>
|
||||||
|
internal static void Show()
|
||||||
|
{
|
||||||
|
DockPane pane = FrameworkApplication.DockPaneManager.Find(_dockPaneID);
|
||||||
|
if (pane == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pane.Activate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Text shown near the top of the DockPane.
|
||||||
|
/// </summary>
|
||||||
|
private string _heading = "My DockPane";
|
||||||
|
public string Heading
|
||||||
|
{
|
||||||
|
get => _heading;
|
||||||
|
set => SetProperty(ref _heading, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Button implementation to show the DockPane.
|
||||||
|
/// </summary>
|
||||||
|
internal class TestDockpane_ShowButton : Button
|
||||||
|
{
|
||||||
|
protected override void OnClick()
|
||||||
|
{
|
||||||
|
TestDockpaneViewModel.Show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
9
ui/message/ChatMessageItem.cs
Normal file
9
ui/message/ChatMessageItem.cs
Normal file
@ -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; }
|
||||||
|
}
|
||||||
@ -1,7 +1,15 @@
|
|||||||
namespace LinkToolAddin.message;
|
namespace LinkToolAddin.message;
|
||||||
|
|
||||||
|
public enum MessageType
|
||||||
|
{
|
||||||
|
TOOL_MESSAGE,
|
||||||
|
CHAT_MESSAGE,
|
||||||
|
}
|
||||||
|
|
||||||
public interface MessageListItem
|
public interface MessageListItem
|
||||||
{
|
{
|
||||||
|
string id { get; set; }
|
||||||
string role { get; set; }
|
string role { get; set; }
|
||||||
string content { get; set; }
|
string content { get; set; }
|
||||||
|
MessageType type { get; set; }
|
||||||
}
|
}
|
||||||
15
ui/message/ToolMessageItem.cs
Normal file
15
ui/message/ToolMessageItem.cs
Normal file
@ -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<string,object> toolParams { get; set; }
|
||||||
|
public MessageType type { get; set; }
|
||||||
|
public string status { get; set; }
|
||||||
|
public string result { get; set; }
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user