From 52148f693611bf4c222946d36cd06488dfcffa2d Mon Sep 17 00:00:00 2001 From: PeterZhong Date: Tue, 3 Jun 2025 18:35:01 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E4=BA=86=E5=9F=BA?= =?UTF-8?q?=E7=A1=80=E7=9A=84=E5=B7=A5=E5=85=B7=E3=80=81=E6=B6=88=E6=81=AF?= =?UTF-8?q?UI=E7=95=8C=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LinkToolAddin.csproj | 12 ++ common/LocalResource.cs | 28 +++- host/Gateway.cs | 52 ++++--- host/McpServerList.cs | 94 ++++++------ resource/img/linktool.png | Bin 0 -> 931 bytes resource/img/tool.png | Bin 0 -> 1082 bytes resource/img/user.png | Bin 0 -> 784 bytes ui/dockpane/DialogDockpane.xaml | 29 +++- ui/dockpane/DialogDockpane.xaml.cs | 203 ++++++++++++++++++++++++- ui/dockpane/DialogDockpaneViewModel.cs | 9 +- 10 files changed, 344 insertions(+), 83 deletions(-) create mode 100644 resource/img/linktool.png create mode 100644 resource/img/tool.png create mode 100644 resource/img/user.png diff --git a/LinkToolAddin.csproj b/LinkToolAddin.csproj index 0f3f990..d764cc6 100644 --- a/LinkToolAddin.csproj +++ b/LinkToolAddin.csproj @@ -120,6 +120,18 @@ Always + + + Always + + + + Always + + + + Always + diff --git a/common/LocalResource.cs b/common/LocalResource.cs index fc1e719..4f4e53a 100644 --- a/common/LocalResource.cs +++ b/common/LocalResource.cs @@ -1,5 +1,7 @@ using System; using System.IO; +using System.Windows.Controls; +using System.Windows.Media.Imaging; namespace LinkToolAddin.common; @@ -8,12 +10,6 @@ public class LocalResource public static string ReadFileByResource(string resourceName) { var assembly = System.Reflection.Assembly.GetExecutingAssembly(); - - string[] resourceNames = assembly.GetManifestResourceNames(); - foreach (string name in resourceNames) - { - Console.WriteLine(name); - } using (Stream stream = assembly.GetManifestResourceStream(resourceName)) { @@ -28,4 +24,24 @@ public class LocalResource } } } + + public static BitmapImage ReadImageByResource(string resourceName) + { + var assembly = System.Reflection.Assembly.GetExecutingAssembly(); + using (Stream stream = assembly.GetManifestResourceStream(resourceName)) + { + if (stream == null) + { + Console.WriteLine("资源未找到,请检查资源名称是否正确。"); + return null; + } + + // 如果是 WPF,可以转换为 BitmapImage + BitmapImage bitmap = new BitmapImage(); + bitmap.BeginInit(); + bitmap.StreamSource = stream; + bitmap.EndInit(); + return bitmap; + } + } } \ No newline at end of file diff --git a/host/Gateway.cs b/host/Gateway.cs index 2a789c5..63ef2b2 100644 --- a/host/Gateway.cs +++ b/host/Gateway.cs @@ -328,14 +328,17 @@ public class Gateway else { //包含Prompt调用请求的消息 - MessageListItem chatMessageListItem = new ChatMessageItem() + if (remainingPrompt != "") { - content = remainingPrompt, - role = "assistant", - type = MessageType.CHAT_MESSAGE, - id = timestamp.ToString() - }; - callback?.Invoke(chatMessageListItem); + MessageListItem chatMessageListItem = new ChatMessageItem() + { + content = remainingPrompt, + role = "assistant", + type = MessageType.CHAT_MESSAGE, + id = timestamp.ToString() + }; + callback?.Invoke(chatMessageListItem); + } XElement promptUse = XElement.Parse(matchedPrompt); string promptKey = promptUse.Element("name")?.Value; string promptArgs = promptUse.Element("arguments")?.Value; @@ -352,17 +355,20 @@ public class Gateway else { //包含工具调用请求的消息 - MessageListItem chatMessageListItem = new ChatMessageItem() + if (remaining != "") { - content = remaining, - role = "assistant", - type = MessageType.CHAT_MESSAGE, - id = timestamp.ToString() - }; - Application.Current.Dispatcher.Invoke(() => - { - callback?.Invoke(chatMessageListItem); - }); + MessageListItem chatMessageListItem = new ChatMessageItem() + { + content = remaining, + role = "assistant", + type = MessageType.CHAT_MESSAGE, + id = timestamp.ToString() + }; + Application.Current.Dispatcher.Invoke(() => + { + callback?.Invoke(chatMessageListItem); + }); + } XElement toolUse = XElement.Parse(matched); string fullToolName = toolUse.Element("name")?.Value; string toolArgs = toolUse.Element("arguments")?.Value; @@ -415,7 +421,8 @@ public class Gateway type = MessageType.TOOL_MESSAGE, status = toolResponse.IsError ? "fail" : "success", content = JsonConvert.SerializeObject(toolResponse), - id = (timestamp + 1).ToString() + id = (timestamp + 1).ToString(), + role = "user" }; messages.Add(new Message { @@ -441,7 +448,8 @@ public class Gateway type = MessageType.TOOL_MESSAGE, status = toolResponse.IsError ? "fail" : "success", content = JsonConvert.SerializeObject(toolResponse), - id = (timestamp + 1).ToString() + id = (timestamp + 1).ToString(), + role = "user" }; messages.Add(new Message { @@ -486,7 +494,8 @@ public class Gateway type = MessageType.TOOL_MESSAGE, status = "fail", content = JsonConvert.SerializeObject(innerResult), - id = (timestamp + 1).ToString() + id = (timestamp + 1).ToString(), + role = "user" }; messages.Add(new Message { @@ -507,7 +516,8 @@ public class Gateway type = MessageType.TOOL_MESSAGE, status = "success", content = JsonConvert.SerializeObject(innerResult), - id = (timestamp + 1).ToString() + id = (timestamp + 1).ToString(), + role = "user" }; messages.Add(new Message { diff --git a/host/McpServerList.cs b/host/McpServerList.cs index ca7415d..b452abc 100644 --- a/host/McpServerList.cs +++ b/host/McpServerList.cs @@ -35,53 +35,53 @@ public class McpServerList Description = "可以调用进行查询知识库,获取相关参考信息。", IsActive = true }); - servers.Add("filesystem", new StdioMcpServer() - { - Name = "filesystem", - Type = "stdio", - Command = "npx", - Args = new List() - { - "-y", - "@modelcontextprotocol/server-filesystem", - "D:\\01_Project\\20250305_LinkTool\\20250420_AiDemoProject\\TestData" - } - }); - servers.Add("fetch", new StdioMcpServer() - { - Name = "fetch", - Type = "stdio", - Command = "uvx", - Args = new List() - { - "mcp-server-fetch" - } - }); - servers.Add("bing-search", new StdioMcpServer() - { - Name = "bing-search", - Type = "stdio", - Command = "npx", - Args = new List() - { - "bing-cn-mcp" - } - }); - servers.Add("mcp-python-interpreter", new StdioMcpServer() - { - Name = "mcp-python-interpreter", - Type = "stdio", - Command = "uvx", - Args = new List() - { - "--native-tls", - "mcp-python-interpreter", - "--dir", - "D:\\01_Project\\20250305_LinkTool\\20250420_AiDemoProject\\TestData", - "--python-path", - "C:\\Program Files\\ArcGIS\\Pro\\bin\\Python\\envs\\custom\\python.exe" - } - }); + // servers.Add("filesystem", new StdioMcpServer() + // { + // Name = "filesystem", + // Type = "stdio", + // Command = "npx", + // Args = new List() + // { + // "-y", + // "@modelcontextprotocol/server-filesystem", + // "D:\\01_Project\\20250305_LinkTool\\20250420_AiDemoProject\\TestData" + // } + // }); + // servers.Add("fetch", new StdioMcpServer() + // { + // Name = "fetch", + // Type = "stdio", + // Command = "uvx", + // Args = new List() + // { + // "mcp-server-fetch" + // } + // }); + // servers.Add("bing-search", new StdioMcpServer() + // { + // Name = "bing-search", + // Type = "stdio", + // Command = "npx", + // Args = new List() + // { + // "bing-cn-mcp" + // } + // }); + // servers.Add("mcp-python-interpreter", new StdioMcpServer() + // { + // Name = "mcp-python-interpreter", + // Type = "stdio", + // Command = "uvx", + // Args = new List() + // { + // "--native-tls", + // "mcp-python-interpreter", + // "--dir", + // "D:\\01_Project\\20250305_LinkTool\\20250420_AiDemoProject\\TestData", + // "--python-path", + // "C:\\Program Files\\ArcGIS\\Pro\\bin\\Python\\envs\\custom\\python.exe" + // } + // }); } public McpServer GetServer(string name) diff --git a/resource/img/linktool.png b/resource/img/linktool.png new file mode 100644 index 0000000000000000000000000000000000000000..37264c2046f6c4a22ba32068324771e29f4246ed GIT binary patch literal 931 zcmV;U16=%xP)Px&T}ebiR9Hu?SM6=vKnx|743N45Q~~M$nIg_4iGSK1!p;zlf7+hJ&J+dW08t01 zn*m(0;8B!l>P}Vw=U;rf<0JVVKM>CRH(2auL@+|2JUorK+E0d0DKq#P`&Wx!IlyI} z0o=(w%mJuS17DtZ8w41&-=w0%fA=4g+rppq0?>FBdmLat9U^}N1arX!^AZm0i}GSb zh)e#70JeXp!~0JGu#fTsh*$v8BYRDN1$&D`<3B%cR)go)caDfRG+4YXG$#1pRbSX9edA@51w}<-chli-dwAv#{l5|V=~;@ zD6{~u@r*7uf*8kq!5il@3qbB%zSj>|ppVkhCj!kw$6heG_;H&z=d6`|4NlvT=luqj2&WvobWaY2G7e%J$uaX`P(Gp!l+u1J#}wN{{pEG7{yE}j?O zNbFvS>f&wbi7R}Qf~F2*isc&0SY%Qp^ig7CzVbEiimWje=C0KA0iYGtmSqJfPQ#W< zJT^7_G|$iaMb%S61OT(GR{&-BEwopJIhORhtpYi>DzM+gRHEmEFk_p{kscgqcQ8w) zE)o(^9-9F|)T`no0Dy9zD^Hdf!I;fm0Qinqf~r8(RZlW;8FG5!Go3z^1Q1f&zU#@2 zU7n^S+A9T#BF6Q>rsj;jpua|JajUvvGj3TmbSa^e<&i#7_W^*BOt9 zK6dqjSaI{@)3<5>br-ATaa{9Z=2emckor9~ZPo3#-Nj@Q7P3_XXB1d773&*X*sT0g zQf~o}E>W*B=IpI5F)S}p4sSx3Yq{+b=*iuXJ>}6XzH}b7pF);Z z*#ij=Px&^hrcPR9Hu?m%VNjNf5`YdY6mc z_&L+R*Y9-98WCLNVPnk8_irA}Qggrc8^#-)9o>IHL_Z`pUJ$_Uhxv5-Bt}<wFAw?&@+LW-f(ijF!H|x=#3_S7lr*r zpDG2xbL(8GVS2*}!{7Gbb_;8_Wp4*&%pOA&)(&uWu=y(@{)UL}^P;$N9E3VqKjj7Q z@;xA$VW+bli`N6N7n~O{qFsuw_JkM|FQ75w*g(^m_8=f^Wc$Fgwm@(L5OcD2lW!4&>h(&zcsRPjBNVzYS zZ~{a*c!8Pw@<`rnBHY?ruQldXLO(M`x>Y1+!j~aW2tM~ zlrbx**n46Njd{+ek+c~$K%8a!kH>n$ifD=ckZ>HAs)God==d~Tk_q8I1MnvhbOGU? zY=8P=4TK9vHlLnv+ETvUS1pL|QDJrQxH+W$}Zod>`z8!5KS^-F0iQr#E zI2Y#yG1T*#0BjF&EI=%(l?!*TnQrF=0Gv*Hq7-IZh(>_exUTW6d;&W6tq`>UO~$#B z6@{I3P3JX392K9X+tD^0Nr1ShRJt2qfYh8)0u2xd@RDf+CvI7+RBfEgGLMJW zDq)<6?x4XZDX) z%jR_u(#*=+B4|rGqPk)vjf%8RI_9ZPi1*PDGAHcgJ8TzHV-C1FW(QBk&I7W!T&duy zM9k}qizfo8U#kEhK&cK(18^%1B0T<^t6Q6sYay%B?iw7oz9_b&7f6PHHwdRDniWJF zCovvUvTsb|Bo)62*hb|RXb3R)+`o>3>)I3-r78FL;7*C}KXJ!YzN#wwE#(0Z;Tq9+ za$5iev87%}{JD|?l8Hz}$-lqHlbqcydP*JOD~scR7Kw-0EdT%j07*qoM6N<$f@+}i A%m4rY literal 0 HcmV?d00001 diff --git a/resource/img/user.png b/resource/img/user.png new file mode 100644 index 0000000000000000000000000000000000000000..a992685890033c8da9d9ba147f96b6195e87355e GIT binary patch literal 784 zcmV+r1MmEaP)Px%%1J~)R9HvFS3z>yFbo9bsXP5a>K^Lc?0%y5OA^1t&P$xWBMwy<_Dds zW1$0zkU$!wq?2_?W=xUG#qI(^xbcHGJ|9K{xcjr17X>^x;8@JvU#d$)c)cK$Z|_cr zF_#()VD@*h1;j@HXbw$3B@jKI-=Cg_0OF;Tb&^8JRRkE zdc3zvVgd*bztH;a!>Jrn&v=akGQpRI4SYUNe{AA4R{&Ja%Q|zoTjy(!P=Eh5Jvm(@ zK>T!?0ougtt^mxcB`==WNNbDsyMK#SK~9vh82WP|H^7Rmb4)_@o;lV-AjlX1#hdGz zw&gJZ3OlLyHG8_eEdZ&LB@_WMtCqz7pQlIDJ^uHk<-}e3jCLcbe-40bUX_Ws0HWN_}L&1v1~i`o6mFMlmZ~^v8Y9y7K?VIiY5K-S~O_~hQCCeGno-4fGgYe z%ykwh?TB1JC1*lwt{XCLdm(p2X^(z-$8zI)z(p_umOP5Nv5aFFan%J;H?Z`5AM^s? zt%MEZ5R3gm-vjdEAOQN5cJ^;SMw(AEUQ^fbZR`X+8o*E&3|)6~0RI8<6D&WHlhY;u O0000 @@ -16,13 +17,27 @@ - + - + + + + - - - + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ui/dockpane/DialogDockpane.xaml.cs b/ui/dockpane/DialogDockpane.xaml.cs index aa2ea7f..1148b88 100644 --- a/ui/dockpane/DialogDockpane.xaml.cs +++ b/ui/dockpane/DialogDockpane.xaml.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.ComponentModel; using System.IO; using System.Net.Http; @@ -12,10 +14,15 @@ using Microsoft.Extensions.Logging; using System.Text.Json; using System.Threading; using System.Windows.Documents; +using System.Windows.Media; +using ArcGIS.Desktop.Core; using ArcGIS.Desktop.Core.Geoprocessing; using LinkToolAddin.client; +using LinkToolAddin.common; +using LinkToolAddin.host; using LinkToolAddin.host.llm; using LinkToolAddin.host.llm.entity; +using LinkToolAddin.message; using LinkToolAddin.resource; using LinkToolAddin.server; using log4net; @@ -29,17 +36,26 @@ using Newtonsoft.Json; namespace LinkToolAddin.ui.dockpane { + public class ItemModel + { + public string Content { get; set; } + } /// /// Interaction logic for DialogDockpaneView.xaml /// public partial class DialogDockpaneView : UserControl { private static ILog log = LogManager.GetLogger(typeof(DialogDockpaneView)); - + + private List idList = new List(); + private ConcurrentDictionary messageDict = new ConcurrentDictionary(); + private ConcurrentDictionary borderItemsDict = new ConcurrentDictionary(); + public DialogDockpaneView() { InitLogger(); InitializeComponent(); + DataContext = this; } private async void TestServer_OnClick(object sender, RoutedEventArgs e) @@ -81,5 +97,190 @@ namespace LinkToolAddin.ui.dockpane log.Info("Info 日志(控制台和文件可见)"); log.Error("Error 日志(严重问题)"); } + + private void SendButton_OnClick(object sender, RoutedEventArgs e) + { + string question = QuestionTextbox.Text; + string defaultGdbPath = Project.Current.DefaultGeodatabasePath; + string gdbPath = @""; + long timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); + MessageListItem userMsg = new ChatMessageItem() + { + content = question, + role = "user", + type = MessageType.CHAT_MESSAGE, + id = timestamp.ToString() + }; + Border userMsgBoder = GetUserChatBorder(userMsg); + idList.Add(timestamp.ToString()); + messageDict[timestamp.ToString()] = userMsg; + QuestionTextbox.Text = ""; + borderItemsDict[timestamp.ToString()] = userMsgBoder; + ChatHistoryStackPanel.Children.Add(userMsgBoder); + Gateway.SendMessageStream(question,"qwen-max",defaultGdbPath,NewMessage_Recall); + } + + public void NewMessage_Recall(MessageListItem msg) + { + string msgId = msg.id; + log.Info(msg.content); + if (!idList.Contains(msgId)) + { + //不存在该消息,需添加到ListView中 + if (msg.content == "") + { + return; + } + idList.Add(msgId); + messageDict[msgId] = msg; + if (msg.role == "user") + { + if (msg.type == MessageType.TOOL_MESSAGE) + { + Border border = GetToolChatBorder(msg); + borderItemsDict[msgId] = border; + ChatHistoryStackPanel.Children.Add(border); + }else if (msg.type == MessageType.CHAT_MESSAGE) + { + Border border = GetUserChatBorder(msg); + borderItemsDict[msgId] = border; + ChatHistoryStackPanel.Children.Add(border); + } + } + else + { + Border border = GetAiChatBorder(msg); + borderItemsDict[msgId] = border; + ChatHistoryStackPanel.Children.Add(border); + } + } + else + { + //已有该消息,只需要修改内容 + messageDict[msgId] = msg; + if (msg.role == "user") + { + if (msg.type == MessageType.TOOL_MESSAGE) + { + Border borderItem = borderItemsDict[msgId]; + Grid grid = borderItem.Child as Grid; + TextBlock textBlock = grid.Children[1] as TextBlock; + textBlock.Text = (msg as ToolMessageItem).toolName; + }else if (msg.type == MessageType.CHAT_MESSAGE) + { + Border borderItem = borderItemsDict[msgId]; + Grid grid = borderItem.Child as Grid; + TextBox textBox = grid.Children[1] as TextBox; + textBox.Text = msg.content; + } + } + else + { + Border borderItem = borderItemsDict[msgId]; + Grid grid = borderItem.Child as Grid; + TextBox textBox = grid.Children[1] as TextBox; + textBox.Text = msg.content; + } + } + } + + private Border GetAiChatBorder(MessageListItem msg) + { + Border border = new Border(); + border.Margin = new Thickness(8, 12, 8, 12); + border.BorderThickness = new Thickness(0); + // border.Background = Brushes.DarkSeaGreen; + Grid grid = new Grid(); + Image icon = new Image() + { + Source = LocalResource.ReadImageByResource("LinkToolAddin.resource.img.linktool.png"), + Stretch = Stretch.Fill, + HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Top + }; + grid.ColumnDefinitions.Add(new ColumnDefinition(){Width = new GridLength(24, GridUnitType.Pixel)}); + grid.ColumnDefinitions.Add(new ColumnDefinition(){Width = new GridLength(1, GridUnitType.Star)}); + TextBox textBox = new TextBox(); + grid.Children.Add(icon); + grid.Children.Add(textBox); + Grid.SetColumn(icon, 0); + Grid.SetColumn(textBox, 1); + textBox.Background = Brushes.Transparent; + textBox.Text = msg.content; + textBox.TextWrapping = TextWrapping.Wrap; + border.Child = grid; + return border; + } + + private Border GetUserChatBorder(MessageListItem msg) + { + Border border = new Border(); + border.Margin = new Thickness(8, 12, 8, 12); + border.BorderThickness = new Thickness(0); + // border.Background = Brushes.DarkSeaGreen; + Grid grid = new Grid(); + Image icon = new Image() + { + Source = LocalResource.ReadImageByResource("LinkToolAddin.resource.img.user.png"), + Stretch = Stretch.Fill, + HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Top + }; + grid.ColumnDefinitions.Add(new ColumnDefinition(){Width = new GridLength(1, GridUnitType.Star)}); + grid.ColumnDefinitions.Add(new ColumnDefinition(){Width = new GridLength(24, GridUnitType.Pixel)}); + TextBox textBox = new TextBox(); + grid.Children.Add(icon); + grid.Children.Add(textBox); + Grid.SetColumn(icon, 1); + Grid.SetColumn(textBox, 0); + textBox.Background = Brushes.Transparent; + textBox.Text = msg.content; + textBox.TextWrapping = TextWrapping.Wrap; + border.Child = grid; + return border; + } + + private Border GetToolChatBorder(MessageListItem msg) + { + Border border = new Border(); + border.Margin = new Thickness(24); + border.Padding = new Thickness(8); + border.BorderThickness = new Thickness(1); + border.BorderBrush = Brushes.Gray; + // border.Background = Brushes.DarkSeaGreen; + Grid grid = new Grid(); + Image icon = new Image() + { + Source = LocalResource.ReadImageByResource("LinkToolAddin.resource.img.tool.png"), + Stretch = Stretch.Fill, + HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center + }; + icon.Margin = new Thickness(0, 0, 8, 0); + grid.ColumnDefinitions.Add(new ColumnDefinition(){Width = new GridLength(24, GridUnitType.Pixel)}); + grid.ColumnDefinitions.Add(new ColumnDefinition(){Width = new GridLength(1, GridUnitType.Star)}); + TextBlock textBlock = new TextBlock(); + textBlock.Text = (msg as ToolMessageItem).toolName; + textBlock.TextWrapping = TextWrapping.Wrap; + grid.Children.Add(icon); + grid.Children.Add(textBlock); + Grid.SetColumn(icon, 0); + Grid.SetColumn(textBlock, 1); + border.Child = grid; + return border; + } + + private void TestButton_OnClick(object sender, RoutedEventArgs e) + { + long timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); + MessageListItem toolMessageItem = new ToolMessageItem + { + toolName = "toolName", + toolParams = new Dictionary(), + type = MessageType.TOOL_MESSAGE, + status = "success", + content = "JsonConvert.SerializeObject(toolResponse)", + id = (timestamp + 1).ToString(), + role = "user" + }; + NewMessage_Recall(toolMessageItem); + } } } diff --git a/ui/dockpane/DialogDockpaneViewModel.cs b/ui/dockpane/DialogDockpaneViewModel.cs index 1d7a4e5..42258fc 100644 --- a/ui/dockpane/DialogDockpaneViewModel.cs +++ b/ui/dockpane/DialogDockpaneViewModel.cs @@ -14,6 +14,7 @@ using ArcGIS.Desktop.Layouts; using ArcGIS.Desktop.Mapping; using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -27,8 +28,14 @@ namespace LinkToolAddin.ui.dockpane internal class DialogDockpaneViewModel : DockPane { private const string _dockPaneID = "DialogDockpane"; + + public ObservableCollection Items { get; set; } - protected DialogDockpaneViewModel() { } + protected DialogDockpaneViewModel() + { + Items = new ObservableCollection(); + Items.Add(new ItemModel(){Content = "adfdfdafdfs"}); + } /// /// Show the DockPane. From 35054ee7c0bc5505ac6724d1e4bd4aa0da09b91e Mon Sep 17 00:00:00 2001 From: PeterZhong Date: Tue, 3 Jun 2025 22:41:03 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E5=89=8D=E7=AB=AFUI=E6=8E=A8=E7=90=86?= =?UTF-8?q?=E3=80=81=E5=B7=A5=E5=85=B7=E3=80=81=E6=B6=88=E6=81=AF=E7=9A=84?= =?UTF-8?q?=E5=9F=BA=E7=A1=80=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LinkToolAddin.csproj | 8 ++ host/Gateway.cs | 87 ++++++++---- resource/img/fold.png | Bin 0 -> 261 bytes resource/img/unfold.png | Bin 0 -> 962 bytes ui/VersionButton.cs | 2 +- ui/dockpane/DialogDockpane.xaml | 20 ++- ui/dockpane/DialogDockpane.xaml.cs | 217 +++++++++++++++++++++++++++-- ui/message/MessageListItem.cs | 1 + 8 files changed, 295 insertions(+), 40 deletions(-) create mode 100644 resource/img/fold.png create mode 100644 resource/img/unfold.png diff --git a/LinkToolAddin.csproj b/LinkToolAddin.csproj index d764cc6..bece90c 100644 --- a/LinkToolAddin.csproj +++ b/LinkToolAddin.csproj @@ -132,6 +132,14 @@ Always + + + Always + + + + Always + diff --git a/host/Gateway.cs b/host/Gateway.cs index 63ef2b2..a2af774 100644 --- a/host/Gateway.cs +++ b/host/Gateway.cs @@ -282,12 +282,28 @@ public class Gateway { //如果本次回复不包含任何工具的调用或提示词的调用,则不再请求 goOn = false; + MessageListItem endMessageListItem1 = new ChatMessageItem + { + type = MessageType.END_TAG, + content = "", + id = (timestamp+3).ToString(), + role = "assistant" + }; + callback?.Invoke(endMessageListItem1); break; } await foreach(LlmStreamChat llmStreamChat in bailian.SendChatStreamAsync(jsonContent)) { if (!goOn) { + MessageListItem endMessageListItem2 = new ChatMessageItem + { + type = MessageType.END_TAG, + content = "", + id = (timestamp+3).ToString(), + role = "assistant" + }; + callback?.Invoke(endMessageListItem2); break; } @@ -299,7 +315,7 @@ public class Gateway content = llmStreamChat.Choices[0].Delta.ResoningContent, role = "assistant", type = MessageType.REASON_MESSAGE, - id = (timestamp-1).ToString() + id = (timestamp+2).ToString() }; Application.Current.Dispatcher.Invoke(() => { @@ -328,17 +344,14 @@ public class Gateway else { //包含Prompt调用请求的消息 - if (remainingPrompt != "") + MessageListItem chatMessageListItem = new ChatMessageItem() { - MessageListItem chatMessageListItem = new ChatMessageItem() - { - content = remainingPrompt, - role = "assistant", - type = MessageType.CHAT_MESSAGE, - id = timestamp.ToString() - }; - callback?.Invoke(chatMessageListItem); - } + content = remainingPrompt, + role = "assistant", + type = MessageType.CHAT_MESSAGE, + id = timestamp.ToString() + }; + callback?.Invoke(chatMessageListItem); XElement promptUse = XElement.Parse(matchedPrompt); string promptKey = promptUse.Element("name")?.Value; string promptArgs = promptUse.Element("arguments")?.Value; @@ -355,20 +368,6 @@ public class Gateway else { //包含工具调用请求的消息 - if (remaining != "") - { - MessageListItem chatMessageListItem = new ChatMessageItem() - { - content = remaining, - role = "assistant", - type = MessageType.CHAT_MESSAGE, - id = timestamp.ToString() - }; - Application.Current.Dispatcher.Invoke(() => - { - callback?.Invoke(chatMessageListItem); - }); - } XElement toolUse = XElement.Parse(matched); string fullToolName = toolUse.Element("name")?.Value; string toolArgs = toolUse.Element("arguments")?.Value; @@ -377,6 +376,32 @@ public class Gateway string toolName = fullToolName.Contains(":") ? fullToolName.Split(':')[1] : fullToolName; McpServer mcpServer = mcpServerList.GetServer(serverName); //将工具调用请求添加至列表中待一次回答完整后再统一进行调用 + MessageListItem chatMessageListItem = new ChatMessageItem() + { + content = remaining, + role = "assistant", + type = MessageType.CHAT_MESSAGE, + id = timestamp.ToString() + }; + Application.Current.Dispatcher.Invoke(() => + { + callback?.Invoke(chatMessageListItem); + }); + MessageListItem toolMessageListItem = new ToolMessageItem() + { + content = "", + result = "", + toolName = toolName, + toolParams = toolParams, + role = "user", + type = MessageType.TOOL_MESSAGE, + id = (timestamp+1).ToString(), + status = "loading" + }; + Application.Current.Dispatcher.Invoke(() => + { + callback?.Invoke(toolMessageListItem); + }); mcpToolRequests = new List(); McpToolRequest mcpToolRequest = new McpToolRequest() { @@ -421,6 +446,7 @@ public class Gateway type = MessageType.TOOL_MESSAGE, status = toolResponse.IsError ? "fail" : "success", content = JsonConvert.SerializeObject(toolResponse), + result = JsonConvert.SerializeObject(toolResponse), id = (timestamp + 1).ToString(), role = "user" }; @@ -448,6 +474,7 @@ public class Gateway type = MessageType.TOOL_MESSAGE, status = toolResponse.IsError ? "fail" : "success", content = JsonConvert.SerializeObject(toolResponse), + result = JsonConvert.SerializeObject(toolResponse), id = (timestamp + 1).ToString(), role = "user" }; @@ -494,6 +521,7 @@ public class Gateway type = MessageType.TOOL_MESSAGE, status = "fail", content = JsonConvert.SerializeObject(innerResult), + result = JsonConvert.SerializeObject(innerResult), id = (timestamp + 1).ToString(), role = "user" }; @@ -516,6 +544,7 @@ public class Gateway type = MessageType.TOOL_MESSAGE, status = "success", content = JsonConvert.SerializeObject(innerResult), + result = JsonConvert.SerializeObject(innerResult), id = (timestamp + 1).ToString(), role = "user" }; @@ -569,6 +598,14 @@ public class Gateway log.Error(e.Message); } } + MessageListItem endMessageListItem = new ChatMessageItem + { + type = MessageType.END_TAG, + content = "", + id = (timestamp+3).ToString(), + role = "assistant" + }; + callback?.Invoke(endMessageListItem); } } diff --git a/resource/img/fold.png b/resource/img/fold.png new file mode 100644 index 0000000000000000000000000000000000000000..2690b192bcf51f476621b77dcbd4d32880b546d5 GIT binary patch literal 261 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}`#oJ8Ln7SY zPCdxmY{27cKYNPr3pLq;iz}KpdAe&Z4q4aJqSPcCzoVw_$g}-6?kR`Po-Zl3<8WX$ z0V7RjrB55Yy+gOZd75fF^OwMZ!}}R@{z%qdd3~QjjG;J0p6N!P>k)=Chg4mJ_pN*- zBYB!B;>UBYMM8N6nhe`7w6195XZ)fN^U?0}ly8qCF0p-6yZ^ROX4@Bg`I$4frzc4~ zIMT9LtChch!BX*w)Bnp~d$HyFHE*_6iRra03mByqG|C5Ycq!(&XLJI+!r!lvI6;>1s;*b3=DjSL74G){)!X^2By`SArU1JzCKpT`MG+DDfvmMdKI|^K-CNk zHue<-iOJciB??KY>6v-9>hE{&S69ePu~iQ@^)>JLw)`r|23QrX=bnrWhOQrWhNin420}7^N8|DZw0= zTL8B{uNWE%!0^zoNG#Ad)H47%80aM{=c3falKi5O{QMj{-^}Eq{Nnty5{2;0yp;U% zVugT={E~cyu*}r*)FK5#13d#hBQrw-13g0v3nLqSbp2ohlOYC{kZT~aej9yI5FiB! zB#@B=C<>#J%rrzCp#&001{O*nwv~TTW-2hIK+$4nXrqrIhQ*~|w*%9I9WbC^sRxvl z;3+UQ518!Af$6I}WaAcK+Fao2;usR){&wm?UM52x7Iv+juUV`b`C_`P7l^!I@p?FU z@`R&@%O1^t{&LQi$y5Csmu1fKbV=E~nM2+BgHhA`18i?r{n~iH!s2!#yYM_NI}Y;? z>VIbKwGC{%`p|_%>k#L=1D^`^Few$S<~Xh$;F-dHZ*i-5LHyOG=mw?E2@I@4iHu_2 zOQr>ce*fqm)6j0)KOyVEgXNuHl1 - + + + + + + + + + + + + + - + - + - + diff --git a/ui/dockpane/DialogDockpane.xaml.cs b/ui/dockpane/DialogDockpane.xaml.cs index 1148b88..d11083d 100644 --- a/ui/dockpane/DialogDockpane.xaml.cs +++ b/ui/dockpane/DialogDockpane.xaml.cs @@ -117,13 +117,17 @@ namespace LinkToolAddin.ui.dockpane QuestionTextbox.Text = ""; borderItemsDict[timestamp.ToString()] = userMsgBoder; ChatHistoryStackPanel.Children.Add(userMsgBoder); - Gateway.SendMessageStream(question,"qwen-max",defaultGdbPath,NewMessage_Recall); + Gateway.SendMessageStream(question,"qwen3-235b-a22b",defaultGdbPath,NewMessage_Recall); } public void NewMessage_Recall(MessageListItem msg) { string msgId = msg.id; log.Info(msg.content); + double verticalOffset = ScrollViewer.VerticalOffset; + double viewportHeight = ScrollViewer.ViewportHeight; + double contentHeight = ChatHistoryStackPanel.ActualHeight; + double tolerance = 24; if (!idList.Contains(msgId)) { //不存在该消息,需添加到ListView中 @@ -147,17 +151,32 @@ namespace LinkToolAddin.ui.dockpane ChatHistoryStackPanel.Children.Add(border); } } - else + else if(msg.role == "assistant") { - Border border = GetAiChatBorder(msg); - borderItemsDict[msgId] = border; - ChatHistoryStackPanel.Children.Add(border); + if (msg.type == MessageType.REASON_MESSAGE) + { + Border border = GetAiReasonBorder(msg); + borderItemsDict[msgId] = border; + ChatHistoryStackPanel.Children.Add(border); + }else if (msg.type == MessageType.CHAT_MESSAGE) + { + Border border = GetAiChatBorder(msg); + borderItemsDict[msgId] = border; + ChatHistoryStackPanel.Children.Add(border); + } } } else { //已有该消息,只需要修改内容 messageDict[msgId] = msg; + if (msg.content == "") + { + ChatHistoryStackPanel.Children.Remove(borderItemsDict[msgId]); + borderItemsDict.TryRemove(msgId, out Border border); + messageDict.TryRemove(msgId, out MessageListItem tempMsg); + idList.Remove(msgId); + } if (msg.role == "user") { if (msg.type == MessageType.TOOL_MESSAGE) @@ -166,22 +185,42 @@ namespace LinkToolAddin.ui.dockpane Grid grid = borderItem.Child as Grid; TextBlock textBlock = grid.Children[1] as TextBlock; textBlock.Text = (msg as ToolMessageItem).toolName; + StatusTextBlock.Text = "正在执行工具"; }else if (msg.type == MessageType.CHAT_MESSAGE) { Border borderItem = borderItemsDict[msgId]; Grid grid = borderItem.Child as Grid; TextBox textBox = grid.Children[1] as TextBox; textBox.Text = msg.content; + StatusTextBlock.Text = "正在读取用户输入"; } } else { - Border borderItem = borderItemsDict[msgId]; - Grid grid = borderItem.Child as Grid; - TextBox textBox = grid.Children[1] as TextBox; - textBox.Text = msg.content; + if (msg.type == MessageType.REASON_MESSAGE) + { + Border borderItem = borderItemsDict[msgId]; + Grid grid = borderItem.Child as Grid; + TextBox textBox = grid.Children[0] as TextBox; + textBox.Text = msg.content; + StatusTextBlock.Text = "深度思考中"; + }else if (msg.type == MessageType.CHAT_MESSAGE) + { + Border borderItem = borderItemsDict[msgId]; + Grid grid = borderItem.Child as Grid; + TextBox textBox = grid.Children[1] as TextBox; + textBox.Text = msg.content; + StatusTextBlock.Text = "回答生成中"; + }else if (msg.type == MessageType.END_TAG) + { + StatusTextBlock.Text = ""; + } } } + if (Math.Abs(verticalOffset + viewportHeight - contentHeight) < tolerance) + { + ScrollViewer.ScrollToBottom(); + } } private Border GetAiChatBorder(MessageListItem msg) @@ -204,6 +243,8 @@ namespace LinkToolAddin.ui.dockpane grid.Children.Add(textBox); Grid.SetColumn(icon, 0); Grid.SetColumn(textBox, 1); + textBox.IsReadOnly = true; + textBox.BorderThickness = new Thickness(0); textBox.Background = Brushes.Transparent; textBox.Text = msg.content; textBox.TextWrapping = TextWrapping.Wrap; @@ -211,6 +252,105 @@ namespace LinkToolAddin.ui.dockpane return border; } + private Border GetAiReasonBorder(MessageListItem msg) + { + Border border = new Border(); + border.Margin = new Thickness(8, 12, 8, 12); + border.BorderThickness = new Thickness(0); + // border.Background = Brushes.DarkSeaGreen; + Grid grid = new Grid(); + Image icon = new Image() + { + Source = LocalResource.ReadImageByResource("LinkToolAddin.resource.img.linktool.png"), + Stretch = Stretch.Fill, + HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Top + }; + Image fold = new Image() + { + Source = LocalResource.ReadImageByResource("LinkToolAddin.resource.img.fold.png"), + Stretch = Stretch.Fill, + HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Top + }; + Image unfold = new Image() + { + Source = LocalResource.ReadImageByResource("LinkToolAddin.resource.img.unfold.png"), + Stretch = Stretch.Fill, + HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Top + }; + grid.ColumnDefinitions.Add(new ColumnDefinition(){Width = new GridLength(24, GridUnitType.Pixel)}); + grid.ColumnDefinitions.Add(new ColumnDefinition(){Width = new GridLength(1, GridUnitType.Star)}); + grid.ColumnDefinitions.Add(new ColumnDefinition(){Width = new GridLength(16, GridUnitType.Pixel)}); + TextBox textBox = new TextBox(); + // grid.Children.Add(icon); + grid.Children.Add(textBox); + // Grid.SetColumn(icon, 0); + Grid.SetColumn(textBox, 1); + textBox.IsReadOnly = true; + textBox.Foreground = Brushes.Gray; + textBox.BorderThickness = new Thickness(2,0,0,0); + textBox.BorderBrush = Brushes.Gray; + textBox.Background = Brushes.Transparent; + textBox.Text = msg.content; + textBox.TextWrapping = TextWrapping.Wrap; + Button button = new Button(); + StackPanel panel = new StackPanel(); + panel.Orientation = Orientation.Horizontal; + panel.Children.Add(fold); + button.Content = panel; + button.BorderThickness = new Thickness(0); + button.Background = Brushes.Transparent; + button.Width = 16; + button.Height = 16; + button.Padding = new Thickness(0); + button.HorizontalAlignment = HorizontalAlignment.Center; + button.VerticalAlignment = VerticalAlignment.Top; + button.Tag = "fold"; + button.Click += FoldButton_OnClick; + Grid.SetColumn(button, 2); + grid.Children.Add(button); + border.Child = grid; + return border; + } + + private void FoldButton_OnClick(object sender, RoutedEventArgs e) + { + Button button = sender as Button; + string tag = button.Tag.ToString(); + if (tag == "fold") + { + button.Tag = "unfold"; + Grid grid = button.Parent as Grid; + TextBox textBox = grid.Children[0] as TextBox; + textBox.Visibility = Visibility.Collapsed; + StackPanel stackPanel = button.Content as StackPanel; + Image unfold = new Image() + { + Source = LocalResource.ReadImageByResource("LinkToolAddin.resource.img.unfold.png"), + Stretch = Stretch.Fill, + HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Top + }; + stackPanel.Children.Clear(); + stackPanel.Children.Add(unfold); + } + else + { + button.Tag = "fold"; + Image fold = new Image() + { + Source = LocalResource.ReadImageByResource("LinkToolAddin.resource.img.fold.png"), + Stretch = Stretch.Fill, + HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Top + }; + Grid grid = button.Parent as Grid; + TextBox textBox = grid.Children[0] as TextBox; + textBox.Visibility = Visibility.Visible; + StackPanel stackPanel = button.Content as StackPanel; + stackPanel.Children.Clear(); + stackPanel.Children.Add(fold); + } + + } + private Border GetUserChatBorder(MessageListItem msg) { Border border = new Border(); @@ -227,11 +367,14 @@ namespace LinkToolAddin.ui.dockpane grid.ColumnDefinitions.Add(new ColumnDefinition(){Width = new GridLength(1, GridUnitType.Star)}); grid.ColumnDefinitions.Add(new ColumnDefinition(){Width = new GridLength(24, GridUnitType.Pixel)}); TextBox textBox = new TextBox(); + textBox.HorizontalAlignment = HorizontalAlignment.Right; grid.Children.Add(icon); grid.Children.Add(textBox); Grid.SetColumn(icon, 1); Grid.SetColumn(textBox, 0); textBox.Background = Brushes.Transparent; + textBox.IsReadOnly = true; + textBox.BorderThickness = new Thickness(0); textBox.Text = msg.content; textBox.TextWrapping = TextWrapping.Wrap; border.Child = grid; @@ -245,6 +388,7 @@ namespace LinkToolAddin.ui.dockpane border.Padding = new Thickness(8); border.BorderThickness = new Thickness(1); border.BorderBrush = Brushes.Gray; + border.CornerRadius = new CornerRadius(3); // border.Background = Brushes.DarkSeaGreen; Grid grid = new Grid(); Image icon = new Image() @@ -256,17 +400,46 @@ namespace LinkToolAddin.ui.dockpane icon.Margin = new Thickness(0, 0, 8, 0); grid.ColumnDefinitions.Add(new ColumnDefinition(){Width = new GridLength(24, GridUnitType.Pixel)}); grid.ColumnDefinitions.Add(new ColumnDefinition(){Width = new GridLength(1, GridUnitType.Star)}); + grid.ColumnDefinitions.Add(new ColumnDefinition(){Width = new GridLength(36, GridUnitType.Pixel)}); + grid.ColumnDefinitions.Add(new ColumnDefinition(){Width = new GridLength(36, GridUnitType.Pixel)}); TextBlock textBlock = new TextBlock(); - textBlock.Text = (msg as ToolMessageItem).toolName; + ToolMessageItem toolMsg = msg as ToolMessageItem; + textBlock.Text = toolMsg.toolName + " | " + toolMsg.status; textBlock.TextWrapping = TextWrapping.Wrap; grid.Children.Add(icon); grid.Children.Add(textBlock); Grid.SetColumn(icon, 0); Grid.SetColumn(textBlock, 1); + Button argsButton = new Button(); + argsButton.Content = "参数"; + argsButton.Tag = msg as ToolMessageItem; + argsButton.Click += ToolArgsButton_OnClick; border.Child = grid; + Button resButton = new Button(); + resButton.Content = "结果"; + resButton.Tag = msg as ToolMessageItem; + resButton.Click += ToolResButton_OnClick; + grid.Children.Add(argsButton); + Grid.SetColumn(argsButton, 2); + grid.Children.Add(resButton); + Grid.SetColumn(resButton, 3); return border; } + private void ToolArgsButton_OnClick(object sender, RoutedEventArgs e) + { + Button button = sender as Button; + ToolMessageItem toolItem = button.Tag as ToolMessageItem; + ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show(JsonConvert.SerializeObject(toolItem.toolParams),toolItem.toolName+"工具参数"); + } + + private void ToolResButton_OnClick(object sender, RoutedEventArgs e) + { + Button button = sender as Button; + ToolMessageItem toolItem = button.Tag as ToolMessageItem; + ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show(toolItem.result,toolItem.toolName+"运行结果"); + } + private void TestButton_OnClick(object sender, RoutedEventArgs e) { long timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); @@ -282,5 +455,29 @@ namespace LinkToolAddin.ui.dockpane }; NewMessage_Recall(toolMessageItem); } + + private void ClearButton_OnClick(object sender, RoutedEventArgs e) + { + idList.Clear(); + messageDict.Clear(); + borderItemsDict.Clear(); + ChatHistoryStackPanel.Children.Clear(); + QuestionTextbox.Clear(); + } + + private void TopButton_OnClick(object sender, RoutedEventArgs e) + { + ScrollViewer.ScrollToTop(); + } + + private void BottomButton_OnClick(object sender, RoutedEventArgs e) + { + ScrollViewer.ScrollToBottom(); + } + + private void StopButton_OnClick(object sender, RoutedEventArgs e) + { + Gateway.StopConversation(); + } } } diff --git a/ui/message/MessageListItem.cs b/ui/message/MessageListItem.cs index 9b97709..3b0ce37 100644 --- a/ui/message/MessageListItem.cs +++ b/ui/message/MessageListItem.cs @@ -5,6 +5,7 @@ public enum MessageType TOOL_MESSAGE, CHAT_MESSAGE, REASON_MESSAGE, + END_TAG } public interface MessageListItem From 3b9005381a6bd8524330db56e4012472dfa99417 Mon Sep 17 00:00:00 2001 From: PeterZhong Date: Wed, 4 Jun 2025 16:14:43 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=80=82=E9=85=8D?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=E8=AF=8D=E5=8D=A1=E7=89=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- host/Gateway.cs | 3 ++- ui/dockpane/DialogDockpane.xaml.cs | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/host/Gateway.cs b/host/Gateway.cs index a2af774..78889e8 100644 --- a/host/Gateway.cs +++ b/host/Gateway.cs @@ -585,7 +585,8 @@ public class Gateway type = MessageType.TOOL_MESSAGE, status = "success", content = "成功调用提示词:"+promptRequest.PromptName, - id = (timestamp+1).ToString() + id = (timestamp+1).ToString(), + result = "成功调用提示词:"+promptRequest.PromptName }; Application.Current.Dispatcher.Invoke(() => { diff --git a/ui/dockpane/DialogDockpane.xaml.cs b/ui/dockpane/DialogDockpane.xaml.cs index d11083d..3e623ae 100644 --- a/ui/dockpane/DialogDockpane.xaml.cs +++ b/ui/dockpane/DialogDockpane.xaml.cs @@ -144,11 +144,13 @@ namespace LinkToolAddin.ui.dockpane Border border = GetToolChatBorder(msg); borderItemsDict[msgId] = border; ChatHistoryStackPanel.Children.Add(border); + StatusTextBlock.Text = "正在执行工具"; }else if (msg.type == MessageType.CHAT_MESSAGE) { Border border = GetUserChatBorder(msg); borderItemsDict[msgId] = border; ChatHistoryStackPanel.Children.Add(border); + StatusTextBlock.Text = "正在读取用户输入"; } } else if(msg.role == "assistant") @@ -158,11 +160,16 @@ namespace LinkToolAddin.ui.dockpane Border border = GetAiReasonBorder(msg); borderItemsDict[msgId] = border; ChatHistoryStackPanel.Children.Add(border); + StatusTextBlock.Text = "深度思考中"; }else if (msg.type == MessageType.CHAT_MESSAGE) { Border border = GetAiChatBorder(msg); borderItemsDict[msgId] = border; ChatHistoryStackPanel.Children.Add(border); + StatusTextBlock.Text = "回答生成中"; + }else if (msg.type == MessageType.END_TAG) + { + StatusTextBlock.Text = ""; } } } @@ -463,6 +470,7 @@ namespace LinkToolAddin.ui.dockpane borderItemsDict.Clear(); ChatHistoryStackPanel.Children.Clear(); QuestionTextbox.Clear(); + StatusTextBlock.Text = ""; } private void TopButton_OnClick(object sender, RoutedEventArgs e) @@ -478,6 +486,7 @@ namespace LinkToolAddin.ui.dockpane private void StopButton_OnClick(object sender, RoutedEventArgs e) { Gateway.StopConversation(); + StatusTextBlock.Text = ""; } } }