添加注释添加项目文件。

This commit is contained in:
ShaoHua
2025-10-17 02:39:47 +08:00
parent e94dab2050
commit 183177043f
14 changed files with 822 additions and 0 deletions

26
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,26 @@
{
"version": "0.2.0",
"configurations": [
{
// 使用 IntelliSense 找出 C# 调试存在哪些属性
// 将悬停用于现有属性的说明
// 有关详细信息,请访问 https://github.com/dotnet/vscode-csharp/blob/main/debugger-launchjson.md
"name": ".NET Core Launch (console)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
// 如果已更改目标框架,请确保更新程序路径。
"program": "${workspaceFolder}/MilvusDemo/bin/Debug/net9.0/MilvusDemo.dll",
"args": [],
"cwd": "${workspaceFolder}/MilvusDemo",
// 有关“控制台”字段的详细信息,请参阅 https://aka.ms/VSCode-CS-LaunchJson-Console
"console": "internalConsole",
"stopAtEntry": false
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach"
}
]
}

41
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,41 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/MilvusDemo/MilvusDemo.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary;ForceNoAlign"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/MilvusDemo/MilvusDemo.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary;ForceNoAlign"
],
"problemMatcher": "$msCompile"
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"args": [
"watch",
"run",
"--project",
"${workspaceFolder}/MilvusDemo/MilvusDemo.csproj"
],
"problemMatcher": "$msCompile"
}
]
}

View File

@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Milvus.Client" Version="2.3.0-preview.1" />
</ItemGroup>
</Project>

144
MilvusDemo/MilvusService.cs Normal file
View File

@@ -0,0 +1,144 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Milvus.Client;
namespace MilvusDemo
{
/// <summary>
/// 提供与Milvus向量数据库交互的服务类
/// </summary>
public class MilvusService
{
private readonly MilvusClient _milvusClient;
private readonly string _collectionName;
private readonly int _dim;
/// <summary>
/// 初始化MilvusService的新实例
/// </summary>
/// <param name="host">Milvus服务器主机名</param>
/// <param name="port">Milvus服务器端口</param>
/// <param name="collectionName">集合名称</param>
/// <param name="dim">向量维度</param>
public MilvusService(string host, int port, string collectionName, int dim)
{
_milvusClient = new MilvusClient(host, port);
_collectionName = collectionName;
_dim = dim;
}
/// <summary>
/// 初始化集合,如果存在则删除并重新创建
/// </summary>
public async Task InitializeCollectionAsync()
{
// 检查集合是否存在,如果存在则删除
if (await _milvusClient.HasCollectionAsync(_collectionName))
{
var collectionToDrop = _milvusClient.GetCollection(_collectionName);
await collectionToDrop.DropAsync();
Console.WriteLine($"Collection '{_collectionName}' dropped.");
}
// 创建新的集合
await _milvusClient.CreateCollectionAsync(
_collectionName,
new[]
{
FieldSchema.Create<long>("id", isPrimaryKey: true),
FieldSchema.CreateVarchar("varchar", 256),
FieldSchema.CreateFloatVector("vector", _dim)
});
Console.WriteLine($"Collection '{_collectionName}' created.");
}
/// <summary>
/// 创建索引并加载集合
/// </summary>
public async Task CreateIndexAndLoadAsync()
{
var collection = _milvusClient.GetCollection(_collectionName);
// 创建索引
await collection.CreateIndexAsync("vector", IndexType.Flat, SimilarityMetricType.L2);
Console.WriteLine("Index created.");
// 加载集合
await collection.LoadAsync();
Console.WriteLine("Collection loaded.");
}
/// <summary>
/// 插入随机向量数据
/// </summary>
/// <param name="count">要插入的向量数量</param>
public async Task InsertRandomDataAsync(int count)
{
var collection = _milvusClient.GetCollection(_collectionName);
var random = new Random();
// 生成随机向量
var vectors = new List<ReadOnlyMemory<float>>();
for (int i = 0; i < count; i++)
{
var vector = new float[_dim];
for (int j = 0; j < _dim; j++)
{
vector[j] = (float)random.NextDouble();
}
vectors.Add(vector);
}
// 生成ID和字符串字段
var ids = Enumerable.Range(0, count).Select(i => (long)i).ToList();
var varchars = ids.Select(i => $"varchar_{i}").ToList();
// 打包数据
var insertData = new List<FieldData>
{
FieldData.Create("id", ids),
FieldData.Create("varchar", varchars),
FieldData.CreateFloatVector("vector", vectors)
};
// 执行插入
await collection.InsertAsync(insertData);
Console.WriteLine("Data inserted.");
}
/// <summary>
/// 执行向量相似度搜索
/// </summary>
/// <param name="topK">返回最相似的结果数量</param>
/// <returns>搜索结果</returns>
public async Task<SearchResults> SearchVectorAsync(int topK = 5)
{
var collection = _milvusClient.GetCollection(_collectionName);
var random = new Random();
// 生成随机目标向量
var targetVector = new float[_dim];
for (int j = 0; j < _dim; j++)
{
targetVector[j] = (float)random.NextDouble();
}
// 设置搜索参数
var searchParameters = new SearchParameters();
searchParameters.OutputFields.Add("id");
searchParameters.OutputFields.Add("varchar");
// 执行搜索
var searchResults = await collection.SearchAsync(
"vector",
new[] { (ReadOnlyMemory<float>)targetVector },
SimilarityMetricType.L2,
topK,
searchParameters);
return searchResults;
}
}
}

View File

@@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Milvus.Client;
namespace MilvusDemo
{
/// <summary>
/// 用于测试MilvusService的模拟类
/// </summary>
public class MilvusServiceTests
{
// 模拟的MilvusService实例
private readonly MilvusService _milvusService;
// 标记各个方法是否被调用
public bool InitializeCollectionCalled { get; private set; }
public bool CreateIndexAndLoadCalled { get; private set; }
public bool InsertRandomDataCalled { get; private set; }
public bool SearchVectorCalled { get; private set; }
// 记录传入的参数
public int InsertDataCount { get; private set; }
public int SearchTopK { get; private set; }
public MilvusServiceTests()
{
// 创建真实的MilvusService实例但我们将拦截其方法调用
_milvusService = new MilvusService("localhost", 19530, "test_collection", 8);
}
/// <summary>
/// 模拟初始化集合的方法
/// </summary>
public async Task MockInitializeCollectionAsync()
{
InitializeCollectionCalled = true;
Console.WriteLine("[TEST] InitializeCollectionAsync called");
// 模拟操作延迟
await Task.Delay(100);
Console.WriteLine("[TEST] Collection dropped and created");
}
/// <summary>
/// 模拟创建索引并加载集合的方法
/// </summary>
public async Task MockCreateIndexAndLoadAsync()
{
CreateIndexAndLoadCalled = true;
Console.WriteLine("[TEST] CreateIndexAndLoadAsync called");
// 模拟操作延迟
await Task.Delay(100);
Console.WriteLine("[TEST] Index created");
Console.WriteLine("[TEST] Collection loaded");
}
/// <summary>
/// 模拟插入随机数据的方法
/// </summary>
public async Task MockInsertRandomDataAsync(int count)
{
InsertRandomDataCalled = true;
InsertDataCount = count;
Console.WriteLine($"[TEST] InsertRandomDataAsync called with count: {count}");
// 模拟操作延迟
await Task.Delay(100);
Console.WriteLine("[TEST] Data inserted");
}
/// <summary>
/// 模拟向量搜索的方法
/// </summary>
public async Task<SearchResults> MockSearchVectorAsync(int topK = 5)
{
SearchVectorCalled = true;
SearchTopK = topK;
Console.WriteLine($"[TEST] SearchVectorAsync called with topK: {topK}");
// 模拟操作延迟
await Task.Delay(100);
// 创建模拟的搜索结果
var mockIds = new List<long>();
for (int i = 0; i < topK; i++)
{
mockIds.Add(1000 + i); // 使用1000+i作为模拟ID
}
Console.WriteLine("[TEST] Search completed");
// 注意这里我们无法直接创建SearchResults实例因为它可能是内部类
// 在实际测试中您可能需要使用模拟框架如Moq来模拟这个返回值
// 这里我们返回null实际使用时需要处理这种情况
return null;
}
/// <summary>
/// 运行完整的测试流程
/// </summary>
public async Task RunFullTestAsync()
{
Console.WriteLine("=== Starting MilvusService Test ===");
await MockInitializeCollectionAsync();
await MockCreateIndexAndLoadAsync();
await MockInsertRandomDataAsync(1000);
await MockSearchVectorAsync(5);
// 打印测试结果摘要
Console.WriteLine("\n=== Test Summary ===");
Console.WriteLine($"InitializeCollection Called: {InitializeCollectionCalled}");
Console.WriteLine($"CreateIndexAndLoad Called: {CreateIndexAndLoadCalled}");
Console.WriteLine($"InsertRandomData Called: {InsertRandomDataCalled} (Count: {InsertDataCount})");
Console.WriteLine($"SearchVector Called: {SearchVectorCalled} (TopK: {SearchTopK})");
Console.WriteLine("=== Test Completed ===");
}
}
}

74
MilvusDemo/Program.cs Normal file
View File

@@ -0,0 +1,74 @@
using System;
using System.Threading.Tasks;
namespace MilvusDemo
{
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("Milvus 演示程序");
Console.WriteLine("1. 运行实际的 Milvus 操作");
Console.WriteLine("2. 运行模拟测试");
Console.Write("请选择 (1/2): ");
string choice = Console.ReadLine();
if (choice == "2")
{
await RunTests();
}
else
{
await RunActualMilvusOperations();
}
}
static async Task RunActualMilvusOperations()
{
// 初始化MilvusService
const string host = "localhost";
const int port = 19530;
const string collectionName = "csharp_demo_collection";
const int dim = 8; // 向量维度
// 创建MilvusService实例
var milvusService = new MilvusService(host, port, collectionName, dim);
try
{
// 初始化集合(如果存在则删除并重新创建)
await milvusService.InitializeCollectionAsync();
// 创建索引并加载集合
await milvusService.CreateIndexAndLoadAsync();
// 插入随机数据
await milvusService.InsertRandomDataAsync(1000);
// 执行向量搜索
var searchResults = await milvusService.SearchVectorAsync(5);
// 显示搜索结果
Console.WriteLine("\nSearch results:");
foreach (var result in searchResults.Ids.LongIds)
{
Console.WriteLine($"- ID: {result}");
}
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
if (ex.InnerException != null)
{
Console.WriteLine($"Inner error: {ex.InnerException.Message}");
}
}
}
static async Task RunTests()
{
await TestRunner.RunTests();
}
}
}

24
MilvusDemo/TestRunner.cs Normal file
View File

@@ -0,0 +1,24 @@
using System;
using System.Threading.Tasks;
namespace MilvusDemo
{
/// <summary>
/// 用于运行MilvusService测试的类
/// </summary>
public class TestRunner
{
/// <summary>
/// 运行测试
/// </summary>
public static async Task RunTests()
{
Console.WriteLine("开始运行MilvusService测试...");
var tester = new MilvusServiceTests();
await tester.RunFullTestAsync();
Console.WriteLine("测试完成!");
}
}
}

109
README.md Normal file
View File

@@ -0,0 +1,109 @@
# MilvusDemo
一个使用 C#.NET 9`Milvus.Client` 的极简示例项目,演示:
- 初始化集合(存在则删除并重建)
- 创建向量索引与加载集合
- 批量插入随机向量
- 执行向量相似度搜索
- 通过内置测试流程验证调用链
### 模块划分
- **App入口层**`Program.cs`
- 提供交互式入口:输入 1=实际连接 Milvus 执行;输入 2=运行内置测试(无需 Milvus 实例)。
- **Core/Service业务层**`MilvusService.cs`
- 封装与 Milvus 的连接、集合初始化、索引创建/加载、数据插入与搜索。
- **Test Harness测试层**`TestRunner.cs``MilvusServiceTests.cs`
- `TestRunner` 负责编排测试流程;`MilvusServiceTests` 提供无外部依赖的模拟测试(验证调用链与参数)。
### 环境要求
- .NET SDK 9.0+
- 仅当选择“实际运行(选项 1”时需要可访问的 Milvus Server默认 `localhost:19530`)。
### 快速开始
1. 构建
```powershell
dotnet build
```
2. 运行(测试模式,无需 Milvus
- PowerShell
```powershell
echo 2 | dotnet run
```
- Bash
```bash
echo 2 | dotnet run
```
3. 运行(实际连接 Milvus
- 确保本地或可达的 Milvus 实例运行在 `localhost:19530`。
- 程序启动后输入 `1`。
### 在解决方案根目录运行(多项目)
本仓库包含多个示例项目。可在解决方案根目录使用 `--project` 指定要运行的项目:
```powershell
# 运行 Milvus 示例(默认交互菜单 1/2
dotnet run --project MilvusDemo
# 运行语音到函数示例
dotnet run --project VoiceToFunctionDemo
```
### 启动 Milvus可选
若需在本机快速启动 Milvus可参考官方快速开始或使用 Docker示例
```bash
# 仅供参考,建议按官方文档选择合适的版本与持久化配置
docker pull milvusdb/milvus:latest
docker run -d --name milvus-standalone -p 19530:19530 milvusdb/milvus:latest
```
文档:`https://milvus.io/docs`查看“Get Started / Install”
### 主要参数(实际运行模式)
- 主机与端口:`localhost:19530`
- 集合名:`csharp_demo_collection`
- 向量维度:`8`
> 提示:若需修改连接地址或集合名,请在代码中相应位置调整(例如在连接初始化与集合定义处)。
### 文件说明
- `Program.cs`:控制台入口与菜单;调用服务或测试。
- `MilvusService.cs`:核心服务,封装 Milvus 客户端操作。
- `MilvusServiceTests.cs`:简单的模拟测试实现(不依赖 Milvus
- `TestRunner.cs`:运行测试流程的编排类。
- `MilvusDemo.csproj`:项目与依赖定义(包含 `Milvus.Client`)。
### 项目结构
- `MilvusDemo/`Milvus 向量数据库最小示例,支持实际连接与模拟测试两种模式。
- `VoiceToFunctionDemo/`:语音(文本)解析为函数调用的示例,展示如何从自然语言中抽取参数并调用预定义函数。
---
## VoiceToFunctionDemo
一个将中文自然语言指令解析为函数调用的控制台示例。内置函数库包含:
- `PRODUCT(double[], double[])`:计算两列数值的逐项乘积
- `FILTER(List<User>, Func<User,bool>)`:按条件筛选用户(支持年龄阈值与姓名包含)
- `COUNTIF(double[], Func<double,bool>)`:按范围统计数量
### 运行
```powershell
dotnet run --project VoiceToFunctionDemo
```
程序内置了示例输入,启动后会依次演示:
- 计算两列数值的乘积(如 `[1,3,5]` 与 `[2,4,6]`
- 筛选年龄大于某值且姓名包含关键字的用户
- 统计销售额处于指定区间内的订单数
如需扩展,请修改 `VoiceToFunctionDemo/Program.cs`
- 新增函数:在 `functionLibrary` 中增加 `FunctionInfo`,定义参数类型与执行逻辑。
- 扩展解析:在 `ParseVoiceCommand` 中为新函数添加参数解析与类型校验。
---
### 常见问题FAQ
- 无法连接到 Milvus请确认 Milvus 是否已启动并监听 `19530` 端口,以及本机/容器网络连通性。
- 还原/编译失败:请确认已安装 .NET 9 SDK并允许联网下载 NuGet 依赖;必要时执行 `dotnet restore` 后再构建。
- 端口占用:如 `19530` 已被占用,请修改容器映射或程序连接端口并保持一致。

10
VectorDBDemo.slnx Normal file
View File

@@ -0,0 +1,10 @@
<Solution>
<Projects>
<Project type="FAE04EC0-301F-11D3-BF4B-00C04F79EFBC" name="MilvusDemo" path="MilvusDemo\MilvusDemo.csproj" />
</Projects>
<Folder Name="/src/">
<Project Path="MilvusDemo/MilvusDemo.csproj" />
<Project Path="VoiceToFunctionDemo/VoiceToFunctionDemo.csproj" />
</Folder>
</Solution>

View File

@@ -0,0 +1,13 @@
namespace VoiceToFunction
{
// 函数信息模型(新增参数类型描述,用于校验)
public class FunctionInfo
{
public string Name { get; set; }
public string Description { get; set; }
public List<string> Synonyms { get; set; }
public int MinParams { get; set; }
public List<Type> ParamTypes { get; set; } // 参数类型列表如double[], List<User>
public Func<object[], object> Execute { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
namespace VoiceToFunction
{
// 语音解析结果(新增参数类型信息)
public class ParsedResult
{
public string FunctionName { get; set; }
public object[] Parameters { get; set; }
public string[] ParamTypes { get; set; } // 实际提取的参数类型
public string Error { get; set; }
}
}

View File

@@ -0,0 +1,210 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace VoiceToFunction
{
class Program
{
// 初始化函数库(明确参数类型要求)
private static List<FunctionInfo> functionLibrary = new List<FunctionInfo>
{
// 1. 乘积函数参数两个double数组
new FunctionInfo
{
Name = "PRODUCT",
Description = "计算多列对应行的乘积",
Synonyms = new List<string> { "计算乘积", "相乘", "乘积" },
MinParams = 2,
ParamTypes = new List<Type> { typeof(double[]), typeof(double[]) },
Execute = (args) =>
{
double[] col1 = (double[])args[0];
double[] col2 = (double[])args[1];
return col1.Zip(col2, (a, b) => a * b).ToArray();
}
},
// 2. 筛选函数(参数:用户列表 + 筛选条件)
new FunctionInfo
{
Name = "FILTER",
Description = "筛选满足条件的数据",
Synonyms = new List<string> { "筛选", "过滤", "选出" },
MinParams = 2,
ParamTypes = new List<Type> { typeof(List<User>), typeof(Func<User, bool>) },
Execute = (args) =>
{
List<User> users = (List<User>)args[0];
Func<User, bool> condition = (Func<User, bool>)args[1];
return users.Where(condition).ToList();
}
},
// 3. 统计函数(参数:销售额数组 + 统计条件)
new FunctionInfo
{
Name = "COUNTIF",
Description = "统计满足条件的记录数",
Synonyms = new List<string> { "统计数量", "计数", "数一下" },
MinParams = 2,
ParamTypes = new List<Type> { typeof(double[]), typeof(Func<double, bool>) },
Execute = (args) =>
{
double[] sales = (double[])args[0];
Func<double, bool> condition = (Func<double, bool>)args[1];
return sales.Count(condition);
}
}
};
static void Main(string[] args)
{
// 测试带复杂参数的语音指令
TestVoiceCommand("计算C列和D列的乘积C列是[1,3,5]D列是[2,4,6]");
TestVoiceCommand("计算A列和B列的乘积A列是[1,3,5]B列是[2,4,6]");
TestVoiceCommand("筛选出年龄大于28且姓名包含'李'的用户");
TestVoiceCommand("统计销售额在5000到20000之间的订单数数据是[3000, 8000, 15000, 25000]");
Console.ReadKey();
}
static void TestVoiceCommand(string voiceText)
{
Console.WriteLine($"=== 语音指令:{voiceText} ===");
ParsedResult result = ParseVoiceCommand(voiceText);
if (!string.IsNullOrEmpty(result.Error))
{
Console.WriteLine($"错误:{result.Error}");
return;
}
// 校验参数类型是否匹配函数要求
var function = functionLibrary.First(f => f.Name == result.FunctionName);
bool paramTypeMatch = function.ParamTypes.Zip(result.ParamTypes,
(required, actual) => required.Name == actual).All(match => match);
if (!paramTypeMatch)
{
Console.WriteLine("错误:参数类型与函数要求不匹配");
return;
}
// 执行函数并输出结果
var executionResult = function.Execute(result.Parameters);
Console.WriteLine($"匹配函数:{result.FunctionName}");
Console.WriteLine($"执行结果:{GetResultString(executionResult)}");
Console.WriteLine();
}
// 核心:解析语音文本,提取函数+参数(强化入参处理)
static ParsedResult ParseVoiceCommand(string text)
{
var result = new ParsedResult();
// 1. 匹配函数(同之前逻辑)
FunctionInfo matchedFunction = functionLibrary.FirstOrDefault(
func => func.Synonyms.Any(syn => text.Contains(syn)));
if (matchedFunction == null)
{
result.Error = "未找到匹配的函数";
return result;
}
result.FunctionName = matchedFunction.Name;
// 2. 提取并解析参数(根据函数类型动态处理)
try
{
switch (matchedFunction.Name)
{
case "PRODUCT":
// 提取列数据(支持显式输入如"[1,3,5]"
var colDataMatches = Regex.Matches(text, @"\[([\d, ]+)\]")
.Cast<Match>()
.Select(m => m.Groups[1].Value.Split(',').Select(double.Parse).ToArray())
.ToList();
if (colDataMatches.Count < 2)
{
result.Error = "PRODUCT需要至少两列数据格式如'[1,2,3]'";
return result;
}
result.Parameters = new object[] { colDataMatches[0], colDataMatches[1] };
result.ParamTypes = new[] { "Double[]", "Double[]" };
break;
case "FILTER":
// 提取年龄条件(如"大于28")和姓名条件(如"包含'李'"
int ageThreshold = 0;
string nameKeyword = null;
var ageMatch = Regex.Match(text, @"年龄(大于|小于|等于)(\d+)");
if (ageMatch.Success)
{
string op = ageMatch.Groups[1].Value;
ageThreshold = int.Parse(ageMatch.Groups[2].Value);
}
var nameMatch = Regex.Match(text, @"姓名包含'([^']+)'");
if (nameMatch.Success)
{
nameKeyword = nameMatch.Groups[1].Value;
}
// 组合多条件筛选器
Func<User, bool> condition = u =>
(ageMatch.Success ? (ageMatch.Groups[1].Value == "大于" ? u.Age > ageThreshold : u.Age < ageThreshold) : true) &&
(nameMatch.Success ? u.Name.Contains(nameKeyword) : true);
// 模拟用户数据(实际应从数据源获取)
var users = new List<User>
{
new User { Name = "张三", Age = 25 },
new User { Name = "李四", Age = 30 },
new User { Name = "李白", Age = 29 },
new User { Name = "王五", Age = 35 }
};
result.Parameters = new object[] { users, condition };
result.ParamTypes = new[] { "List<User>", "Func<User, Boolean>" };
break;
case "COUNTIF":
// 提取数值范围(如"5000到20000")和数据
var rangeMatch = Regex.Match(text, @"(\d+)到(\d+)");
if (!rangeMatch.Success)
{
result.Error = "COUNTIF需要范围条件如'5000到20000'";
return result;
}
double min = double.Parse(rangeMatch.Groups[1].Value);
double max = double.Parse(rangeMatch.Groups[2].Value);
// 提取销售额数据
var salesData = Regex.Match(text, @"\[([\d, ]+)\]")
.Groups[1].Value.Split(',').Select(double.Parse).ToArray();
result.Parameters = new object[] { salesData, (Func<double, bool>)(s => s >= min && s <= max) };
result.ParamTypes = new[] { "Double[]", "Func<Double, Boolean>" };
break;
}
}
catch (Exception ex)
{
result.Error = $"参数解析失败:{ex.Message}";
return result;
}
return result;
}
static string GetResultString(object result)
{
if (result is double[] nums) return string.Join(", ", nums);
if (result is List<User> users) return string.Join(", ", users.Select(u => $"{u.Name}({u.Age})"));
if (result is int count) return count.ToString();
return "未知结果";
}
}
}

View File

@@ -0,0 +1,8 @@
namespace VoiceToFunction
{
public class User
{
public string Name { get; set; }
public int Age { get; set; }
}
}

View File

@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
</ItemGroup>
</Project>