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.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
{
///
/// Interaction logic for TestDockpaneView.xaml
///
public partial class TestDockpaneView : UserControl
{
private static ILog log = LogManager.GetLogger(typeof(TestDockpaneView));
private List idList = new List();
private ConcurrentDictionary messageDict = new ConcurrentDictionary();
public TestDockpaneView()
{
InitLogger();
InitializeComponent();
}
protected void InitLogger()
{
// 1. 创建控制台输出器(Appender)
var consoleAppender = new ConsoleAppender
{
Layout = new PatternLayout("%date [%thread] %-5level %logger - %message%newline"),
Threshold = log4net.Core.Level.Info // 仅输出 Info 及以上级别
};
consoleAppender.ActivateOptions(); // 激活配置
// 2. 创建文件滚动输出器(按大小滚动)
var fileAppender = new RollingFileAppender
{
File = System.IO.Path.Combine("Logs", "linktool_app.log"), // 日志文件路径
AppendToFile = true, // 追加模式
RollingStyle = RollingFileAppender.RollingMode.Size, // 按文件大小滚动
MaxSizeRollBackups = 10, // 保留 10 个历史文件
MaximumFileSize = "1MB", // 单个文件最大 1MB
StaticLogFileName = true, // 固定文件名(否则自动追加序号)
Layout = new PatternLayout("%date [%thread] %-5level %logger - %message%newline"),
Threshold = log4net.Core.Level.Info // 仅输出 Info 及以上级别
};
fileAppender.ActivateOptions(); // 激活配置
// 3. 直接通过 BasicConfigurator 注册 Appender
BasicConfigurator.Configure(consoleAppender, fileAppender);
log = LogManager.GetLogger(typeof(DialogDockpaneView));
// 测试日志输出
log.Debug("Debug 日志(控制台可见)");
log.Info("Info 日志(控制台和文件可见)");
log.Error("Error 日志(严重问题)");
}
public void CallBack(string str,object obj)
{
log.Info($"CallBack {str}");
}
private async void TestServer_OnClick(object sender, RoutedEventArgs e)
{
log.Info("TestServer Clicked");
ArcGISProMcpServer.TestMcpServer();
}
private async void StdioMcp_test()
{
List args = new List();
args.Add("mcp-server-time");
args.Add("--local-timezone=America/New_York");
McpClient stdioMcpClient = new StdioMcpClient("uvx",args);
IList tools = await stdioMcpClient.GetToolListAsync();
foreach (McpClientTool tool in tools)
{
log.Info(tool.JsonSchema.ToString());
}
CallToolResponse response = await stdioMcpClient.CallToolAsync("get_current_time",
new Dictionary { { "timezone", "America/New_York" } });
log.Info(JsonConvert.SerializeObject(response));
}
private async void SseMcp_test()
{
SseMcpClient client = new SseMcpClient("https://mcp.amap.com/sse?key=ed418512c94ade8f83d42c37b77d2bb2");
IList tools = await client.GetToolListAsync();
foreach (McpClientTool tool in tools)
{
log.Info(tool.JsonSchema.ToString());
}
}
private async void Retrieve_Test()
{
log.Info("TestServer Clicked");
// string jsonRpcString = @"{""jsonrpc"":""2.0"",""method"":""CallArcGISPro.CallArcGISProTool"",""params"":{""toolName"":""analysis.Buffer"",""toolParams"":""[\""D:/01_Development/02_ArcGIS_Pro_Project/20250319_GisAi/Test.gdb/河流\"",\""D:/01_Development/02_ArcGIS_Pro_Project/20250319_GisAi/Test.gdb/河流buffer\"",\""100\""]""},""id"":1}";
DocDb docDb = new DocDb("sk-db177155677e438f832860e7f4da6afc", DocDb.KnowledgeBase.ArcGISProHelpDoc);
string query = "缓冲区";
KnowledgeResult knowledgeResult = await docDb.Retrieve(query);
log.Info(JsonConvert.SerializeObject(knowledgeResult.ChunkList));
}
private async void Request_Bailian_Test()
{
Llm bailian = new Bailian
{
api_key = "sk-db177155677e438f832860e7f4da6afc",
app_id = "6a77c5a68de64f469b79fcdcde9d5001",
};
string reponse = await bailian.SendChatAsync(new LlmJsonContent()
{
Model = "qwen-max",
Messages = new List()
{
new Message()
{
Role = "user",
Content = "你是谁"
}
},
Temperature = 0.7,
TopP = 1,
MaxTokens = 1000,
});
log.Info(reponse);
}
private async void Request_Bailian_Stream_Test()
{
LlmJsonContent jsonContent = new LlmJsonContent()
{
Model = "qwen-max",
Messages = new List()
{
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\\linktooltest\\linktooltest.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);
}
Application.Current.Dispatcher.Invoke(() =>
{
ReplyTextBox.Clear();
});
try
{
StringBuilder builder = new StringBuilder();
foreach (KeyValuePair pair in messageDict)
{
MessageListItem msgItem = pair.Value;
string content = msgItem.content;
if (msgItem.type == MessageType.REASON_MESSAGE)
{
content = "" + content + "";
}
builder.AppendLine(content);
builder.AppendLine();
}
Application.Current.Dispatcher.Invoke(() =>
{
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 =
"\nArcGisPro:ArcGisProTool\n{\"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\"]}\n";
XElement toolUse = XElement.Parse(xmlStr);
string fullToolName = toolUse.Element("name")?.Value;
string toolArgs = toolUse.Element("arguments")?.Value;
Dictionary toolParams = JsonConvert.DeserializeObject>(toolArgs);
string serverName = fullToolName.Contains(":") ? fullToolName.Split(':')[0] : fullToolName;
string toolName = fullToolName.Contains(":") ? fullToolName.Split(':')[1] : fullToolName;
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 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);
}
}
}