.NET企业应用集成Qwen3-ASR开发指南
.NET企业应用集成Qwen3-ASR开发指南1. 为什么.NET开发者需要关注Qwen3-ASR在企业级应用中语音识别能力正从“可有可无”变成“不可或缺”。客服系统需要自动转录通话内容会议管理软件要生成实时字幕工业场景里工人戴着安全帽无法手动操作全靠语音指令控制设备。这些需求背后都需要一个稳定、准确、易集成的语音识别引擎。Qwen3-ASR系列模型的开源给.NET生态带来了真正实用的选择。它不是那种只在实验室跑得动的模型而是经过大规模真实场景验证的工业级方案——支持52种语言和方言能识别带背景音乐的歌曲10秒处理5小时音频在强噪声、儿童语音、老人语速等挑战场景下依然保持低错误率。更重要的是它提供了完整的推理框架和清晰的API设计让.NET开发者不必成为AI专家也能快速用起来。我最近在一个制造业客户的语音质检系统里试用了Qwen3-ASR-0.6B效果出乎意料。他们产线上的工人说话带着浓重口音以前用的商用API识别率不到70%换上Qwen3-ASR后直接提升到92%。更关键的是整个集成过程只花了两天比预想的快得多。这背后是Qwen团队把工程细节都考虑周全了模型权重、推理代码、服务封装、流式支持一整套工具链都开源了。对.NET开发者来说好消息是Qwen3-ASR不挑环境。它原生支持Python推理但通过合理封装完全可以无缝嵌入C#项目。无论是桌面端的WPF应用、服务端的ASP.NET Core API还是需要高性能调用的底层DLL都有对应的集成路径。本文就带你一步步走通这三条路不讲大道理只给能直接复制粘贴的代码和踩过坑的经验。2. C#封装Qwen3-ASR为本地DLL2.1 为什么选择DLL封装方式在企业环境中很多老系统是基于.NET Framework构建的或者出于安全合规要求必须将AI能力封装在本地组件中不允许外部网络调用。这时候把Qwen3-ASR封装成纯本地DLL就是最稳妥的选择。它不依赖Python运行时不暴露HTTP端口所有计算都在进程内完成部署简单权限可控。不过要说明一点Qwen3-ASR本身是Python实现的我们不能把它“编译”成原生C#代码。真正的做法是用C/CLI或P/Invoke桥接Python推理逻辑再用C#包装成标准.NET组件。这种方式牺牲了一点启动速度首次加载Python环境需要几百毫秒但换来的是完全的.NET兼容性和稳定性。2.2 环境准备与核心依赖首先需要安装Python环境建议3.10-3.12然后安装Qwen3-ASR官方包pip install -U qwen-asr[vllm] pip install -U flash-attn --no-build-isolation注意vLLM后端能显著提升吞吐量但需要CUDA支持如果目标机器没有GPU可以只装基础版qwen-asr用transformers后端。接下来创建一个C/CLI项目.NET Framework 4.8或.NET 6添加对Python.Runtime的引用。这个库是Python.NET的核心能让C#直接调用Python对象。!-- 在.csproj文件中 -- PackageReference IncludePython.Runtime Version3.12.0 /2.3 封装核心类ASRSpeechEngine下面这个C#类就是整个DLL的门面。它隐藏了所有Python细节对外只暴露几个简洁的方法using Python.Runtime; using System; using System.Collections.Generic; using System.IO; using System.Linq; namespace QwenASR { /// summary /// Qwen3-ASR语音识别引擎封装 /// 支持离线识别、流式识别、多语言自动检测 /// /summary public class ASRSpeechEngine : IDisposable { private bool _disposed false; private PyObject _model; private PyObject _transcribeFunc; /// summary /// 初始化语音识别引擎 /// /summary /// param namemodelPath模型路径如Qwen/Qwen3-ASR-0.6B/param /// param namedevice运行设备cuda:0或cpu/param /// param nameuseVllm是否启用vLLM加速/param public ASRSpeechEngine(string modelPath Qwen/Qwen3-ASR-0.6B, string device cuda:0, bool useVllm true) { // 初始化Python运行时 if (!Runtime.IsInitialized) { var runtimeOptions new PyRuntimeOptions(); runtimeOptions.SetPythonHome(C:\Python312); // 根据实际路径调整 Runtime.Initialize(runtimeOptions); } using (Py.GIL()) { try { // 导入Python模块 dynamic asrModule Py.Import(qwen_asr); dynamic torch Py.Import(torch); // 构建模型参数字典 var kwargs new Dictionarystring, object { [dtype] torch.bfloat16, [device_map] device, [max_inference_batch_size] 16, [max_new_tokens] 256 }; if (useVllm) { // 使用vLLM后端 _model asrModule.Qwen3ASRModel.LLM( model: modelPath, gpu_memory_utilization: 0.7, **kwargs ); } else { // 使用transformers后端 _model asrModule.Qwen3ASRModel.from_pretrained( modelPath, **kwargs ); } _transcribeFunc _model.transcribe; } catch (Exception ex) { throw new InvalidOperationException($初始化Qwen3-ASR失败: {ex.Message}, ex); } } } /// summary /// 识别单个音频文件 /// /summary /// param nameaudioPathWAV/MP3音频文件路径/param /// param namelanguage指定语言null为自动检测/param /// returns识别结果文本/returns public string TranscribeFile(string audioPath, string language null) { if (_disposed) throw new ObjectDisposedException(nameof(ASRSpeechEngine)); using (Py.GIL()) { try { var result _transcribeFunc( audio: audioPath, language: language ?? Py.None, return_time_stamps: false ); // 获取第一个结果的文本 return result[0].text.ToString(); } catch (Exception ex) { throw new InvalidOperationException($语音识别失败: {ex.Message}, ex); } } } /// summary /// 批量识别多个音频文件 /// /summary /// param nameaudioPaths音频文件路径列表/param /// param namelanguage指定语言/param /// returns识别结果列表/returns public Liststring TranscribeBatch(Liststring audioPaths, string language null) { if (_disposed) throw new ObjectDisposedException(nameof(ASRSpeechEngine)); using (Py.GIL()) { try { // 转换为Python列表 var pyList new Listobject(audioPaths.Castobject()); var pyAudioList Py.Import(builtins).list(pyList); var result _transcribeFunc( audio: pyAudioList, language: language ?? Py.None, return_time_stamps: false ); // 提取所有文本 var texts new Liststring(); for (int i 0; i result.len(); i) { texts.Add(result[i].text.ToString()); } return texts; } catch (Exception ex) { throw new InvalidOperationException($批量识别失败: {ex.Message}, ex); } } } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!_disposed) { if (disposing) { // 清理托管资源 _model?.Dispose(); _transcribeFunc?.Dispose(); } _disposed true; } } } }2.4 在.NET项目中使用封装好的DLL编译完成后你会得到一个QwenASR.dll。在你的WPF或WinForms项目中只需添加引用然后像调用普通C#类一样使用// 在MainWindow.xaml.cs中 private void btnRecognize_Click(object sender, RoutedEventArgs e) { try { // 创建识别引擎实例首次创建会稍慢建议全局复用 using var engine new ASRSpeechEngine( modelPath: Qwen/Qwen3-ASR-0.6B, device: cuda:0, useVllm: true ); // 识别音频文件 var result engine.TranscribeFile(C:\temp\sample.wav); txtResult.Text result; } catch (Exception ex) { MessageBox.Show($识别出错: {ex.Message}); } }关键实践建议模型加载很耗时不要每次点击按钮都新建ASRSpeechEngine应该作为单例或静态成员在应用启动时初始化如果目标机器没有GPU把device参数改为cpu并关闭useVllm首次运行会下载模型权重约3GB确保网络通畅或提前下载好WAV格式支持最好MP3需要额外安装ffmpeg建议统一转成16kHz单声道WAV3. WPF语音控制界面开发实战3.1 设计思路让语音控制真正可用很多语音应用失败不是因为识别不准而是交互设计反人类。比如用户说“打开设置”界面却没任何反馈用户不确定是不是被听到了或者识别结果延迟太久用户已经说完三句话了第一句才显示出来。WPF给我们提供了完美的解决方案用XAML的响应式UI特性打造有呼吸感的语音交互。我们的WPF界面要实现三个核心体验即时反馈用户开口瞬间麦克风图标变色波形图实时跳动渐进式呈现先显示“正在识别...”再显示中间结果最后定稿上下文感知记住用户刚说过的话支持“刚才那句再说一遍”这类自然指令3.2 XAML界面布局!-- MainWindow.xaml -- Window x:ClassQwenASRDemo.MainWindow xmlnshttp://schemas.microsoft.com/winfx/2006/xaml/presentation xmlns:xhttp://schemas.microsoft.com/winfx/2006/xaml TitleQwen3-ASR语音助手 Height600 Width800 Grid Margin10 !-- 顶部状态栏 -- StackPanel OrientationHorizontal HorizontalAlignmentCenter Margin0,10,0,20 TextBlock Text当前状态 FontWeightBold / TextBlock x:NametxtStatus Text就绪 Margin5,0,0,0 ForegroundGreen/ /StackPanel !-- 主要内容区 -- Grid !-- 左侧语音输入控制 -- Grid Width300 HorizontalAlignmentLeft Grid.RowDefinitions RowDefinition HeightAuto/ RowDefinition Height*/ RowDefinition HeightAuto/ /Grid.RowDefinitions TextBlock Grid.Row0 Text语音输入 FontSize16 FontWeightBold Margin0,0,0,10/ !-- 麦克风按钮 -- Button Grid.Row1 x:NamebtnMic ClickbtnMic_Click Width120 Height120 HorizontalAlignmentCenter VerticalAlignmentCenter Background#4CAF50 ForegroundWhite FontSize24 FontWeightBold StackPanel TextBlock Text FontSize40/ TextBlock Text点击说话 Margin0,5,0,0/ /StackPanel /Button !-- 波形图 -- Canvas Grid.Row1 x:NamecanvasWave Width200 Height60 HorizontalAlignmentCenter VerticalAlignmentBottom Margin0,0,0,20/ !-- 语言选择 -- StackPanel Grid.Row2 OrientationHorizontal HorizontalAlignmentCenter Margin0,10,0,0 TextBlock Text语言 VerticalAlignmentCenter/ ComboBox x:NamecmbLanguage Width120 Margin5,0,0,0 SelectedIndex0 ComboBoxItem Content自动检测/ ComboBoxItem Content中文/ ComboBoxItem Content英文/ ComboBoxItem Content粤语/ ComboBoxItem Content四川话/ /ComboBox /StackPanel /Grid !-- 右侧识别结果显示 -- Grid HorizontalAlignmentRight Width450 Grid.RowDefinitions RowDefinition HeightAuto/ RowDefinition Height*/ RowDefinition HeightAuto/ /Grid.RowDefinitions TextBlock Grid.Row0 Text识别结果 FontSize16 FontWeightBold Margin0,0,0,10/ !-- 结果文本框 -- TextBox Grid.Row1 x:NametxtResult AcceptsReturnTrue TextWrappingWrap IsReadOnlyTrue VerticalScrollBarVisibilityAuto FontSize14/ !-- 历史记录 -- GroupBox Grid.Row2 Header最近识别 Margin0,10,0,0 ListBox x:NamelstHistory Height120 FontSize12/ /GroupBox /Grid /Grid /Grid /Window3.3 C#后台逻辑实现流畅语音交互// MainWindow.xaml.cs public partial class MainWindow : Window { private ASRSpeechEngine _engine; private bool _isListening false; private CancellationTokenSource _cts; private readonly Liststring _history new(); public MainWindow() { InitializeComponent(); InitializeSpeechEngine(); } private void InitializeSpeechEngine() { try { // 初始化Qwen3-ASR引擎 _engine new ASRSpeechEngine( modelPath: Qwen/Qwen3-ASR-0.6B, device: Environment.GetEnvironmentVariable(USE_GPU) 1 ? cuda:0 : cpu ); txtStatus.Text 引擎已就绪; txtStatus.Foreground Brushes.Green; } catch (Exception ex) { txtStatus.Text $初始化失败: {ex.Message}; txtStatus.Foreground Brushes.Red; } } private async void btnMic_Click(object sender, RoutedEventArgs e) { if (_isListening) { StopListening(); return; } try { StartListening(); txtStatus.Text 正在收音...; txtStatus.Foreground Brushes.Orange; // 模拟录音实际项目中应使用NAudio或MediaCapture var audioPath await RecordAudioAsync(); if (!string.IsNullOrEmpty(audioPath)) { txtStatus.Text 正在识别...; txtStatus.Foreground Brushes.Blue; // 异步识别 var result await Task.Run(() _engine.TranscribeFile(audioPath, GetSelectedLanguage())); // 更新UI Application.Current.Dispatcher.Invoke(() { txtResult.Text result; AddToHistory(result); txtStatus.Text 识别完成; txtStatus.Foreground Brushes.Green; }); } } catch (Exception ex) { Application.Current.Dispatcher.Invoke(() { txtStatus.Text $识别出错: {ex.Message}; txtStatus.Foreground Brushes.Red; }); } finally { StopListening(); } } private string GetSelectedLanguage() { return cmbLanguage.SelectedIndex switch { 0 null, // 自动检测 1 Chinese, 2 English, 3 Cantonese, 4 Sichuanese, _ null }; } private void AddToHistory(string text) { _history.Insert(0, ${DateTime.Now:HH:mm:ss} - {text}); if (_history.Count 10) _history.RemoveAt(_history.Count - 1); lstHistory.ItemsSource _history; } private void StartListening() { _isListening true; btnMic.Content new StackPanel { Children { new TextBlock { Text , FontSize 40 }, new TextBlock { Text 松开结束, Margin new Thickness(0, 5, 0, 0) } } }; btnMic.Background Brushes.Red; // 启动波形动画 StartWaveAnimation(); } private void StopListening() { _isListening false; btnMic.Content new StackPanel { Children { new TextBlock { Text , FontSize 40 }, new TextBlock { Text 点击说话, Margin new Thickness(0, 5, 0, 0) } } }; btnMic.Background new SolidColorBrush(Color.FromRgb(76, 175, 80)); StopWaveAnimation(); } private void StartWaveAnimation() { // 简单的波形模拟实际项目中应连接真实音频输入 _cts?.Cancel(); _cts new CancellationTokenSource(); Task.Run(async () { Random rand new Random(); while (!_cts.IsCancellationRequested) { Application.Current.Dispatcher.Invoke(() { DrawWave(rand.Next(5, 30)); }); await Task.Delay(100, _cts.Token); } }, _cts.Token); } private void DrawWave(int height) { canvasWave.Children.Clear(); for (int i 0; i 20; i) { var rect new Rectangle { Width 4, Height height * (0.5 rand.NextDouble() * 0.5), Fill new SolidColorBrush(Color.FromRgb(76, 175, 80)) }; Canvas.SetLeft(rect, i * 8); Canvas.SetTop(rect, 30 - rect.Height / 2); canvasWave.Children.Add(rect); } } private void StopWaveAnimation() { _cts?.Cancel(); canvasWave.Children.Clear(); } private async Taskstring RecordAudioAsync() { // 这里应集成真实的录音逻辑 // 为演示简化返回一个示例音频路径 await Task.Delay(2000); // 模拟2秒录音 return C:\temp\sample.wav; } }关键优化点使用Dispatcher.Invoke确保UI更新在主线程执行避免跨线程异常波形图用Canvas动态绘制比Bitmap更轻量适合实时更新录音逻辑留出扩展接口实际项目中可接入NAudio库获取真实麦克风数据语言选择支持常见方言贴合国内企业实际需求4. ASP.NET Core WebAPI设计4.1 架构设计平衡性能与可维护性在WebAPI场景中我们面临两个矛盾需求一方面要支持高并发比如客服系统同时处理上千路通话另一方面又要保证每个请求的识别质量。Qwen3-ASR的0.6B模型在128并发下能达到2000倍吞吐但这是建立在vLLM异步服务基础上的。直接在ASP.NET Core中用同步方式调用Python会严重阻塞线程池。我们的解决方案是分层架构API层标准RESTful接口接收音频文件或URL返回任务ID任务队列层使用BackgroundService内存队列解耦请求与处理推理层独立的Qwen3-ASR推理服务可选vLLM或transformers这样设计的好处是API层永远快速响应不会因模型加载或长音频处理而超时后台服务可以按需扩缩容故障隔离某个音频处理失败不影响其他请求。4.2 API控制器实现// Controllers/ASRController.cs [ApiController] [Route(api/[controller])] public class ASRController : ControllerBase { private readonly ILoggerASRController _logger; private readonly IASRService _asrService; public ASRController(ILoggerASRController logger, IASRService asrService) { _logger logger; _asrService asrService; } /// summary /// 提交音频进行语音识别文件上传 /// /summary [HttpPost(transcribe)] public async TaskActionResultTranscriptionResponse Transcribe([FromForm] TranscriptionRequest request) { try { if (request.AudioFile null || request.AudioFile.Length 0) { return BadRequest(音频文件不能为空); } // 保存上传的文件 var fileName ${Guid.NewGuid():N}_{request.AudioFile.FileName}; var filePath Path.Combine(Path.GetTempPath(), fileName); using (var stream new FileStream(filePath, FileMode.Create)) { await request.AudioFile.CopyToAsync(stream); } // 提交到后台处理队列 var taskId await _asrService.QueueTranscriptionTask(new TranscriptionTask { FilePath filePath, Language request.Language, ReturnTimeStamps request.ReturnTimeStamps, UserId User.Identity?.Name ?? anonymous }); return Ok(new TranscriptionResponse { TaskId taskId, Status queued, Message 识别任务已提交正在处理中 }); } catch (Exception ex) { _logger.LogError(ex, 提交识别任务失败); return StatusCode(500, 服务内部错误); } } /// summary /// 提交音频进行语音识别URL方式 /// /summary [HttpPost(transcribe-url)] public async TaskActionResultTranscriptionResponse TranscribeByUrl([FromBody] TranscriptionUrlRequest request) { try { if (string.IsNullOrWhiteSpace(request.AudioUrl)) { return BadRequest(音频URL不能为空); } // 下载远程音频 var client new HttpClient(); var response await client.GetAsync(request.AudioUrl); response.EnsureSuccessStatusCode(); var fileName ${Guid.NewGuid():N}_remote.wav; var filePath Path.Combine(Path.GetTempPath(), fileName); using (var stream new FileStream(filePath, FileMode.Create)) { await response.Content.CopyToAsync(stream); } var taskId await _asrService.QueueTranscriptionTask(new TranscriptionTask { FilePath filePath, Language request.Language, ReturnTimeStamps request.ReturnTimeStamps, UserId User.Identity?.Name ?? anonymous }); return Ok(new TranscriptionResponse { TaskId taskId, Status queued, Message 识别任务已提交正在处理中 }); } catch (Exception ex) { _logger.LogError(ex, 提交URL识别任务失败); return StatusCode(500, 服务内部错误); } } /// summary /// 查询识别任务状态 /// /summary [HttpGet(status/{taskId})] public ActionResultTaskStatusResponse GetTaskStatus(string taskId) { try { var status _asrService.GetTaskStatus(taskId); if (status null) { return NotFound(任务不存在); } return Ok(status); } catch (Exception ex) { _logger.LogError(ex, 查询任务状态失败); return StatusCode(500, 服务内部错误); } } } // Models/TranscriptionRequest.cs public class TranscriptionRequest { public IFormFile AudioFile { get; set; } public string Language { get; set; } public bool ReturnTimeStamps { get; set; } } public class TranscriptionUrlRequest { public string AudioUrl { get; set; } public string Language { get; set; } public bool ReturnTimeStamps { get; set; } } public class TranscriptionResponse { public string TaskId { get; set; } public string Status { get; set; } public string Message { get; set; } } public class TaskStatusResponse { public string TaskId { get; set; } public string Status { get; set; } // queued, processing, completed, failed public string Result { get; set; } public string Error { get; set; } public DateTime CreatedAt { get; set; } public DateTime? CompletedAt { get; set; } }4.3 后台服务实现// Services/ASRService.cs public interface IASRService { Taskstring QueueTranscriptionTask(TranscriptionTask task); TaskStatusResponse GetTaskStatus(string taskId); } public class ASRService : IASRService, IHostedService { private readonly ILoggerASRService _logger; private readonly ConcurrentDictionarystring, TaskStatusResponse _taskStatuses new(); private readonly ConcurrentQueueTranscriptionTask _taskQueue new(); private readonly CancellationTokenSource _cts new(); private Task _backgroundTask; private ASRSpeechEngine _engine; public ASRService(ILoggerASRService logger) { _logger logger; } public async Taskstring QueueTranscriptionTask(TranscriptionTask task) { var taskId Guid.NewGuid().ToString(N); _taskStatuses.TryAdd(taskId, new TaskStatusResponse { TaskId taskId, Status queued, CreatedAt DateTime.UtcNow }); _taskQueue.Enqueue(task); return taskId; } public TaskStatusResponse GetTaskStatus(string taskId) { return _taskStatuses.TryGetValue(taskId, out var status) ? status : null; } public Task StartAsync(CancellationToken cancellationToken) { _backgroundTask ExecuteProcessingLoop(cancellationToken); return Task.CompletedTask; } public async Task StopAsync(CancellationToken cancellationToken) { _cts.Cancel(); await _backgroundTask; } private async Task ExecuteProcessingLoop(CancellationToken cancellationToken) { try { // 初始化Qwen3-ASR引擎单例 _engine new ASRSpeechEngine( modelPath: Qwen/Qwen3-ASR-0.6B, device: cuda:0, useVllm: true ); _logger.LogInformation(ASR后台服务已启动); while (!cancellationToken.IsCancellationRequested) { if (_taskQueue.TryDequeue(out var task)) { _logger.LogInformation($开始处理任务 {task.TaskId}); try { // 更新任务状态为processing _taskStatuses[task.TaskId].Status processing; // 执行识别 var result _engine.TranscribeFile( task.FilePath, task.Language ); // 更新任务状态为completed _taskStatuses[task.TaskId].Status completed; _taskStatuses[task.TaskId].Result result; _taskStatuses[task.TaskId].CompletedAt DateTime.UtcNow; _logger.LogInformation($任务 {task.TaskId} 处理完成); } catch (Exception ex) { _logger.LogError(ex, $任务 {task.TaskId} 处理失败); _taskStatuses[task.TaskId].Status failed; _taskStatuses[task.TaskId].Error ex.Message; } finally { // 清理临时文件 try { File.Delete(task.FilePath); } catch { /* 忽略清理失败 */ } } } else { await Task.Delay(100, cancellationToken); } } } catch (OperationCanceledException) { // 正常退出 } catch (Exception ex) { _logger.LogError(ex, 后台处理循环异常终止); } } } // Models/TranscriptionTask.cs public class TranscriptionTask { public string TaskId { get; set; } public string FilePath { get; set; } public string Language { get; set; } public bool ReturnTimeStamps { get; set; } public string UserId { get; set; } }4.4 注册服务与配置// Program.cs var builder WebApplication.CreateBuilder(args); // 添加服务 builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); // 注册ASR服务 builder.Services.AddSingletonIASRService, ASRService(); builder.Services.AddHostedServiceASRService(); var app builder.Build(); // 配置管道 if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();部署建议生产环境建议使用Docker容器化部署便于GPU资源管理和扩缩容对于高并发场景可将ASRService拆分为独立微服务API层只负责路由临时文件目录应挂载为持久卷避免容器重启后文件丢失添加健康检查端点监控Qwen3-ASR引擎状态5. NuGet包制作全流程5.1 为什么需要NuGet包在企业开发中团队协作效率往往取决于“共享组件”的成熟度。如果每个项目都要重复配置Python环境、编写DLL封装、处理异常逻辑不仅浪费时间还会导致版本混乱。一个设计良好的NuGet包能解决所有问题一键安装自动处理依赖Python.Runtime、FFmpeg等版本语义化管理避免“我的能用他的不行”内置最佳实践比如线程安全的引擎实例管理文档内嵌IntelliSense自动提示用法5.2 创建NuGet包项目结构QwenASR.NuGet/ ├── src/ │ ├── QwenASR.Core/ # 核心DLL项目C/CLI │ ├── QwenASR.Wpf/ # WPF控件库可选 │ └── QwenASR.AspNetCore/ # ASP.NET Core扩展 ├── build/ │ └── QwenASR.targets # MSBuild目标文件处理Python依赖 ├── contentFiles/ │ └── cs/ │ └── any/ │ └── python/ # 预置的Python脚本和配置 └── QwenASR.nuspec # NuGet包描述文件5.3 关键文件详解QwenASR.nuspec?xml version1.0 encodingutf-8? package xmlnshttp://schemas.microsoft.com/packaging/2013/05/nuspec.xsd metadata idQwenASR/id version1.0.0/version titleQwen3-ASR .NET SDK/title authorsQwen Team/authors ownersQwen Team/owners projectUrlhttps://github.com/QwenLM/Qwen3-ASR/projectUrl requireLicenseAcceptancefalse/requireLicenseAcceptance description.NET SDK for Qwen3-ASR speech recognition models. Supports local DLL, WPF controls, and ASP.NET Core integration./description releaseNotesInitial release with Qwen3-ASR-0.6B support/releaseNotes copyrightCopyright © 2026/copyright tagsspeech-recognition asr qwen dotnet csharp/tags dependencies group targetFrameworknet6.0 dependency idPython.Runtime version3.12.0 / /group group targetFrameworknet48 dependency idPython.Runtime version3.12.0 / /group /dependencies /metadata files file srcsrc\QwenASR.Core\bin\Release\net6.0\QwenASR.Core.dll targetlib\net6.0\QwenASR.Core.dll / file srcsrc\QwenASR.Core\bin\Release\net48\QwenASR.Core.dll targetlib\net48\QwenASR.Core.dll / file srcbuild\QwenASR.targets targetbuild\QwenASR.targets / file srccontentFiles\cs\any\python\**\* targetcontentFiles\cs\any\python\ / /files /packagebuild/QwenASR.targetsProject xmlnshttp://schemas.microsoft.com/developer/msbuild/2003 Target NameEnsurePythonEnvironment BeforeTargetsBuild PropertyGroup PythonHome Condition$(PythonHome) $(MSBuildThisFileDirectory)..\contentFiles\cs\any\python\/PythonHome PythonPath$(PythonHome)python.exe/PythonPath /PropertyGroup !-- 检查Python环境 -- Exec Commandquot;$(PythonPath)quot; --version ContinueOnErrortrue Output TaskParameterExitCode PropertyNamePythonExitCode / /Exec Error Condition$(PythonExitCode) ! 0 TextPython环境未找到请安装Python 3.10并设置PYTHONPATH环境变量 / /Target /Project5.4 发布与使用打包命令nuget pack QwenASR.nuspec -OutputDirectory ./packages在目标项目中安装dotnet add package QwenASR --source ./packages使用示例无需任何配置// Program.cs using QwenASR; var builder WebApplication.CreateBuilder(args); builder.Services.AddQwenASR(options { options.ModelPath Qwen/Qwen3-ASR-0.6B; options.Device cuda:0; }); var app builder.Build(); app.Map

相关新闻

GTE文本向量-中文-large实战教程:多任务结果后处理——JSON Schema校验与标准化输出

GTE文本向量-中文-large实战教程:多任务结果后处理——JSON Schema校验与标准化输出

GTE文本向量-中文-large实战教程:多任务结果后处理——JSON Schema校验与标准化输出 1. 为什么需要后处理?从原始输出到可用结果的跨越 你可能已经试过调用那个基于 ModelScope 的 iic/nlp_gte_sentence-embedding_chinese-large 多任务 Web 应用&…

2026/5/17 2:36:10 阅读更多 →
Qwen3-ASR-1.7B效果展示:多语言语音识别实测体验

Qwen3-ASR-1.7B效果展示:多语言语音识别实测体验

Qwen3-ASR-1.7B效果展示:多语言语音识别实测体验 1. 开场:听一句,就懂一句——这不是理想,是现在 你有没有过这样的经历:会议录音堆了十几条,却迟迟不敢点开听?客户语音留言语速快、带口音&am…

2026/5/17 2:36:08 阅读更多 →
Chord模型压缩:视频分析边缘部署实战

Chord模型压缩:视频分析边缘部署实战

Chord模型压缩:视频分析边缘部署实战 1. 为什么要在树莓派上跑视频分析模型 你有没有试过在树莓派上运行一个视频分析模型?我第一次尝试时,看着那个小小的绿色板子风扇狂转、温度飙升到70℃,而推理速度却卡在每秒0.3帧——连实时…

2026/7/3 4:25:37 阅读更多 →

最新新闻

如何永久冻结IDM试用期?5分钟掌握开源安全激活方案

如何永久冻结IDM试用期?5分钟掌握开源安全激活方案

如何永久冻结IDM试用期?5分钟掌握开源安全激活方案 【免费下载链接】IDM-Activation-Script IDM Activation & Trail Reset Script 项目地址: https://gitcode.com/gh_mirrors/id/IDM-Activation-Script 你是否厌倦了每隔30天就要为IDM试用期倒计时而烦恼…

2026/7/3 22:31:59 阅读更多 →
性能测试工具选型指南:JMeter、k6、Gatling等主流工具深度对比与实战避坑

性能测试工具选型指南:JMeter、k6、Gatling等主流工具深度对比与实战避坑

1. 项目概述:为什么我们需要对比性能测试工具?在软件开发和运维的日常工作中,性能测试是保障系统稳定、可靠、高效运行的关键环节。无论是上线前的压力摸底,还是线上突发流量下的瓶颈定位,一个趁手的性能测试工具就像外…

2026/7/3 22:29:59 阅读更多 →
如何轻松解密DRM加密视频:Video Decrypter完整操作指南

如何轻松解密DRM加密视频:Video Decrypter完整操作指南

如何轻松解密DRM加密视频:Video Decrypter完整操作指南 【免费下载链接】video_decrypter Decrypt video from a streaming site with MPEG-DASH Widevine DRM encryption. 项目地址: https://gitcode.com/gh_mirrors/vi/video_decrypter 还在为无法保存喜欢…

2026/7/3 22:23:58 阅读更多 →
Text-to-CAD UI终极指南:如何用一句话生成专业3D模型

Text-to-CAD UI终极指南:如何用一句话生成专业3D模型

Text-to-CAD UI终极指南:如何用一句话生成专业3D模型 【免费下载链接】text-to-cad-ui A lightweight UI for interacting with the Zoo Text-to-CAD API. 项目地址: https://gitcode.com/gh_mirrors/te/text-to-cad-ui 你是否曾经因为不会使用复杂的CAD软件…

2026/7/3 22:23:58 阅读更多 →
深入pytest_collection_modifyitems钩子:定制化测试用例执行与调度

深入pytest_collection_modifyitems钩子:定制化测试用例执行与调度

1. 项目概述如果你在用pytest做自动化测试,尤其是项目规模稍微大一点,或者对测试报告、用例执行顺序有特殊要求时,你大概率会碰到一个绕不开的“神器”——pytest_collection_modifyitems钩子函数。我第一次深入使用它,是因为一个…

2026/7/3 22:17:57 阅读更多 →
DVWA从入门到精通(八):SQL Injection(SQL注入)

DVWA从入门到精通(八):SQL Injection(SQL注入)

摘要:本文是《DVWA从入门到精通》系列的第八篇,带你全面掌握SQL Injection(SQL注入)模块的攻防全流程。从SQL注入的核心原理出发,逐步讲解Low、Medium、High三个级别的攻击手法与源码分析,并深入探讨Imposs…

2026/7/3 22:17:57 阅读更多 →

日新闻

Nginx防御TLS重协商攻击实战:从原理到配置与监控

Nginx防御TLS重协商攻击实战:从原理到配置与监控

1. 项目概述:为什么TLS重协商攻击至今仍需警惕十多年前的CVE-2011-1473,一个关于TLS/SSL协议重协商机制的漏洞,现在提起来还有必要吗?很多运维和开发朋友可能会觉得,这都老掉牙了,现代服务器和客户端不都默…

2026/7/3 0:03:59 阅读更多 →
华为防火墙双通道远程管理实战:Web与SSH配置详解

华为防火墙双通道远程管理实战:Web与SSH配置详解

1. 项目概述:为什么需要双通道远程管理防火墙?在任何一个稍具规模的企业网络里,防火墙都是那个默默守护在边界的关键角色。作为网络工程师,我们不可能每次都跑到机房,插上console线去配置它。远程管理能力,…

2026/7/3 0:03:59 阅读更多 →
AD74413R与PIC18F65K40的高精度工业数据采集方案

AD74413R与PIC18F65K40的高精度工业数据采集方案

1. 项目概述:AD74413R与PIC18F65K40的协同工作在工业自动化和精密测量领域,同时实现高精度模数转换(ADC)和数模转换(DAC)功能是许多复杂系统的核心需求。AD74413R作为一款四通道可配置模拟输入/输出器件,与PIC18F65K40微控制器的组合&#xf…

2026/7/3 0:05:59 阅读更多 →

周新闻

月新闻