Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 514d02d4d4 | |||
| 93f185dc3b | |||
| 468d13b9d1 | |||
| f7326491d7 | |||
| 157eb29a82 | |||
| 4cd81dfc2e | |||
| 9b1f479425 | |||
| 0a4ed9ee6b | |||
| ca807080b6 | |||
| 2a80940879 | |||
| ab78de8078 | |||
| 805293e80f |
2
.gitignore
vendored
2
.gitignore
vendored
@ -7,7 +7,7 @@
|
|||||||
./vs/
|
./vs/
|
||||||
./bin/
|
./bin/
|
||||||
./obj/
|
./obj/
|
||||||
./Properties/launchSettings.json
|
./Properties/
|
||||||
*.sln.iml
|
*.sln.iml
|
||||||
*.DotSettings
|
*.DotSettings
|
||||||
*.dotCover
|
*.dotCover
|
||||||
|
|||||||
@ -26,6 +26,7 @@
|
|||||||
<button refID="DialogDockpane_ShowButton" size="large" />
|
<button refID="DialogDockpane_ShowButton" size="large" />
|
||||||
<button refID="Version_Button" size="large" />
|
<button refID="Version_Button" size="large" />
|
||||||
<button refID="LinkToolAddin_ui_dockpane_TestDockpane_ShowButton" size="large" />
|
<button refID="LinkToolAddin_ui_dockpane_TestDockpane_ShowButton" size="large" />
|
||||||
|
<button refID="LinkToolAddin_ui_mcp_McpConfigWindow" size="large" />
|
||||||
</group>
|
</group>
|
||||||
<group id="PreferenceGroup" caption="设置项" appearsOnAddInTab="false">
|
<group id="PreferenceGroup" caption="设置项" appearsOnAddInTab="false">
|
||||||
<button refID="Preference_Button" size="large" />
|
<button refID="Preference_Button" size="large" />
|
||||||
@ -44,6 +45,9 @@
|
|||||||
<button id="LinkToolAddin_ui_dockpane_TestDockpane_ShowButton" caption="测试面板" className="LinkToolAddin.ui.dockpane.TestDockpane_ShowButton" loadOnClick="true" smallImage="GenericButtonPurple16" largeImage="GenericButtonPurple32">
|
<button id="LinkToolAddin_ui_dockpane_TestDockpane_ShowButton" caption="测试面板" className="LinkToolAddin.ui.dockpane.TestDockpane_ShowButton" loadOnClick="true" smallImage="GenericButtonPurple16" largeImage="GenericButtonPurple32">
|
||||||
<tooltip heading="测试面板">打开测试面板<disabledText /></tooltip>
|
<tooltip heading="测试面板">打开测试面板<disabledText /></tooltip>
|
||||||
</button>
|
</button>
|
||||||
|
<button id="LinkToolAddin_ui_mcp_McpConfigWindow" caption="McpConfigWindow" className="LinkToolAddin.ui.mcp.ShowMcpConfigWindow" loadOnClick="true" smallImage="GenericButtonPurple16" largeImage="GenericButtonPurple32">
|
||||||
|
<tooltip heading="Tooltip Heading">Tooltip text<disabledText /></tooltip>
|
||||||
|
</button>
|
||||||
</controls>
|
</controls>
|
||||||
<dockPanes>
|
<dockPanes>
|
||||||
<dockPane id="DialogDockpane" caption="LinkTool" className="LinkToolAddin.ui.dockpane.DialogDockpaneViewModel" dock="group" dockWith="esri_core_projectDockPane">
|
<dockPane id="DialogDockpane" caption="LinkTool" className="LinkToolAddin.ui.dockpane.DialogDockpaneViewModel" dock="group" dockWith="esri_core_projectDockPane">
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
"profiles": {
|
"profiles": {
|
||||||
"LinkToolAddin": {
|
"LinkToolAddin": {
|
||||||
"commandName": "Executable",
|
"commandName": "Executable",
|
||||||
"executablePath": "C:\\Users\\86158\\AppData\\Local\\Programs\\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"
|
||||||
|
|||||||
@ -137,8 +137,8 @@ public class ArcGisPro
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
[McpServerTool, Description("获取要素类的属性表内容,可以查看属性表中的至多前20条记录的内容")]
|
[McpServerTool, Description("获取要素类的属性表内容,可以查看属性表中的至多前20条记录的内容,传入Where子句筛选特定数据,例如“OBJECTID > 10”")]
|
||||||
public static async Task<JsonRpcResultEntity> GetFeatureDatasetAttributeTable(string datasetPath, string dataName, string rowsLimit)
|
public static async Task<JsonRpcResultEntity> GetFeatureDatasetAttributeTable(string datasetPath, string dataName, string whereClause)
|
||||||
{
|
{
|
||||||
JsonRpcResultEntity result = new JsonRpcResultEntity();
|
JsonRpcResultEntity result = new JsonRpcResultEntity();
|
||||||
await QueuedTask.Run(async () =>
|
await QueuedTask.Run(async () =>
|
||||||
@ -147,7 +147,7 @@ public class ArcGisPro
|
|||||||
{
|
{
|
||||||
using Geodatabase gdb = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(datasetPath)));
|
using Geodatabase gdb = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(datasetPath)));
|
||||||
FeatureClass featureClass = gdb.OpenDataset<FeatureClass>(dataName);
|
FeatureClass featureClass = gdb.OpenDataset<FeatureClass>(dataName);
|
||||||
List<Dictionary<string, string>> attributeTable = await GetAttributeTableAsync(featureClass,Convert.ToInt32(rowsLimit));
|
List<Dictionary<string, string>> attributeTable = await GetAttributeTableAsync(featureClass,whereClause);
|
||||||
result = new JsonRpcSuccessEntity()
|
result = new JsonRpcSuccessEntity()
|
||||||
{
|
{
|
||||||
Id = 1,
|
Id = 1,
|
||||||
@ -170,15 +170,15 @@ public class ArcGisPro
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<List<Dictionary<string, string>>> GetAttributeTableAsync(FeatureClass featureClass,int limit = 5)
|
private static async Task<List<Dictionary<string, string>>> GetAttributeTableAsync(FeatureClass featureClass,String whereClause)
|
||||||
{
|
{
|
||||||
if (limit > 20)
|
int limit = 20;
|
||||||
limit = 20;
|
|
||||||
return await QueuedTask.Run(() =>
|
return await QueuedTask.Run(() =>
|
||||||
{
|
{
|
||||||
var result = new List<Dictionary<string, string>>();
|
var result = new List<Dictionary<string, string>>();
|
||||||
|
QueryFilter queryFilter = new QueryFilter();
|
||||||
using (var cursor = featureClass.Search())
|
queryFilter.WhereClause = whereClause;
|
||||||
|
using (var cursor = featureClass.Search(queryFilter))
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (cursor.MoveNext())
|
while (cursor.MoveNext())
|
||||||
@ -198,7 +198,10 @@ public class ArcGisPro
|
|||||||
|
|
||||||
// 处理 DBNull 值
|
// 处理 DBNull 值
|
||||||
if (value is DBNull)
|
if (value is DBNull)
|
||||||
value = null;
|
value = "";
|
||||||
|
|
||||||
|
if (value == null)
|
||||||
|
value = "";
|
||||||
|
|
||||||
record[field.Name] = value.ToString();
|
record[field.Name] = value.ToString();
|
||||||
}
|
}
|
||||||
|
|||||||
379
host/Gateway.cs
379
host/Gateway.cs
@ -43,175 +43,19 @@ public class Gateway
|
|||||||
{
|
{
|
||||||
private static ILog log = LogManager.GetLogger(typeof(Gateway));
|
private static ILog log = LogManager.GetLogger(typeof(Gateway));
|
||||||
private static bool goOn = true;
|
private static bool goOn = true;
|
||||||
|
private static DialogDockpaneView dockpaneView = null;
|
||||||
|
|
||||||
|
public static void SetDockpaneView(DialogDockpaneView view)
|
||||||
|
{
|
||||||
|
dockpaneView = view;
|
||||||
|
}
|
||||||
|
|
||||||
public static void StopConversation()
|
public static void StopConversation()
|
||||||
{
|
{
|
||||||
goOn = false;
|
goOn = false;
|
||||||
}
|
if (dockpaneView != null)
|
||||||
|
|
||||||
public static async void SendMessage(string message, string model, string gdbPath, Action<MessageListItem> callback)
|
|
||||||
{
|
|
||||||
Llm bailian = new Bailian
|
|
||||||
{
|
{
|
||||||
api_key = "sk-db177155677e438f832860e7f4da6afc"
|
dockpaneView.hideProgressBar();
|
||||||
};
|
|
||||||
List<Message> messages = new List<Message>();
|
|
||||||
string toolInfos = await GetToolInfos(new McpServerList());
|
|
||||||
log.Info(SystemPrompt.SysPrompt(gdbPath, toolInfos));
|
|
||||||
messages.Add(new Message
|
|
||||||
{
|
|
||||||
Role = "system",
|
|
||||||
Content = SystemPrompt.SysPrompt(gdbPath, toolInfos)
|
|
||||||
});
|
|
||||||
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>$";
|
|
||||||
McpServerList mcpServerList = new McpServerList();
|
|
||||||
while (goOn)
|
|
||||||
{
|
|
||||||
string reponse = await bailian.SendChatAsync(new LlmJsonContent()
|
|
||||||
{
|
|
||||||
Model = model,
|
|
||||||
Messages = messages,
|
|
||||||
Temperature = 0.3,
|
|
||||||
TopP = 0.6,
|
|
||||||
TopK = 25,
|
|
||||||
MaxTokens = 1024,
|
|
||||||
ThinkingBudget = 1024
|
|
||||||
});
|
|
||||||
long timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
|
||||||
log.Info(reponse);
|
|
||||||
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 = mcpServerList.GetServer(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 = JsonConvert.SerializeObject(toolResponse),
|
|
||||||
id = timestamp.ToString()
|
|
||||||
};
|
|
||||||
messages.Add(new Message
|
|
||||||
{
|
|
||||||
Role = "user",
|
|
||||||
Content = toolResponse.IsError ? SystemPrompt.ErrorPrompt(JsonConvert.SerializeObject(toolResponse)) : SystemPrompt.ContinuePrompt(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 = JsonConvert.SerializeObject(toolResponse),
|
|
||||||
id = timestamp.ToString()
|
|
||||||
};
|
|
||||||
messages.Add(new Message
|
|
||||||
{
|
|
||||||
Role = "user",
|
|
||||||
Content = toolResponse.IsError ? SystemPrompt.ErrorPrompt(JsonConvert.SerializeObject(toolResponse)) : SystemPrompt.ContinuePrompt(JsonConvert.SerializeObject(toolResponse))
|
|
||||||
});
|
|
||||||
callback?.Invoke(toolMessageItem);
|
|
||||||
}else if (mcpServer is InnerMcpServer)
|
|
||||||
{
|
|
||||||
Type type = Type.GetType("LinkToolAddin.client.tool."+serverName);
|
|
||||||
MethodInfo method = type.GetMethod(toolName,BindingFlags.Public | BindingFlags.Static);
|
|
||||||
var task = method.Invoke(null, toolParams.Values.ToArray()) as Task<JsonRpcResultEntity>;
|
|
||||||
JsonRpcResultEntity innerResult = await task;
|
|
||||||
if (innerResult is JsonRpcErrorEntity)
|
|
||||||
{
|
|
||||||
MessageListItem toolMessageItem = new ToolMessageItem
|
|
||||||
{
|
|
||||||
toolName = toolName,
|
|
||||||
toolParams = toolParams,
|
|
||||||
type = MessageType.TOOL_MESSAGE,
|
|
||||||
status = "fail",
|
|
||||||
content = JsonConvert.SerializeObject(innerResult)
|
|
||||||
};
|
|
||||||
messages.Add(new Message
|
|
||||||
{
|
|
||||||
Role = "user",
|
|
||||||
Content = SystemPrompt.ErrorPrompt(JsonConvert.SerializeObject(innerResult))
|
|
||||||
});
|
|
||||||
callback?.Invoke(toolMessageItem);
|
|
||||||
}else if (innerResult is JsonRpcSuccessEntity)
|
|
||||||
{
|
|
||||||
MessageListItem toolMessageItem = new ToolMessageItem
|
|
||||||
{
|
|
||||||
toolName = toolName,
|
|
||||||
toolParams = toolParams,
|
|
||||||
type = MessageType.TOOL_MESSAGE,
|
|
||||||
status = "success",
|
|
||||||
content = JsonConvert.SerializeObject(innerResult)
|
|
||||||
};
|
|
||||||
messages.Add(new Message
|
|
||||||
{
|
|
||||||
Role = "user",
|
|
||||||
Content = SystemPrompt.ContinuePrompt(JsonConvert.SerializeObject(innerResult))
|
|
||||||
});
|
|
||||||
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, null);
|
|
||||||
messages.Add(new Message
|
|
||||||
{
|
|
||||||
Role = "user",
|
|
||||||
Content = promptRes
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MessageListItem chatMessageListItem = new ChatMessageItem()
|
|
||||||
{
|
|
||||||
content = reponse,
|
|
||||||
role = "assistant",
|
|
||||||
type = MessageType.CHAT_MESSAGE,
|
|
||||||
id = timestamp.ToString()
|
|
||||||
};
|
|
||||||
callback?.Invoke(chatMessageListItem);
|
|
||||||
}
|
|
||||||
if (reponse.EndsWith("[DONE]"))
|
|
||||||
{
|
|
||||||
goOn = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,33 +80,81 @@ public class Gateway
|
|||||||
return (matched, remaining);
|
return (matched, remaining);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async void SendMessageStream(string message, string model, string gdbPath, Action<MessageListItem> callback)
|
public static async void SendMessageStream(string message, string model, string gdbPath, List<Message> historyMessages, Action<MessageListItem,List< Message>> callback)
|
||||||
{
|
{
|
||||||
Llm bailian = new Bailian
|
Llm modelObj = new Bailian();
|
||||||
{
|
List<string> bailianModels = ["Moonshot-Kimi-K2-Instruct","deepseek-r1","deepseek-v3","qwen3-235b-a22b","qwen3-32b","qwen-plus","qwen-turbo","abab6.5s-chat"];
|
||||||
api_key = "sk-db177155677e438f832860e7f4da6afc"
|
List<string> dmxModels = ["grok-3-mini","o4-mini","claude-3-5-haiku-20241022","claude-sonnet-4-20250514-thinking","claude-3-7-sonnet-20250219-thinking","grok-4-ssvip","gemini-2.5-pro-ssvip","gemini-2.5-flash-ssvip","o3-pro","gpt-4.1","gpt-4o"];
|
||||||
};
|
List<Message> messages = null;
|
||||||
List<Message> messages = new List<Message>();
|
|
||||||
string toolInfos = "";
|
string toolInfos = "";
|
||||||
try
|
if (historyMessages.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
toolInfos = await GetToolInfos(new McpServerList());
|
messages = new List<Message>();
|
||||||
messages.Add(new Message
|
try
|
||||||
{
|
{
|
||||||
Role = "system",
|
toolInfos = await GetToolInfos(new McpServerList(),messages,callback);
|
||||||
Content = SystemPrompt.SysPrompt(gdbPath, toolInfos)
|
messages.Add(new Message
|
||||||
});
|
{
|
||||||
messages.Add(new Message
|
Role = "system",
|
||||||
|
Content = SystemPrompt.SysPrompt(gdbPath, toolInfos)
|
||||||
|
});
|
||||||
|
}catch (Exception ex)
|
||||||
{
|
{
|
||||||
Role = "user",
|
log.Error(ex);
|
||||||
Content = message
|
MessageListItem endMessageListItem2 = new ChatMessageItem
|
||||||
});
|
{
|
||||||
}catch (Exception ex)
|
type = MessageType.WARNING,
|
||||||
{
|
content = $"MCP列表读取失败{ex.Message}",
|
||||||
log.Error(ex);
|
id = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString(),
|
||||||
MessageBox.Show(ex.Message,"获取MCP列表失败");
|
role = "system",
|
||||||
|
};
|
||||||
|
callback?.Invoke(endMessageListItem2,messages);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
messages = historyMessages;
|
||||||
|
}
|
||||||
|
if (bailianModels.Contains(model))
|
||||||
|
{
|
||||||
|
modelObj = new Bailian
|
||||||
|
{
|
||||||
|
api_key = "sk-db177155677e438f832860e7f4da6afc"
|
||||||
|
};
|
||||||
|
}else if (dmxModels.Contains(model))
|
||||||
|
{
|
||||||
|
modelObj = new DmxApi
|
||||||
|
{
|
||||||
|
api_key = "sk-VQeuLUmhO1LL8H97tFj5kuWOqGFD4CFRmAsdqhxkmkYxUUlP"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MessageListItem endMessageListItem2 = new ChatMessageItem
|
||||||
|
{
|
||||||
|
type = MessageType.ERROR,
|
||||||
|
content = $"目前暂未支持{model}模型,请选择其他模型。",
|
||||||
|
id = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString(),
|
||||||
|
role = "system"
|
||||||
|
};
|
||||||
|
callback?.Invoke(endMessageListItem2,messages);
|
||||||
|
MessageListItem endMessageListItem1 = new ChatMessageItem
|
||||||
|
{
|
||||||
|
type = MessageType.END_TAG,
|
||||||
|
content = "",
|
||||||
|
id = (DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + 3).ToString(),
|
||||||
|
role = "assistant"
|
||||||
|
};
|
||||||
|
callback?.Invoke(endMessageListItem1,messages);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
messages.Add(new Message
|
||||||
|
{
|
||||||
|
Role = "user",
|
||||||
|
Content = message
|
||||||
|
});
|
||||||
goOn = true;
|
goOn = true;
|
||||||
|
long accTokens = 0;
|
||||||
string toolPattern = "<tool_use>([\\s\\S]*?)<name>([\\s\\S]*?)<\\/name>([\\s\\S]*?)<arguments>([\\s\\S]*?)<\\/arguments>([\\s\\S]*?)<\\/tool_use>";
|
string toolPattern = "<tool_use>([\\s\\S]*?)<name>([\\s\\S]*?)<\\/name>([\\s\\S]*?)<arguments>([\\s\\S]*?)<\\/arguments>([\\s\\S]*?)<\\/tool_use>";
|
||||||
string promptPattern = "<prompt>([\\s\\S]*?)<name>([\\s\\S]*?)<\\/name>([\\s\\S]*?)<arguments>([\\s\\S]*?)<\\/arguments>([\\s\\S]*?)<\\/prompt>";
|
string promptPattern = "<prompt>([\\s\\S]*?)<name>([\\s\\S]*?)<\\/name>([\\s\\S]*?)<arguments>([\\s\\S]*?)<\\/arguments>([\\s\\S]*?)<\\/prompt>";
|
||||||
McpServerList mcpServerList = new McpServerList();
|
McpServerList mcpServerList = new McpServerList();
|
||||||
@ -273,10 +165,35 @@ public class Gateway
|
|||||||
bool executedTool = false;
|
bool executedTool = false;
|
||||||
while (goOn)
|
while (goOn)
|
||||||
{
|
{
|
||||||
|
long timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||||
loop++;
|
loop++;
|
||||||
if (loop > 500)
|
if (loop > 500)
|
||||||
{
|
{
|
||||||
MessageBox.Show("达到最大循环次数", "退出循环");
|
MessageListItem endMessageListItem2 = new ChatMessageItem
|
||||||
|
{
|
||||||
|
type = MessageType.ERROR,
|
||||||
|
content = "达到最大循环次数,已退出循环。",
|
||||||
|
id = timestamp.ToString(),
|
||||||
|
role = "system"
|
||||||
|
};
|
||||||
|
callback?.Invoke(endMessageListItem2,messages);
|
||||||
|
MessageListItem endMessageListItem1 = new ChatMessageItem
|
||||||
|
{
|
||||||
|
type = MessageType.END_TAG,
|
||||||
|
content = "",
|
||||||
|
id = (timestamp + 3).ToString(),
|
||||||
|
role = "assistant"
|
||||||
|
};
|
||||||
|
callback?.Invoke(endMessageListItem1,messages);
|
||||||
|
// MessageBox.Show("达到最大循环次数", "退出循环");
|
||||||
|
MessageListItem endAllMsgItem = new ChatMessageItem
|
||||||
|
{
|
||||||
|
type = MessageType.END_ALL,
|
||||||
|
content = "",
|
||||||
|
id = (timestamp + 4).ToString(),
|
||||||
|
role = "assistant"
|
||||||
|
};
|
||||||
|
callback?.Invoke(endAllMsgItem,messages);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
LlmJsonContent jsonContent = new LlmJsonContent()
|
LlmJsonContent jsonContent = new LlmJsonContent()
|
||||||
@ -285,10 +202,8 @@ public class Gateway
|
|||||||
Messages = messages,
|
Messages = messages,
|
||||||
Temperature = 0.3,
|
Temperature = 0.3,
|
||||||
TopP = 0.4,
|
TopP = 0.4,
|
||||||
TopK = 7,
|
|
||||||
MaxTokens = 1000,
|
MaxTokens = 1000,
|
||||||
};
|
};
|
||||||
long timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
|
||||||
List<McpToolRequest> mcpToolRequests = new List<McpToolRequest>();
|
List<McpToolRequest> mcpToolRequests = new List<McpToolRequest>();
|
||||||
List<PromptRequest> promptRequests = new List<PromptRequest>();
|
List<PromptRequest> promptRequests = new List<PromptRequest>();
|
||||||
var (toolMatched, toolRemaining) = ExtractMatchedPart(messageContent, toolPattern);
|
var (toolMatched, toolRemaining) = ExtractMatchedPart(messageContent, toolPattern);
|
||||||
@ -304,13 +219,21 @@ public class Gateway
|
|||||||
id = (timestamp + 3).ToString(),
|
id = (timestamp + 3).ToString(),
|
||||||
role = "assistant"
|
role = "assistant"
|
||||||
};
|
};
|
||||||
callback?.Invoke(endMessageListItem1);
|
callback?.Invoke(endMessageListItem1,messages);
|
||||||
|
MessageListItem endAllMsgItem = new ChatMessageItem
|
||||||
|
{
|
||||||
|
type = MessageType.END_ALL,
|
||||||
|
content = "",
|
||||||
|
id = (timestamp + 4).ToString(),
|
||||||
|
role = "assistant"
|
||||||
|
};
|
||||||
|
callback?.Invoke(endAllMsgItem,messages);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await foreach(LlmStreamChat llmStreamChat in bailian.SendChatStreamAsync(jsonContent))
|
await foreach(LlmStreamChat llmStreamChat in modelObj.SendChatStreamAsync(jsonContent))
|
||||||
{
|
{
|
||||||
if (!goOn)
|
if (!goOn)
|
||||||
{
|
{
|
||||||
@ -321,7 +244,15 @@ public class Gateway
|
|||||||
id = (timestamp+3).ToString(),
|
id = (timestamp+3).ToString(),
|
||||||
role = "assistant"
|
role = "assistant"
|
||||||
};
|
};
|
||||||
callback?.Invoke(endMessageListItem2);
|
callback?.Invoke(endMessageListItem2,messages);
|
||||||
|
MessageListItem endAllMsgItem = new ChatMessageItem
|
||||||
|
{
|
||||||
|
type = MessageType.END_ALL,
|
||||||
|
content = "",
|
||||||
|
id = (timestamp + 4).ToString(),
|
||||||
|
role = "assistant"
|
||||||
|
};
|
||||||
|
callback?.Invoke(endAllMsgItem,messages);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
@ -336,7 +267,7 @@ public class Gateway
|
|||||||
};
|
};
|
||||||
Application.Current.Dispatcher.Invoke(() =>
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
callback?.Invoke(reasonMessageListItem);
|
callback?.Invoke(reasonMessageListItem,messages);
|
||||||
});
|
});
|
||||||
messageContent = chunk;
|
messageContent = chunk;
|
||||||
var (matched, remaining) = ExtractMatchedPart(chunk, toolPattern);
|
var (matched, remaining) = ExtractMatchedPart(chunk, toolPattern);
|
||||||
@ -355,7 +286,7 @@ public class Gateway
|
|||||||
};
|
};
|
||||||
Application.Current.Dispatcher.Invoke(() =>
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
callback?.Invoke(chatMessageListItem);
|
callback?.Invoke(chatMessageListItem,messages);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -368,7 +299,7 @@ public class Gateway
|
|||||||
type = MessageType.CHAT_MESSAGE,
|
type = MessageType.CHAT_MESSAGE,
|
||||||
id = timestamp.ToString()
|
id = timestamp.ToString()
|
||||||
};
|
};
|
||||||
callback?.Invoke(chatMessageListItem);
|
callback?.Invoke(chatMessageListItem,messages);
|
||||||
XElement promptUse = XElement.Parse(matchedPrompt);
|
XElement promptUse = XElement.Parse(matchedPrompt);
|
||||||
string promptKey = promptUse.Element("name")?.Value;
|
string promptKey = promptUse.Element("name")?.Value;
|
||||||
string promptArgs = promptUse.Element("arguments")?.Value;
|
string promptArgs = promptUse.Element("arguments")?.Value;
|
||||||
@ -402,7 +333,7 @@ public class Gateway
|
|||||||
};
|
};
|
||||||
Application.Current.Dispatcher.Invoke(() =>
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
callback?.Invoke(chatMessageListItem);
|
callback?.Invoke(chatMessageListItem,messages);
|
||||||
});
|
});
|
||||||
if (!executedTool)
|
if (!executedTool)
|
||||||
{
|
{
|
||||||
@ -419,7 +350,7 @@ public class Gateway
|
|||||||
};
|
};
|
||||||
Application.Current.Dispatcher.Invoke(() =>
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
callback?.Invoke(toolMessageListItem);
|
callback?.Invoke(toolMessageListItem,messages);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
mcpToolRequests = new List<McpToolRequest>();
|
mcpToolRequests = new List<McpToolRequest>();
|
||||||
@ -441,7 +372,32 @@ public class Gateway
|
|||||||
}catch (Exception e)
|
}catch (Exception e)
|
||||||
{
|
{
|
||||||
log.Error(e.Message);
|
log.Error(e.Message);
|
||||||
MessageBox.Show(e.Message, "请求大模型出错");
|
MessageListItem endMessageListItem2 = new ChatMessageItem
|
||||||
|
{
|
||||||
|
type = MessageType.ERROR,
|
||||||
|
content = $"请求大模型出错:{e.Message}",
|
||||||
|
id = timestamp.ToString(),
|
||||||
|
role = "system"
|
||||||
|
};
|
||||||
|
callback?.Invoke(endMessageListItem2,messages);
|
||||||
|
MessageListItem endMessageListItem1 = new ChatMessageItem
|
||||||
|
{
|
||||||
|
type = MessageType.END_TAG,
|
||||||
|
content = "",
|
||||||
|
id = (timestamp + 3).ToString(),
|
||||||
|
role = "assistant"
|
||||||
|
};
|
||||||
|
callback?.Invoke(endMessageListItem1,messages);
|
||||||
|
// MessageBox.Show(e.Message, "请求大模型出错");
|
||||||
|
MessageListItem endAllMsgItem = new ChatMessageItem
|
||||||
|
{
|
||||||
|
type = MessageType.END_ALL,
|
||||||
|
content = "",
|
||||||
|
id = (timestamp + 4).ToString(),
|
||||||
|
role = "assistant"
|
||||||
|
};
|
||||||
|
callback?.Invoke(endAllMsgItem,messages);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (messageContent != "")
|
if (messageContent != "")
|
||||||
{
|
{
|
||||||
@ -485,7 +441,7 @@ public class Gateway
|
|||||||
});
|
});
|
||||||
Application.Current.Dispatcher.Invoke(() =>
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
callback?.Invoke(toolMessageItem1);
|
callback?.Invoke(toolMessageItem1,messages);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (mcpServer is StdioMcpServer)
|
else if (mcpServer is StdioMcpServer)
|
||||||
@ -513,7 +469,7 @@ public class Gateway
|
|||||||
});
|
});
|
||||||
Application.Current.Dispatcher.Invoke(() =>
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
callback?.Invoke(toolMessageItem1);
|
callback?.Invoke(toolMessageItem1,messages);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (mcpServer is InnerMcpServer)
|
else if (mcpServer is InnerMcpServer)
|
||||||
@ -544,7 +500,7 @@ public class Gateway
|
|||||||
});
|
});
|
||||||
Application.Current.Dispatcher.Invoke(() =>
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
callback?.Invoke(toolMessageItem);
|
callback?.Invoke(toolMessageItem,messages);
|
||||||
});
|
});
|
||||||
queriedKnowledge = true;
|
queriedKnowledge = true;
|
||||||
}
|
}
|
||||||
@ -569,7 +525,7 @@ public class Gateway
|
|||||||
});
|
});
|
||||||
Application.Current.Dispatcher.Invoke(() =>
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
callback?.Invoke(toolMessageItem);
|
callback?.Invoke(toolMessageItem,messages);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@ -620,7 +576,7 @@ public class Gateway
|
|||||||
});
|
});
|
||||||
Application.Current.Dispatcher.Invoke(() =>
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
callback?.Invoke(toolMessageItem1);
|
callback?.Invoke(toolMessageItem1,messages);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (innerResult is JsonRpcSuccessEntity)
|
else if (innerResult is JsonRpcSuccessEntity)
|
||||||
@ -643,7 +599,7 @@ public class Gateway
|
|||||||
});
|
});
|
||||||
Application.Current.Dispatcher.Invoke(() =>
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
callback?.Invoke(toolMessageItem1);
|
callback?.Invoke(toolMessageItem1,messages);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -679,7 +635,7 @@ public class Gateway
|
|||||||
};
|
};
|
||||||
Application.Current.Dispatcher.Invoke(() =>
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
callback?.Invoke(toolMessageItem);
|
callback?.Invoke(toolMessageItem,messages);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -695,12 +651,13 @@ public class Gateway
|
|||||||
id = (timestamp+3).ToString(),
|
id = (timestamp+3).ToString(),
|
||||||
role = "assistant"
|
role = "assistant"
|
||||||
};
|
};
|
||||||
callback?.Invoke(endMessageListItem);
|
callback?.Invoke(endMessageListItem,messages);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<string> GetToolInfos(McpServerList mcpServerList)
|
private static async Task<string> GetToolInfos(McpServerList mcpServerList,List<Message> historyMessages,Action<MessageListItem,List<Message>> callback)
|
||||||
{
|
{
|
||||||
|
long timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||||
StringBuilder toolInfos = new StringBuilder();
|
StringBuilder toolInfos = new StringBuilder();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
List<int> failedMcp = new List<int>();
|
List<int> failedMcp = new List<int>();
|
||||||
@ -784,7 +741,7 @@ public class Gateway
|
|||||||
{
|
{
|
||||||
log.Error(e.Message);
|
log.Error(e.Message);
|
||||||
failedMcp.Add(i);
|
failedMcp.Add(i);
|
||||||
failedMcpString.Add(mcpServerList.GetAllServerNames()[i]);
|
failedMcpString.Add(mcpServerList.GetAllServerNames()[i-1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -805,7 +762,15 @@ public class Gateway
|
|||||||
|
|
||||||
if (!failedMcp.IsNullOrEmpty())
|
if (!failedMcp.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
MessageBox.Show($"读取失败的MCP服务有:{JsonConvert.SerializeObject(failedMcpString)}","MCP读取错误");
|
MessageListItem endMessageListItem2 = new ChatMessageItem
|
||||||
|
{
|
||||||
|
type = MessageType.WARNING,
|
||||||
|
content = $"读取失败的MCP服务有:{JsonConvert.SerializeObject(failedMcpString)}",
|
||||||
|
id = (timestamp-2).ToString(),
|
||||||
|
role = "system"
|
||||||
|
};
|
||||||
|
callback?.Invoke(endMessageListItem2,historyMessages);
|
||||||
|
// MessageBox.Show($"读取失败的MCP服务有:{JsonConvert.SerializeObject(failedMcpString)}","MCP读取错误");
|
||||||
}
|
}
|
||||||
return toolInfos.ToString();
|
return toolInfos.ToString();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using LinkToolAddin.host.mcp;
|
using LinkToolAddin.host.mcp;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace LinkToolAddin.host;
|
namespace LinkToolAddin.host;
|
||||||
|
|
||||||
@ -36,53 +37,58 @@ public class McpServerList
|
|||||||
// "有地理信息的相关案例步骤参考以及Arcgis Pro的工具详细信息",
|
// "有地理信息的相关案例步骤参考以及Arcgis Pro的工具详细信息",
|
||||||
IsActive = true
|
IsActive = true
|
||||||
});
|
});
|
||||||
//servers.Add("filesystem", new StdioMcpServer()
|
servers.Add("filesystem", new StdioMcpServer()
|
||||||
//{
|
{
|
||||||
// Name = "filesystem",
|
Name = "filesystem",
|
||||||
// Type = "stdio",
|
Type = "stdio",
|
||||||
// Command = "npx",
|
Command = "npx",
|
||||||
// Args = new List<string>()
|
Args = new List<string>()
|
||||||
// {
|
{
|
||||||
// "-y",
|
"-y",
|
||||||
// "@modelcontextprotocol/server-filesystem",
|
"@modelcontextprotocol/server-filesystem",
|
||||||
// "F:\\secondsemester\\linktool\\test\\LinkTool0607\\LinkTool0607.gdb"
|
"F:\\secondsemester\\linktool\\test\\LinkTool0607\\LinkTool0607.gdb"
|
||||||
// }
|
}
|
||||||
//});
|
});
|
||||||
//servers.Add("fetch", new StdioMcpServer()
|
// servers.Add("fetch", new StdioMcpServer()
|
||||||
//{
|
// {
|
||||||
// Name = "fetch",
|
// Name = "fetch",
|
||||||
// Type = "stdio",
|
// Type = "stdio",
|
||||||
// Command = "uvx",
|
// Command = "uvx",
|
||||||
// Args = new List<string>()
|
// Args = new List<string>()
|
||||||
// {
|
// {
|
||||||
// "mcp-server-fetch"
|
// "mcp-server-fetch"
|
||||||
// }
|
// }
|
||||||
//});
|
// });
|
||||||
//servers.Add("bing-search", new StdioMcpServer()
|
// servers.Add("bing-search", new StdioMcpServer()
|
||||||
//{
|
// {
|
||||||
// Name = "bing-search",
|
// Name = "bing-search",
|
||||||
// Type = "stdio",
|
// Type = "stdio",
|
||||||
// Command = "npx",
|
// Command = "npx",
|
||||||
// Args = new List<string>()
|
// Args = new List<string>()
|
||||||
// {
|
// {
|
||||||
// "bing-cn-mcp"
|
// "bing-cn-mcp"
|
||||||
// }
|
// }
|
||||||
//});
|
// });
|
||||||
//servers.Add("mcp-python-interpreter", new StdioMcpServer()
|
// servers.Add("mcp-python-interpreter", new StdioMcpServer()
|
||||||
//{
|
// {
|
||||||
// Name = "mcp-python-interpreter",
|
// Name = "mcp-python-interpreter",
|
||||||
// Type = "stdio",
|
// Type = "stdio",
|
||||||
// Command = "uvx",
|
// Command = "uvx",
|
||||||
// Args = new List<string>()
|
// Args = new List<string>()
|
||||||
// {
|
// {
|
||||||
// "--native-tls",
|
// "--native-tls",
|
||||||
// "mcp-python-interpreter",
|
// "mcp-python-interpreter",
|
||||||
// "--dir",
|
// "--dir",
|
||||||
// "F:\\secondsemester\\linktool\\test\\LinkTool0607\\LinkTool0607.gdb",
|
// "F:\\secondsemester\\linktool\\test\\LinkTool0607\\LinkTool0607.gdb",
|
||||||
// "--python-path",
|
// "--python-path",
|
||||||
// "C:\\Program Files\\ArcGIS\\Pro\\bin\\Python\\envs\\custom\\python.exe"
|
// "C:\\Program Files\\ArcGIS\\Pro\\bin\\Python\\envs\\custom\\python.exe"
|
||||||
// }
|
// }
|
||||||
//});
|
// });
|
||||||
|
}
|
||||||
|
|
||||||
|
public McpServerList(string json)
|
||||||
|
{
|
||||||
|
servers = JsonConvert.DeserializeObject<Dictionary<string, McpServer>>(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
public McpServer GetServer(string name)
|
public McpServer GetServer(string name)
|
||||||
|
|||||||
52
host/llm/DmxApi.cs
Normal file
52
host/llm/DmxApi.cs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using LinkToolAddin.common;
|
||||||
|
using LinkToolAddin.host.llm.entity;
|
||||||
|
using LinkToolAddin.host.llm.entity.stream;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace LinkToolAddin.host.llm;
|
||||||
|
|
||||||
|
public class DmxApi : Llm
|
||||||
|
{
|
||||||
|
public string model { get; set; } = "gpt-4o";
|
||||||
|
public string temperature { get; set; }
|
||||||
|
public string top_p { get; set; }
|
||||||
|
public string max_tokens { get; set; }
|
||||||
|
public string app_id { get; set; }
|
||||||
|
public string api_key { get; set; }
|
||||||
|
public async IAsyncEnumerable<LlmStreamChat> SendChatStreamAsync(LlmJsonContent jsonContent)
|
||||||
|
{
|
||||||
|
jsonContent.Stream = true;
|
||||||
|
StringBuilder contentBuilder = new StringBuilder();
|
||||||
|
StringBuilder reasonBuilder = new StringBuilder();
|
||||||
|
await foreach (LlmStreamChat chunk in HttpRequest.PostWithStreamingResponseAsync(
|
||||||
|
"https://www.dmxapi.cn/v1/chat/completions",
|
||||||
|
JsonConvert.SerializeObject(jsonContent),
|
||||||
|
api_key))
|
||||||
|
{
|
||||||
|
contentBuilder.Append(chunk.Choices[0].Delta.Content);
|
||||||
|
reasonBuilder.Append(chunk.Choices[0].Delta.ResoningContent);
|
||||||
|
LlmStreamChat fullChunk = chunk;
|
||||||
|
fullChunk.Choices[0].Delta.Content = contentBuilder.ToString();
|
||||||
|
fullChunk.Choices[0].Delta.ResoningContent = reasonBuilder.ToString();
|
||||||
|
yield return fullChunk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IAsyncEnumerable<string> SendApplicationStreamAsync(string message)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<string> SendChatAsync(LlmJsonContent jsonContent)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<string> SendApplicationAsync(CommonInput commonInput)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -24,7 +24,7 @@ namespace LinkToolAddin.host.llm.entity
|
|||||||
public int MaxTokens { get; set; } = 2048;
|
public int MaxTokens { get; set; } = 2048;
|
||||||
|
|
||||||
[JsonProperty("top_k")]
|
[JsonProperty("top_k")]
|
||||||
public int TopK { get; set; } = 40;
|
public int TopK { get; set; }
|
||||||
|
|
||||||
[JsonProperty("enable_thinking")]
|
[JsonProperty("enable_thinking")]
|
||||||
public bool EnableThinking { get; set; } = true;
|
public bool EnableThinking { get; set; } = true;
|
||||||
|
|||||||
@ -23,7 +23,7 @@
|
|||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
<RowDefinition Height="24"/>
|
<RowDefinition Height="24"/>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="24"/>
|
<RowDefinition Height="16"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid Grid.Row="0" HorizontalAlignment="Center">
|
<Grid Grid.Row="0" HorizontalAlignment="Center">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
@ -40,13 +40,15 @@
|
|||||||
<ComboBox Grid.Column="4" Name="ModelComboBox" SelectionChanged="ModelComboBox_OnSelectionChanged">
|
<ComboBox Grid.Column="4" Name="ModelComboBox" SelectionChanged="ModelComboBox_OnSelectionChanged">
|
||||||
<ComboBoxItem Content="qwen3-235b-a22b" IsSelected="True"/>
|
<ComboBoxItem Content="qwen3-235b-a22b" IsSelected="True"/>
|
||||||
<ComboBoxItem Content="qwen3-32b" />
|
<ComboBoxItem Content="qwen3-32b" />
|
||||||
<ComboBoxItem Content="qwq-32b" />
|
|
||||||
<ComboBoxItem Content="qwen-max-latest" />
|
|
||||||
<ComboBoxItem Content="deepseek-r1" />
|
<ComboBoxItem Content="deepseek-r1" />
|
||||||
<ComboBoxItem Content="deepseek-r1-0528" />
|
|
||||||
<ComboBoxItem Content="deepseek-r1-distill-qwen-32b" />
|
|
||||||
<ComboBoxItem Content="deepseek-r1-distill-llama-70b" />
|
|
||||||
<ComboBoxItem Content="deepseek-v3" />
|
<ComboBoxItem Content="deepseek-v3" />
|
||||||
|
<ComboBoxItem Content="Moonshot-Kimi-K2-Instruct" />
|
||||||
|
<Separator></Separator>
|
||||||
|
<ComboBoxItem Content="grok-3-mini" />
|
||||||
|
<ComboBoxItem Content="o4-mini" />
|
||||||
|
<ComboBoxItem Content="claude-3-5-haiku-20241022" />
|
||||||
|
<ComboBoxItem Content="gemini-2.5-flash-ssvip" />
|
||||||
|
<Separator></Separator>
|
||||||
<ComboBoxItem Content="自定义" />
|
<ComboBoxItem Content="自定义" />
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
</Grid>
|
</Grid>
|
||||||
@ -61,8 +63,14 @@
|
|||||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||||
<ColumnDefinition Width="48"></ColumnDefinition>
|
<ColumnDefinition Width="48"></ColumnDefinition>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<TextBox Grid.Column="0" Name="QuestionTextbox" Text="这是用户的问题" TextWrapping="Wrap"></TextBox>
|
<TextBox Grid.Column="0" Name="QuestionTextbox" Text="" TextWrapping="Wrap" AcceptsReturn="True" VerticalScrollBarVisibility="Auto" PreviewKeyDown="QuestionTextbox_OnPreviewKeyDown"></TextBox>
|
||||||
<Button Grid.Column="1" Name="SendButton" Content="发送" Click="SendButton_OnClick"></Button>
|
<Button Grid.Column="1" Name="SendButton" Content="发送" Click="SendButton_OnClick"></Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
<ProgressBar x:Name="IndeterminateProgressBar"
|
||||||
|
Grid.Row="4"
|
||||||
|
Margin="3"
|
||||||
|
Height="16"
|
||||||
|
IsIndeterminate="True"
|
||||||
|
Visibility="Hidden"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -2,8 +2,10 @@ using System;
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Collections.Specialized;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
@ -14,6 +16,7 @@ using Microsoft.Extensions.Logging;
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Windows.Documents;
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using ArcGIS.Desktop.Core;
|
using ArcGIS.Desktop.Core;
|
||||||
using ArcGIS.Desktop.Core.Geoprocessing;
|
using ArcGIS.Desktop.Core.Geoprocessing;
|
||||||
@ -33,6 +36,7 @@ using ModelContextProtocol.Client;
|
|||||||
using ModelContextProtocol.Protocol.Types;
|
using ModelContextProtocol.Protocol.Types;
|
||||||
using ModelContextProtocol.Server;
|
using ModelContextProtocol.Server;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
namespace LinkToolAddin.ui.dockpane
|
namespace LinkToolAddin.ui.dockpane
|
||||||
{
|
{
|
||||||
@ -50,12 +54,14 @@ namespace LinkToolAddin.ui.dockpane
|
|||||||
private List<string> idList = new List<string>();
|
private List<string> idList = new List<string>();
|
||||||
private ConcurrentDictionary<string,MessageListItem> messageDict = new ConcurrentDictionary<string,MessageListItem>();
|
private ConcurrentDictionary<string,MessageListItem> messageDict = new ConcurrentDictionary<string,MessageListItem>();
|
||||||
private ConcurrentDictionary<string,Border> borderItemsDict = new ConcurrentDictionary<string,Border>();
|
private ConcurrentDictionary<string,Border> borderItemsDict = new ConcurrentDictionary<string,Border>();
|
||||||
|
private List<Message> historyMessages = new List<Message>();
|
||||||
|
|
||||||
public DialogDockpaneView()
|
public DialogDockpaneView()
|
||||||
{
|
{
|
||||||
InitLogger();
|
InitLogger();
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
DataContext = this;
|
DataContext = this;
|
||||||
|
Gateway.SetDockpaneView(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void TestServer_OnClick(object sender, RoutedEventArgs e)
|
private async void TestServer_OnClick(object sender, RoutedEventArgs e)
|
||||||
@ -100,6 +106,8 @@ namespace LinkToolAddin.ui.dockpane
|
|||||||
|
|
||||||
private void SendButton_OnClick(object sender, RoutedEventArgs e)
|
private void SendButton_OnClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
|
StatusTextBlock.Text = "正在读取用户输入和工具列表";
|
||||||
|
IndeterminateProgressBar.Visibility = Visibility.Visible;
|
||||||
string question = QuestionTextbox.Text;
|
string question = QuestionTextbox.Text;
|
||||||
string defaultGdbPath = Project.Current.DefaultGeodatabasePath;
|
string defaultGdbPath = Project.Current.DefaultGeodatabasePath;
|
||||||
string gdbPath = @"";
|
string gdbPath = @"";
|
||||||
@ -123,7 +131,12 @@ namespace LinkToolAddin.ui.dockpane
|
|||||||
model = ShowInputBox("自定义模型", "请输入模型名称:", "");
|
model = ShowInputBox("自定义模型", "请输入模型名称:", "");
|
||||||
}
|
}
|
||||||
ScrollViewer.ScrollToBottom();
|
ScrollViewer.ScrollToBottom();
|
||||||
Gateway.SendMessageStream(question,model,defaultGdbPath,NewMessage_Recall);
|
Gateway.SendMessageStream(question,model,defaultGdbPath,historyMessages,NewMessage_Recall);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void hideProgressBar()
|
||||||
|
{
|
||||||
|
IndeterminateProgressBar.Visibility = Visibility.Hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ShowInputBox(string title, string message, string defaultValue = "")
|
private string ShowInputBox(string title, string message, string defaultValue = "")
|
||||||
@ -166,7 +179,13 @@ namespace LinkToolAddin.ui.dockpane
|
|||||||
return textBox.Text;
|
return textBox.Text;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void NewMessage_Recall(MessageListItem msg)
|
public void NewMessage_Recall(MessageListItem msg, List<Message> historyMessages)
|
||||||
|
{
|
||||||
|
this.historyMessages = historyMessages;
|
||||||
|
NewMessage_Recall(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NewMessage_Recall(MessageListItem msg)
|
||||||
{
|
{
|
||||||
string msgId = msg.id;
|
string msgId = msg.id;
|
||||||
log.Info(msg.content);
|
log.Info(msg.content);
|
||||||
@ -182,6 +201,10 @@ namespace LinkToolAddin.ui.dockpane
|
|||||||
if (msg.type == MessageType.END_TAG)
|
if (msg.type == MessageType.END_TAG)
|
||||||
{
|
{
|
||||||
StatusTextBlock.Text = "";
|
StatusTextBlock.Text = "";
|
||||||
|
}else if (msg.type == MessageType.END_ALL)
|
||||||
|
{
|
||||||
|
StatusTextBlock.Text = "";
|
||||||
|
IndeterminateProgressBar.Visibility = Visibility.Hidden;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -223,7 +246,16 @@ namespace LinkToolAddin.ui.dockpane
|
|||||||
{
|
{
|
||||||
if (msg.type == MessageType.WARNING)
|
if (msg.type == MessageType.WARNING)
|
||||||
{
|
{
|
||||||
|
Border border = GetWarningChatBorder(msg);
|
||||||
|
borderItemsDict[msgId] = border;
|
||||||
|
ChatHistoryStackPanel.Children.Add(border);
|
||||||
|
StatusTextBlock.Text = "出现警告信息";
|
||||||
|
}else if (msg.type == MessageType.ERROR)
|
||||||
|
{
|
||||||
|
Border border = GetErrorChatBorder(msg);
|
||||||
|
borderItemsDict[msgId] = border;
|
||||||
|
ChatHistoryStackPanel.Children.Add(border);
|
||||||
|
StatusTextBlock.Text = "出现错误信息";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -236,6 +268,10 @@ namespace LinkToolAddin.ui.dockpane
|
|||||||
if (msg.type == MessageType.END_TAG)
|
if (msg.type == MessageType.END_TAG)
|
||||||
{
|
{
|
||||||
StatusTextBlock.Text = "";
|
StatusTextBlock.Text = "";
|
||||||
|
}else if (msg.type == MessageType.END_ALL)
|
||||||
|
{
|
||||||
|
StatusTextBlock.Text = "";
|
||||||
|
IndeterminateProgressBar.Visibility = Visibility.Hidden;
|
||||||
}
|
}
|
||||||
ChatHistoryStackPanel.Children.Remove(borderItemsDict[msgId]);
|
ChatHistoryStackPanel.Children.Remove(borderItemsDict[msgId]);
|
||||||
borderItemsDict.TryRemove(msgId, out Border border);
|
borderItemsDict.TryRemove(msgId, out Border border);
|
||||||
@ -263,7 +299,7 @@ namespace LinkToolAddin.ui.dockpane
|
|||||||
StatusTextBlock.Text = "正在读取用户输入";
|
StatusTextBlock.Text = "正在读取用户输入";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else if(msg.role == "assistant")
|
||||||
{
|
{
|
||||||
if (msg.type == MessageType.REASON_MESSAGE)
|
if (msg.type == MessageType.REASON_MESSAGE)
|
||||||
{
|
{
|
||||||
@ -280,6 +316,23 @@ namespace LinkToolAddin.ui.dockpane
|
|||||||
textBox.Text = msg.content;
|
textBox.Text = msg.content;
|
||||||
StatusTextBlock.Text = "回答生成中";
|
StatusTextBlock.Text = "回答生成中";
|
||||||
}
|
}
|
||||||
|
}else if (msg.role == "system")
|
||||||
|
{
|
||||||
|
if (msg.type == MessageType.WARNING)
|
||||||
|
{
|
||||||
|
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.ERROR)
|
||||||
|
{
|
||||||
|
Border borderItem = borderItemsDict[msgId];
|
||||||
|
Grid grid = borderItem.Child as Grid;
|
||||||
|
TextBox textBox = grid.Children[1] as TextBox;
|
||||||
|
textBox.Text = msg.content;
|
||||||
|
StatusTextBlock.Text = "出现错误信息";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Math.Abs(verticalOffset + viewportHeight - contentHeight) < tolerance)
|
if (Math.Abs(verticalOffset + viewportHeight - contentHeight) < tolerance)
|
||||||
@ -446,6 +499,66 @@ namespace LinkToolAddin.ui.dockpane
|
|||||||
return border;
|
return border;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Border GetWarningChatBorder(MessageListItem msg)
|
||||||
|
{
|
||||||
|
Border border = new Border();
|
||||||
|
border.Margin = new Thickness(24);
|
||||||
|
border.Padding = new Thickness(8);
|
||||||
|
border.BorderThickness = new Thickness(1);
|
||||||
|
border.BorderBrush = Brushes.DarkGoldenrod;
|
||||||
|
border.CornerRadius = new CornerRadius(3);
|
||||||
|
border.Background = Brushes.Moccasin;
|
||||||
|
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 ChatMessageItem).content;
|
||||||
|
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 Border GetErrorChatBorder(MessageListItem msg)
|
||||||
|
{
|
||||||
|
Border border = new Border();
|
||||||
|
border.Margin = new Thickness(24);
|
||||||
|
border.Padding = new Thickness(8);
|
||||||
|
border.BorderThickness = new Thickness(1);
|
||||||
|
border.BorderBrush = Brushes.Crimson;
|
||||||
|
border.CornerRadius = new CornerRadius(3);
|
||||||
|
border.Background = Brushes.LightPink;
|
||||||
|
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 ChatMessageItem).content;
|
||||||
|
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 Border GetToolChatBorder(MessageListItem msg)
|
private Border GetToolChatBorder(MessageListItem msg)
|
||||||
{
|
{
|
||||||
Border border = new Border();
|
Border border = new Border();
|
||||||
@ -479,18 +592,47 @@ namespace LinkToolAddin.ui.dockpane
|
|||||||
argsButton.Content = "参数";
|
argsButton.Content = "参数";
|
||||||
argsButton.Tag = msg as ToolMessageItem;
|
argsButton.Tag = msg as ToolMessageItem;
|
||||||
argsButton.Click += ToolArgsButton_OnClick;
|
argsButton.Click += ToolArgsButton_OnClick;
|
||||||
border.Child = grid;
|
|
||||||
Button resButton = new Button();
|
Button resButton = new Button();
|
||||||
resButton.Content = "结果";
|
resButton.Content = "结果";
|
||||||
resButton.Tag = msg as ToolMessageItem;
|
resButton.Tag = msg as ToolMessageItem;
|
||||||
resButton.Click += ToolResButton_OnClick;
|
resButton.Click += ToolResButton_OnClick;
|
||||||
|
|
||||||
grid.Children.Add(argsButton);
|
grid.Children.Add(argsButton);
|
||||||
Grid.SetColumn(argsButton, 2);
|
Grid.SetColumn(argsButton, 2);
|
||||||
grid.Children.Add(resButton);
|
grid.Children.Add(resButton);
|
||||||
Grid.SetColumn(resButton, 3);
|
Grid.SetColumn(resButton, 3);
|
||||||
|
|
||||||
|
if (toolMsg.toolParams.ContainsKey("toolName"))
|
||||||
|
{
|
||||||
|
grid.ColumnDefinitions.Add(new ColumnDefinition(){Width = new GridLength(36, GridUnitType.Pixel)});
|
||||||
|
Button checkButton = new Button();
|
||||||
|
checkButton.Content = "检查";
|
||||||
|
checkButton.Tag = toolMsg;
|
||||||
|
checkButton.Click += ToolCheckButton_OnClick;
|
||||||
|
grid.Children.Add(checkButton);
|
||||||
|
Grid.SetColumn(checkButton, 4);
|
||||||
|
}
|
||||||
|
border.Child = grid;
|
||||||
return border;
|
return border;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ToolCheckButton_OnClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Button button = sender as Button;
|
||||||
|
ToolMessageItem toolItem = button.Tag as ToolMessageItem;
|
||||||
|
string gisToolName = toolItem.toolParams["toolName"] as string;
|
||||||
|
JArray gisToolParams = toolItem.toolParams["toolParams"] as JArray;
|
||||||
|
List<string> gitToolParamsList = (gisToolParams as JArray).Select(token => token.ToString()).ToList();
|
||||||
|
Geoprocessing.OpenToolDialog(gisToolName,gitToolParamsList);
|
||||||
|
}catch (Exception ex)
|
||||||
|
{
|
||||||
|
log.Error(ex);
|
||||||
|
ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show(ex.Message,"打开工具失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void ToolArgsButton_OnClick(object sender, RoutedEventArgs e)
|
private void ToolArgsButton_OnClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
Button button = sender as Button;
|
Button button = sender as Button;
|
||||||
@ -528,6 +670,7 @@ namespace LinkToolAddin.ui.dockpane
|
|||||||
borderItemsDict.Clear();
|
borderItemsDict.Clear();
|
||||||
ChatHistoryStackPanel.Children.Clear();
|
ChatHistoryStackPanel.Children.Clear();
|
||||||
QuestionTextbox.Clear();
|
QuestionTextbox.Clear();
|
||||||
|
historyMessages.Clear();
|
||||||
StatusTextBlock.Text = "";
|
StatusTextBlock.Text = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -553,5 +696,43 @@ namespace LinkToolAddin.ui.dockpane
|
|||||||
string model = ModelComboBox.SelectedValue.ToString();
|
string model = ModelComboBox.SelectedValue.ToString();
|
||||||
log.Info(model);
|
log.Info(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void QuestionTextbox_OnKeyDown(object sender, KeyEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Key == Key.Enter)
|
||||||
|
{
|
||||||
|
if ((Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift)
|
||||||
|
{
|
||||||
|
// Shift + Enter: 插入换行
|
||||||
|
QuestionTextbox.SelectedText = Environment.NewLine;
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Enter: 触发发送
|
||||||
|
e.Handled = true;
|
||||||
|
SendButton_OnClick(sender, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void QuestionTextbox_OnPreviewKeyDown(object sender, KeyEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Key == Key.Enter)
|
||||||
|
{
|
||||||
|
if ((Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift)
|
||||||
|
{
|
||||||
|
// Shift + Enter: 插入换行
|
||||||
|
QuestionTextbox.SelectedText = Environment.NewLine;
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Enter: 触发发送
|
||||||
|
e.Handled = true;
|
||||||
|
SendButton_OnClick(sender, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -201,16 +201,7 @@ namespace LinkToolAddin.ui.dockpane
|
|||||||
|
|
||||||
private async void PromptTestButton_OnClick(object sender, RoutedEventArgs e)
|
private async void PromptTestButton_OnClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
string userPrompt = PromptTestTextBox.Text;
|
throw new NotImplementedException();
|
||||||
// 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)
|
public async void AddReplyStream(MessageListItem msg)
|
||||||
|
|||||||
27
ui/mcp/McpConfigWindow.xaml
Normal file
27
ui/mcp/McpConfigWindow.xaml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<controls:ProWindow x:Class="LinkToolAddin.ui.mcp.McpConfigWindow"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:controls="clr-namespace:ArcGIS.Desktop.Framework.Controls;assembly=ArcGIS.Desktop.Framework"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:extensions="clr-namespace:ArcGIS.Desktop.Extensions;assembly=ArcGIS.Desktop.Extensions"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Title="MCP服务器配置" Height="450" Width="500"
|
||||||
|
WindowStartupLocation="CenterOwner"
|
||||||
|
>
|
||||||
|
<controls:ProWindow.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<extensions:DesignOnlyResourceDictionary Source="pack://application:,,,/ArcGIS.Desktop.Framework;component\Themes\Default.xaml"/>
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
</ResourceDictionary>
|
||||||
|
</controls:ProWindow.Resources>
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*"></RowDefinition>
|
||||||
|
<RowDefinition Height="Auto"></RowDefinition>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<TextBox Grid.Row="0" Name="McpJsonTextBox" AcceptsReturn="True"></TextBox>
|
||||||
|
<Button Grid.Row="1" Name="McpJsonButton">保存</Button>
|
||||||
|
</Grid>
|
||||||
|
</controls:ProWindow>
|
||||||
71
ui/mcp/McpConfigWindow.xaml.cs
Normal file
71
ui/mcp/McpConfigWindow.xaml.cs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Navigation;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
using LinkToolAddin.host;
|
||||||
|
using LinkToolAddin.host.mcp;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Path = System.IO.Path;
|
||||||
|
|
||||||
|
namespace LinkToolAddin.ui.mcp
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for McpConfigWindow.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class McpConfigWindow : ArcGIS.Desktop.Framework.Controls.ProWindow
|
||||||
|
{
|
||||||
|
private static Dictionary<string,McpServer> servers = new Dictionary<string, McpServer>();
|
||||||
|
public McpConfigWindow()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
string mcpConfigStr = ReadMcpConfig();
|
||||||
|
McpJsonTextBox.Text = mcpConfigStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string ReadMcpConfig()
|
||||||
|
{
|
||||||
|
string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
||||||
|
string configDirPath = Path.Combine(appDataPath, "LinkTool");
|
||||||
|
string mcpConfigPath = Path.Combine(appDataPath, "LinkTool", "McpConfig.json");
|
||||||
|
Directory.CreateDirectory(configDirPath);
|
||||||
|
if (!File.Exists(mcpConfigPath))
|
||||||
|
{
|
||||||
|
File.Create(mcpConfigPath);
|
||||||
|
McpServerList mcpServerList = new McpServerList();
|
||||||
|
string json = JsonConvert.SerializeObject(mcpServerList.GetAllServers());
|
||||||
|
File.WriteAllText(mcpConfigPath, json);
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string mcpConfigStr = File.ReadAllText(mcpConfigPath);
|
||||||
|
McpServerList mcpServerList = new McpServerList(mcpConfigStr);
|
||||||
|
return JsonConvert.SerializeObject(mcpServerList.GetAllServers());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteMcpConfig(string json)
|
||||||
|
{
|
||||||
|
string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
||||||
|
string configDirPath = Path.Combine(appDataPath, "LinkTool");
|
||||||
|
string mcpConfigPath = Path.Combine(appDataPath, "LinkTool", "McpConfig.json");
|
||||||
|
Directory.CreateDirectory(configDirPath);
|
||||||
|
if (!File.Exists(mcpConfigPath))
|
||||||
|
{
|
||||||
|
File.Create(mcpConfigPath);
|
||||||
|
}
|
||||||
|
File.WriteAllText(mcpConfigPath, json);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
42
ui/mcp/ShowMcpConfigWindow.cs
Normal file
42
ui/mcp/ShowMcpConfigWindow.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
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.mcp
|
||||||
|
{
|
||||||
|
internal class ShowMcpConfigWindow : Button
|
||||||
|
{
|
||||||
|
|
||||||
|
private McpConfigWindow _mcpconfigwindow = null;
|
||||||
|
|
||||||
|
protected override void OnClick()
|
||||||
|
{
|
||||||
|
//already open?
|
||||||
|
if (_mcpconfigwindow != null)
|
||||||
|
return;
|
||||||
|
_mcpconfigwindow = new McpConfigWindow();
|
||||||
|
_mcpconfigwindow.Owner = FrameworkApplication.Current.MainWindow;
|
||||||
|
_mcpconfigwindow.Closed += (o, e) => { _mcpconfigwindow = null; };
|
||||||
|
_mcpconfigwindow.Show();
|
||||||
|
//uncomment for modal
|
||||||
|
//_mcpconfigwindow.ShowDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,4 +6,6 @@ public class ChatMessageItem : MessageListItem
|
|||||||
public string role { get; set; }
|
public string role { get; set; }
|
||||||
public string content { get; set; }
|
public string content { get; set; }
|
||||||
public MessageType type { get; set; }
|
public MessageType type { get; set; }
|
||||||
|
|
||||||
|
public long accumulateTokens { get; set; }
|
||||||
}
|
}
|
||||||
@ -7,7 +7,8 @@ public enum MessageType
|
|||||||
REASON_MESSAGE,
|
REASON_MESSAGE,
|
||||||
END_TAG,
|
END_TAG,
|
||||||
WARNING,
|
WARNING,
|
||||||
ERROR
|
ERROR,
|
||||||
|
END_ALL
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface MessageListItem
|
public interface MessageListItem
|
||||||
@ -16,4 +17,5 @@ public interface MessageListItem
|
|||||||
string role { get; set; }
|
string role { get; set; }
|
||||||
string content { get; set; }
|
string content { get; set; }
|
||||||
MessageType type { get; set; }
|
MessageType type { get; set; }
|
||||||
|
long accumulateTokens { get; set; }
|
||||||
}
|
}
|
||||||
@ -12,4 +12,6 @@ public class ToolMessageItem : MessageListItem
|
|||||||
public MessageType type { get; set; }
|
public MessageType type { get; set; }
|
||||||
public string status { get; set; }
|
public string status { get; set; }
|
||||||
public string result { get; set; }
|
public string result { get; set; }
|
||||||
|
|
||||||
|
public long accumulateTokens { get; set; }
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user