Compare commits

...

4 Commits
master ... ui

6 changed files with 147 additions and 44 deletions

View File

@ -2,7 +2,7 @@
"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", "applicationUrl": "https://localhost:5001",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"

View File

@ -590,37 +590,37 @@ public class Gateway
return JsonConvert.SerializeObject(paramSchema, settings);; return JsonConvert.SerializeObject(paramSchema, settings);;
} }
public static async void TestChatMessage(string message, string model, string gdbPath, public static async void TestChatMessage(string message, string model, string gdbPath,//生成并返回一个聊天消息ChatMessageItem模拟AI助手的响应。通过回调函数 callback 将消息传递到前端显示。1
Action<MessageListItem> callback) Action<MessageListItem> callback)
{ {
MessageListItem chatListItem = new ChatMessageItem MessageListItem chatListItem = new ChatMessageItem//返回的东西1
{ {
content = message, content = message,
role = "assistant", role = "assistant",//角色assistant是ai的回答user用户的回答sistant系统提示词1
type = MessageType.CHAT_MESSAGE, type = MessageType.CHAT_MESSAGE,//根据type判断是工具卡还是聊天卡1
id = "testmsg12345" id = "testmsg12345"//琅哥虚构的定位可以用引用选中凭id找1
}; };
callback?.Invoke(chatListItem); callback?.Invoke(chatListItem);
} }
public static async void TestToolMessage(string message, string model, string gdbPath, Action<MessageListItem> callback) public static async void TestToolMessage(string message, string model, string gdbPath, Action<MessageListItem> callback)//同上1
{ {
MessageListItem toolListItem = new ToolMessageItem MessageListItem toolListItem = new ToolMessageItem
{ {
content = message, content = message,//大模型生成的信息正常来说是个x啥1
type = MessageType.TOOL_MESSAGE, type = MessageType.TOOL_MESSAGE,
toolName = "arcgis_pro.executeTool", toolName = "arcgis_pro.executeTool",//要调用的工具名称大模型工具不是arcgis工具调⽤ArcGIS Pro.GP工具调用1
toolParams = new Dictionary<string, object> toolParams = new Dictionary<string, object>
{ {
{"gp_name","analysis.Buffer"}, {"gp_name","analysis.Buffer"},//传参要传Arcgis的工具名
{"gp_params","[\"C:\\test.gdb\\river\",\"30 Meters\"]"} {"gp_params","[\"C:\\test.gdb\\river\",\"30 Meters\"]"}//工具参数数组字符串要转成数组前端要调用OpenTrueDialog没听懂1
}, },
id = "testtool123456", id = "testtool123456",
status = "success", status = "success",//显示勾
role = "user", role = "user",
result = "成功创建缓冲区" result = "成功创建缓冲区"
}; };
callback?.Invoke(toolListItem); callback?.Invoke(toolListItem);//这些调用结果显示在前端显示点后面的工具名称用户点的时候展开1
} }
public static async void TestWorkflow(string message, string model, string gdbPath, Action<MessageListItem> callback) public static async void TestWorkflow(string message, string model, string gdbPath, Action<MessageListItem> callback)

View File

@ -16,13 +16,40 @@
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
</ResourceDictionary> </ResourceDictionary>
</UserControl.Resources> </UserControl.Resources>
<Grid>
<Grid Margin="10" Background="White">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto"/> <RowDefinition Height="4*"/>
<RowDefinition Height="*"/> <RowDefinition Height="10"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<DockPanel Grid.Row="0" LastChildFill="true" KeyboardNavigation.TabNavigation="Local" Height="30">
<Button Content="Test Server" Name="TestServer" Click="TestServer_OnClick"></Button> <ScrollViewer Grid.Row="0" VerticalScrollBarVisibility="Auto" Name="MessageScrollViewer">
</ScrollViewer>
<DockPanel Grid.Row="2" Background="AliceBlue" Margin="0,0,0,0">
<Button
x:Name="SendButton"
Content="发送"
Width="45"
Height="40"
Margin="5,0,5,0"
Background="#FFD0E0F0"
BorderBrush="#FFA0B0C0"
BorderThickness="1"
Padding="0"
DockPanel.Dock="Right"
Click="Send_0nclick"/>
<TextBox x:Name="InputTextBox"
Height="40"
Margin="5,0,5,0"
TextWrapping="Wrap"
Background="White"
BorderBrush="#FFD0D0D0"
BorderThickness="1"
Padding="5"/>
</DockPanel> </DockPanel>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@ -1,36 +1,41 @@
using System;
using System.Collections.Generic;
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 System.Windows.Documents;
using ArcGIS.Desktop.Core.Geoprocessing; using ArcGIS.Desktop.Core.Geoprocessing;
using LinkToolAddin.client; using LinkToolAddin.client;
using LinkToolAddin.host;
using LinkToolAddin.host.llm; using LinkToolAddin.host.llm;
using LinkToolAddin.host.llm.entity; using LinkToolAddin.host.llm.entity;
using LinkToolAddin.message;
using LinkToolAddin.resource; using LinkToolAddin.resource;
using LinkToolAddin.server; using LinkToolAddin.server;
using log4net; using log4net;
using log4net.Appender; using log4net.Appender;
using log4net.Config; using log4net.Config;
using log4net.Layout; using log4net.Layout;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using ModelContextProtocol.Client; using ModelContextProtocol.Client;
using ModelContextProtocol.Protocol.Types; using ModelContextProtocol.Protocol.Types;
using ModelContextProtocol.Server; using ModelContextProtocol.Server;
using Newtonsoft.Json; using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text.Json;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
namespace LinkToolAddin.ui.dockpane namespace LinkToolAddin.ui.dockpane
{ {
/// <summary> /// <summary>
/// Interaction logic for DialogDockpaneView.xaml /// Interaction logic for DialogDockpaneView.xaml
/// 显示消息列表、输入框和发送按钮
/// </summary> /// </summary>
public partial class DialogDockpaneView : UserControl public partial class DialogDockpaneView : UserControl
{ {
@ -81,5 +86,69 @@ namespace LinkToolAddin.ui.dockpane
log.Info("Info 日志(控制台和文件可见)"); log.Info("Info 日志(控制台和文件可见)");
log.Error("Error 日志(严重问题)"); log.Error("Error 日志(严重问题)");
} }
private void Send_0nclick(object sender, RoutedEventArgs e)
{
string userInput = InputTextBox.Text.Trim();
if (string.IsNullOrEmpty(userInput)) return;
var userMessage = new ChatMessageItem
{
id = Guid.NewGuid().ToString(),
role = "user",
content = userInput,
type = MessageType.CHAT_MESSAGE
};
// 使用统一方法显示消息
NewMessage(userMessage);
// 清空输入框
InputTextBox.Clear();
Gateway.SendMessageStream(InputTextBox.Text, model: "qwen-max", gdbPath: "c: /user.gdb", NewMessage);
}
public void NewMessage(MessageListItem messagelistItem)
{
// 创建用于显示消息内容的 TextBlock
TextBlock textBlock = new TextBlock();
textBlock.Text = InputTextBox.Text;
textBlock.TextWrapping = TextWrapping.Wrap; // 自动换行
textBlock.VerticalAlignment = VerticalAlignment.Center;
// 创建 Border 作为消息气泡容器
Border border = new Border();
border.Child = textBlock;
border.CornerRadius = new CornerRadius(10);
border.Padding = new Thickness(10);
border.Margin = new Thickness(5);
// 设置默认宽度限制
border.MaxWidth = 300;
if (messagelistItem.role == "user")
{
// 浅蓝色背景,靠右
border.Background = new SolidColorBrush(Color.FromRgb(212, 229, 239)); // 浅蓝
border.HorizontalAlignment = HorizontalAlignment.Right;
}
else if (messagelistItem.role == "assistant")
{
// 浅灰背景,靠左
border.Background = new SolidColorBrush(Color.FromRgb(240, 240, 240)); // 浅灰
border.HorizontalAlignment = HorizontalAlignment.Left;
if (messagelistItem.type == MessageType.TOOL_MESSAGE)
{
border.BorderBrush = new SolidColorBrush(Color.FromRgb(212, 220, 223)); // 灰蓝色边框
border.BorderThickness = new Thickness(1);
}
}
// 把气泡添加到 MessageListView 显示
MessageListView.Items.Add(border);
// 自动滚动到底部
MessageScrollViewer.ScrollToEnd();
}
} }
} }

View File

@ -21,6 +21,8 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Console; using Microsoft.Extensions.Logging.Console;
using System.Collections.ObjectModel;
using LinkToolAddin.message;
namespace LinkToolAddin.ui.dockpane namespace LinkToolAddin.ui.dockpane
{ {
@ -28,12 +30,17 @@ namespace LinkToolAddin.ui.dockpane
{ {
private const string _dockPaneID = "DialogDockpane"; private const string _dockPaneID = "DialogDockpane";
private ObservableCollection<MessageListItem> _message = new ObservableCollection<MessageListItem>();
//ObservableCollection<T> 是 .NET 提供的一个特殊集合类,它会在集合发生变化时自动通知 UI 更新,它实现了 INotifyCollectionChanged 接口UI 绑定后可以自动刷新。
public ObservableCollection<MessageListItem> Messages => _message;
//定义了一个只读属性 Messages返回内部的 _messages 集合。
//该属性将被绑定到 UI 的 ItemsControl.ItemsSource 上,这样 UI 就能实时显示新消息。
protected DialogDockpaneViewModel() { } protected DialogDockpaneViewModel() { }
/// <summary> /// <summary>
/// Show the DockPane. /// Show the DockPane.
/// </summary> /// </summary>
internal static void Show() internal static void Show()//显示面板
{ {
DockPane pane = FrameworkApplication.DockPaneManager.Find(_dockPaneID); DockPane pane = FrameworkApplication.DockPaneManager.Find(_dockPaneID);
if (pane == null) if (pane == null)
@ -45,18 +52,18 @@ namespace LinkToolAddin.ui.dockpane
/// <summary> /// <summary>
/// Text shown near the top of the DockPane. /// Text shown near the top of the DockPane.
/// </summary> /// </summary>
private string _heading = "My DockPane"; private string _heading = "My DockPane";//标题栏文字
public string Heading public string Heading
{ {
get => _heading; get => _heading;//绑定到 UI 上的标题文字,默认是 "My DockPane"。
set => SetProperty(ref _heading, value); set => SetProperty(ref _heading, value);//属性变更通知方法,用于支持数据绑定
} }
} }
/// <summary> /// <summary>
/// Button implementation to show the DockPane. /// Button implementation to show the DockPane.
/// </summary> /// </summary>
internal class DialogDockpane_ShowButton : Button internal class DialogDockpane_ShowButton : Button//用于打开面板
{ {
protected override void OnClick() protected override void OnClick()
{ {

View File

@ -24,7 +24,7 @@ namespace LinkToolAddin.ui.dockpane
/// <summary> /// <summary>
/// Interaction logic for TestDockpaneView.xaml /// Interaction logic for TestDockpaneView.xaml
/// </summary> /// </summary>
public partial class TestDockpaneView : UserControl public partial class TestDockpaneView : UserControl//类1
{ {
private static ILog log = LogManager.GetLogger(typeof(TestDockpaneView)); private static ILog log = LogManager.GetLogger(typeof(TestDockpaneView));
@ -33,11 +33,11 @@ namespace LinkToolAddin.ui.dockpane
public TestDockpaneView() public TestDockpaneView()
{ {
InitLogger(); InitLogger();//初始化日志输出器1
InitializeComponent(); InitializeComponent();
} }
protected void InitLogger() protected void InitLogger()//要复制代码到哪去1
{ {
// 1. 创建控制台输出器Appender // 1. 创建控制台输出器Appender
var consoleAppender = new ConsoleAppender var consoleAppender = new ConsoleAppender
@ -83,7 +83,7 @@ namespace LinkToolAddin.ui.dockpane
ArcGISProMcpServer.TestMcpServer(); ArcGISProMcpServer.TestMcpServer();
} }
private async void StdioMcp_test() private async void StdioMcp_test()//标准输入输出的MCP测试复制过去看能不能返回有没有东西1
{ {
List<string> args = new List<string>(); List<string> args = new List<string>();
args.Add("mcp-server-time"); args.Add("mcp-server-time");
@ -96,7 +96,7 @@ namespace LinkToolAddin.ui.dockpane
} }
CallToolResponse response = await stdioMcpClient.CallToolAsync("get_current_time", CallToolResponse response = await stdioMcpClient.CallToolAsync("get_current_time",
new Dictionary<string, object> { { "timezone", "America/New_York" } }); new Dictionary<string, object> { { "timezone", "America/New_York" } });
log.Info(JsonConvert.SerializeObject(response)); log.Info(JsonConvert.SerializeObject(response));//log看有没有东西和报错实际调试看对应按钮控制台有没有东西1
} }
private async void SseMcp_test() private async void SseMcp_test()