新增托盘图标

This commit is contained in:
2026-03-01 10:42:42 +08:00
parent 0ba966cef2
commit e03e1b9766
26 changed files with 582 additions and 72 deletions

View File

@@ -0,0 +1,52 @@
using System.IO;
using System.Reflection;
using Autodesk.Revit.DB;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
namespace Szmedi.RvKits.LLMScript
{
public class CodeExecutor
{
public void Execute(string methodBody, Autodesk.Revit.DB.Document doc, UIDocument uidoc)
{
string code = $@"
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using System;
public class ScriptRunner
{{
public void Run(Document doc, UIDocument uidoc)
{{
{methodBody}
}}
}}";
var syntaxTree = CSharpSyntaxTree.ParseText(code);
var compilation = CSharpCompilation.Create(
"DynamicScript")
.AddReferences(
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
MetadataReference.CreateFromFile(typeof(Document).Assembly.Location))
.AddSyntaxTrees(syntaxTree)
.WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
using var ms = new MemoryStream();
var result = compilation.Emit(ms);
if (!result.Success)
throw new Exception("Compilation failed");
ms.Seek(0, SeekOrigin.Begin);
var assembly = Assembly.Load(ms.ToArray());
var type = assembly.GetType("ScriptRunner");
var instance = Activator.CreateInstance(type);
type.GetMethod("Run").Invoke(instance, new object[] { doc, uidoc });
}
}
}

View File

@@ -0,0 +1,11 @@
using System.Threading.Tasks;
namespace Szmedi.RvKits.LLMScript
{
internal interface ILLMProvider
{
Task GenerateStreamAsync(string systemPrompt,
string userPrompt,
Action<string> onTokenReceived);
}
}

View File

@@ -0,0 +1,40 @@
using System.Text;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Nice3point.Revit.Toolkit.External;
namespace Szmedi.RvKits.LLMScript
{
/// <summary>
/// Revit执行命令
/// </summary>
[Transaction(TransactionMode.Manual)]
[Regeneration(RegenerationOption.Manual)]
public class LLMCmd : ExternalCommand
{
public async override void Execute()
{
string userTask = "将当前选中墙的Comments参数追加'检查'";
PromptManager promptManager = new PromptManager("Prompts/System_UltraStrict.txt");
string systemPrompt = promptManager.GetSystemPrompt();
string userPrompt = promptManager.BuildUserPrompt(userTask);
var llm = new OllamaProvider("http://localhost:11434/api/chat", "revit-coder");
StringBuilder fullCode = new StringBuilder();
await llm.GenerateStreamAsync(
systemPrompt,
userPrompt,
chunk =>
{
fullCode.Append(chunk);
});
CodeExecutor executor = new CodeExecutor();
executor.Execute(fullCode.ToString(), Document, UiDocument);
}
}
}

View File

@@ -0,0 +1,74 @@
using System.IO;
using System.Net.Http;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Szmedi.RvKits.LLMScript
{
public class OllamaProvider : ILLMProvider
{
private static readonly HttpClient _client = new HttpClient();
private readonly string _endpoint;
private readonly string _model;
public OllamaProvider(string endpoint, string model)
{
_endpoint = endpoint;
_model = model;
}
public async Task GenerateStreamAsync(
string systemPrompt,
string userPrompt,
Action<string> onTokenReceived)
{
var payload = new
{
model = _model,
messages = new[]
{
new { role = "system", content = systemPrompt },
new { role = "user", content = userPrompt }
},
stream = true
};
string json = JsonConvert.SerializeObject(payload);
var request = new HttpRequestMessage(HttpMethod.Post, _endpoint);
request.Content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _client.SendAsync(
request,
HttpCompletionOption.ResponseHeadersRead);
response.EnsureSuccessStatusCode();
using (var stream = await response.Content.ReadAsStreamAsync())
using (var reader = new StreamReader(stream))
{
while (!reader.EndOfStream)
{
string line = await reader.ReadLineAsync();
if (string.IsNullOrWhiteSpace(line))
continue;
JObject obj = JObject.Parse(line);
bool done = obj["done"]?.Value<bool>() ?? false;
var content = obj["message"]?["content"];
if (content != null)
{
onTokenReceived(content.ToString());
}
if (done)
break;
}
}
}
}
}

View File

@@ -0,0 +1,84 @@
using System.IO;
using System.Net.Http;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Szmedi.RvKits.LLMScript
{
public class OpenAiProvider : ILLMProvider
{
private static readonly HttpClient _client = new HttpClient();
private readonly string _endpoint;
private readonly string _apiKey;
private readonly string _model;
public OpenAiProvider(string endpoint, string apiKey, string model)
{
_endpoint = endpoint;
_apiKey = apiKey;
_model = model;
_client.DefaultRequestHeaders.Clear();
_client.DefaultRequestHeaders.Add("Authorization", $"Bearer {_apiKey}");
}
public async Task GenerateStreamAsync(
string systemPrompt,
string userPrompt,
Action<string> onTokenReceived)
{
var payload = new
{
model = _model,
messages = new[]
{
new { role = "system", content = systemPrompt },
new { role = "user", content = userPrompt }
},
temperature = 0,
stream = true
};
string json = JsonConvert.SerializeObject(payload);
var request = new HttpRequestMessage(HttpMethod.Post, _endpoint);
request.Content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _client.SendAsync(
request,
HttpCompletionOption.ResponseHeadersRead);
response.EnsureSuccessStatusCode();
using (var stream = await response.Content.ReadAsStreamAsync())
using (var reader = new StreamReader(stream))
{
while (!reader.EndOfStream)
{
string line = await reader.ReadLineAsync();
if (string.IsNullOrWhiteSpace(line))
continue;
if (!line.StartsWith("data:"))
continue;
string data = line.Substring(5).Trim();
if (data == "[DONE]")
break;
JObject obj = JObject.Parse(data);
var delta = obj["choices"]?[0]?["delta"]?["content"];
if (delta != null)
{
onTokenReceived(delta.ToString());
}
}
}
}
}
}

View File

@@ -0,0 +1,24 @@
using System.IO;
namespace Szmedi.RvKits.LLMScript
{
public class PromptManager
{
private readonly string _systemPrompt;
public PromptManager(string promptPath)
{
_systemPrompt = File.ReadAllText(promptPath);
}
public string GetSystemPrompt()
{
return _systemPrompt;
}
public string BuildUserPrompt(string task)
{
return task.Trim();
}
}
}