325 lines
13 KiB
C#
325 lines
13 KiB
C#
using System;
|
||
using System.Collections.Concurrent;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Reflection;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
using System.Windows;
|
||
using System.Windows.Controls;
|
||
using System.Xml.Linq;
|
||
using LinkToolAddin.client;
|
||
using LinkToolAddin.client.tool;
|
||
using LinkToolAddin.common;
|
||
using LinkToolAddin.host;
|
||
using LinkToolAddin.host.llm;
|
||
using LinkToolAddin.host.llm.entity;
|
||
using LinkToolAddin.host.mcp;
|
||
using LinkToolAddin.host.prompt;
|
||
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;
|
||
using MessageBox = ArcGIS.Desktop.Framework.Dialogs.MessageBox;
|
||
|
||
|
||
namespace LinkToolAddin.ui.dockpane
|
||
{
|
||
/// <summary>
|
||
/// Interaction logic for TestDockpaneView.xaml
|
||
/// </summary>
|
||
public partial class TestDockpaneView : UserControl
|
||
{
|
||
private static ILog log = LogManager.GetLogger(typeof(TestDockpaneView));
|
||
|
||
private List<string> idList = new List<string>();
|
||
private ConcurrentDictionary<string,MessageListItem> messageDict = new ConcurrentDictionary<string,MessageListItem>();
|
||
|
||
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 async void Request_Bailian_Stream_Test()
|
||
{
|
||
LlmJsonContent jsonContent = new LlmJsonContent()
|
||
{
|
||
Model = "qwen-max",
|
||
Messages = new List<Message>()
|
||
{
|
||
new Message()
|
||
{
|
||
Role = "user",
|
||
Content = "给我写一篇1000字的高考议论文"
|
||
}
|
||
},
|
||
Temperature = 0.7,
|
||
TopP = 1,
|
||
MaxTokens = 1000,
|
||
Stream = true
|
||
};
|
||
Llm bailian = new Bailian
|
||
{
|
||
api_key = "sk-db177155677e438f832860e7f4da6afc",
|
||
app_id = "6a77c5a68de64f469b79fcdcde9d5001",
|
||
};
|
||
await foreach (var chunk in bailian.SendChatStreamAsync(jsonContent))
|
||
{
|
||
log.Info(chunk);
|
||
}
|
||
}
|
||
|
||
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);
|
||
Gateway.TestWorkflow("dafdfdgdagdgui","","",AddReply);
|
||
}
|
||
|
||
public void ShowMessage(MessageListItem msg)
|
||
{
|
||
log.Info(msg.content);
|
||
}
|
||
|
||
private async void PromptTestButton_OnClick(object sender, RoutedEventArgs e)
|
||
{
|
||
string userPrompt = PromptTestTextBox.Text;
|
||
// model可选值:qwen3-235b-a22b,qwen-max,deepseek-r1
|
||
try
|
||
{
|
||
await Task.Run(() => Gateway.SendMessageStream(userPrompt,"qwen3-235b-a22b", "F:\\secondsemester\\linktool\\test\\LinkTool0604\\LinkTool0604.gdb", AddReplyStream));
|
||
}
|
||
catch (Exception exception)
|
||
{
|
||
log.Error(exception.Message);
|
||
}
|
||
}
|
||
|
||
public async void AddReplyStream(MessageListItem msg)
|
||
{
|
||
await Task.Run(() => ProcessReplyStream(msg));
|
||
}
|
||
|
||
private void ProcessReplyStream(MessageListItem msg)
|
||
{
|
||
string id = msg.id;
|
||
if (idList.Contains(id))
|
||
{
|
||
messageDict[id] = msg;
|
||
}
|
||
else
|
||
{
|
||
idList.Add(id);
|
||
messageDict.TryAdd(msg.id, msg);
|
||
}
|
||
try
|
||
{
|
||
StringBuilder builder = new StringBuilder();
|
||
foreach (string idStr in idList)
|
||
{
|
||
MessageListItem msgItem = messageDict[idStr];
|
||
string content = msgItem.content;
|
||
if (msgItem.type == MessageType.REASON_MESSAGE)
|
||
{
|
||
content = "<think>" + content + "</think>";
|
||
}
|
||
builder.AppendLine(content);
|
||
builder.AppendLine();
|
||
}
|
||
Application.Current.Dispatcher.Invoke(() =>
|
||
{
|
||
ReplyTextBox.Clear();
|
||
ReplyTextBox.Text = builder.ToString();
|
||
ReplyTextBox.ScrollToEnd();
|
||
});
|
||
}catch (Exception exception)
|
||
{
|
||
log.Error(exception.Message);
|
||
}
|
||
}
|
||
|
||
public void AddReply(MessageListItem msg)
|
||
{
|
||
string content = msg.content;
|
||
log.Info(content);
|
||
string originContent = ReplyTextBox.Text;
|
||
ReplyTextBox.Text = originContent + content;
|
||
}
|
||
|
||
private void TestStream_OnClick(object sender, RoutedEventArgs e)
|
||
{
|
||
Request_Bailian_Stream_Test();
|
||
}
|
||
|
||
private void StopConversation_OnClick(object sender, RoutedEventArgs e)
|
||
{
|
||
Gateway.StopConversation();
|
||
}
|
||
|
||
private async void TestArcGisTool_OnClick(object sender, RoutedEventArgs e)
|
||
{
|
||
Type type1 = Type.GetType("LinkToolAddin.client.tool.ArcGisPro");
|
||
string xmlStr =
|
||
"<tool_use>\n<name>ArcGisPro:ArcGisProTool</name>\n<arguments>{\"toolName\": \"Buffer\", \"toolParams\": [\"D:\\\\01_Project\\\\20250305_LinkTool\\\\20250420_AiDemoProject\\\\20250420_AiDemoProject.gdb\\\\LandUse_2005_Copy\", \"D:\\\\01_Project\\\\20250305_LinkTool\\\\20250420_AiDemoProject\\\\20250420_AiDemoProject.gdb\\\\LandUse_2005_Buffer30m\", \"30 Meters\", \"NONE\", \"ROUND\", \"ALL\"]}</arguments>\n</tool_use>";
|
||
XElement toolUse = XElement.Parse(xmlStr);
|
||
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;
|
||
McpServerList mcpServerList = new McpServerList();
|
||
McpServer mcpServer = mcpServerList.GetServer(serverName);
|
||
if (mcpServer is InnerMcpServer)
|
||
{
|
||
Type type = Type.GetType("LinkToolAddin.client.tool." + serverName);
|
||
var toolParamsValues = toolParams.Values.ToArray();
|
||
MethodInfo method = type.GetMethod(toolName, BindingFlags.Public | BindingFlags.Static);
|
||
var task = method.Invoke(null, toolParams.Values.ToArray()) as Task<JsonRpcResultEntity>;
|
||
JsonRpcResultEntity innerResult = await task;
|
||
MessageListItem toolMessageItem = new ToolMessageItem
|
||
{
|
||
toolName = toolName,
|
||
toolParams = toolParams,
|
||
type = MessageType.TOOL_MESSAGE,
|
||
status = "fail",
|
||
content = JsonConvert.SerializeObject(innerResult),
|
||
id = "1test"
|
||
};
|
||
AddReply(toolMessageItem);
|
||
}
|
||
}
|
||
|
||
private void TestResource_OnClick(object sender, RoutedEventArgs e)
|
||
{
|
||
string content = LocalResource.ReadFileByResource("LinkToolAddin.resource.SystemPrompt.txt");
|
||
MessageBox.Show(content);
|
||
}
|
||
|
||
private async void TestAttrTable_OnClick(object sender, RoutedEventArgs e)
|
||
{
|
||
JsonRpcResultEntity result = await ArcGisPro.GetFeatureDatasetAttributeTable(
|
||
"D:\\01_Project\\20250305_LinkTool\\20250420_AiDemoProject\\20250420_AiDemoProject.gdb",
|
||
"LandUse_2005_Copy", "30");
|
||
log.Info("finish");
|
||
}
|
||
}
|
||
}
|