完成工作流控制面,预留前端接入
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
|
||||
an empty group-->
|
||||
<group id="CoreGroup" caption="核心功能" appearsOnAddInTab="false">
|
||||
<button refID="DialogDockpane_ShowButton" size="large" />
|
||||
<button refID="Version_Button" size="large" />
|
||||
</group>
|
||||
<button refID="DialogDockpane_ShowButton" size="large" />
|
||||
<button refID="Version_Button" size="large" />
|
||||
<button refID="LinkToolAddin_ui_dockpane_TestDockpane_ShowButton" size="large" />
|
||||
</group>
|
||||
<group id="PreferenceGroup" caption="设置项" appearsOnAddInTab="false">
|
||||
<button refID="Preference_Button" size="large" />
|
||||
</group>
|
||||
@ -40,11 +41,17 @@
|
||||
<button id="DialogDockpane_ShowButton" caption="对话面板" className="LinkToolAddin.ui.dockpane.DialogDockpane_ShowButton" loadOnClick="true" smallImage="GenericButtonPurple16" largeImage="GenericButtonPurple32">
|
||||
<tooltip heading="对话面板">打开AI对话面板<disabledText /></tooltip>
|
||||
</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>
|
||||
<dockPanes>
|
||||
<dockPane id="DialogDockpane" caption="LinkTool" className="LinkToolAddin.ui.dockpane.DialogDockpaneViewModel" dock="group" dockWith="esri_core_projectDockPane">
|
||||
<content className="LinkToolAddin.ui.dockpane.DialogDockpaneView" />
|
||||
</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>
|
||||
</insertModule>
|
||||
</modules>
|
||||
|
||||
@ -99,7 +99,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="resource\" />
|
||||
<Folder Include="server\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Esri.ArcGISPro.Extensions30" Version="3.4.1.55405" />
|
||||
|
||||
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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.entity;
|
||||
using LinkToolAddin.resource;
|
||||
using LinkToolAddin.server;
|
||||
using log4net;
|
||||
using log4net.Appender;
|
||||
using log4net.Config;
|
||||
@ -41,71 +42,9 @@ namespace LinkToolAddin.ui.dockpane
|
||||
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<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()
|
||||
@ -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 个历史文件
|
||||
|
||||
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;
|
||||
|
||||
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; }
|
||||
}
|
||||
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