当前位置: 首页 > news >正文

【C#实现手写Ollama服务交互,实现本地模型对话】

前言

C#手写Ollama服务交互,实现本地模型对话

最近使用C#调用OllamaSharpe库实现Ollama本地对话,然后思考着能否自己实现这个功能。经过一番查找,和查看OllamaSharpe源码发现确实可以。其实就是开启Ollama服务后,发送HTTP请求,获取返回结果以及一些数据处理。

基本流程

1、启动Ollama服务进程。
2、创建HttpClient对象。
3、创建请求体(参数:模型名称、提示语、是否流式生成)。
4、将请求体序列化为JSON。
5、创建HTTP请求内容。
6、发送POST请求,并确保请求成功。
7、读取并返回响应内容,并解析相应字符串。
8、返回结果。

 		//创建请求体:模型名称、提示语、是否流式生成var request = new RequestModel{Model = model,Prompt = prompt,Stream = false};// 将请求体序列化为JSONvar json = JsonSerializer.Serialize(request);// 创建HTTP请求内容var content = new StringContent(json, Encoding.UTF8, "application/json");// 发送POST请求var response = await _httpClient.PostAsync("/api/generate", content);// 确保请求成功response.EnsureSuccessStatusCode();// 读取并返回响应内容string responseString = await response.Content.ReadAsStringAsync();///解析相应字符串ResponseModel results = JsonSerializer.Deserialize<ResponseModel>(responseString);//返回结果return results.Response;

项目结构

OllamaClient :实现基本的对话请求、获取模型列表功能。
Model :创建模型结果的一些参数
RequestModel:请求参数模型
ResponseModel:结果参数模型,用于解析返回的结果。
MainWindow:用户界面
MainWindowViewModel:界面交互业务处理

在这里插入图片描述

案例

模型加载

在这里插入图片描述

发送聊天

在这里插入图片描述

代码

OllamaSharpe

Ollama客户端 OllamaClient

public class OllamaClient{public IEnumerable<Model> ModelList { get; set; }private readonly HttpClient _httpClient;public OllamaClient(string baseAddress = "http://localhost:11434"){_httpClient = new HttpClient{BaseAddress = new Uri(baseAddress)};ExecuteCommand("ollama list");  //启动Ollama服务}/// <summary>/// 异步生成文本/// </summary>public async Task<string> GenerateTextAsync(string model, string prompt){try{//创建请求体:模型名称、提示语、是否流式生成var request = new RequestModel{Model = model,Prompt = prompt,Stream = false};// 将请求体序列化为JSONvar json = JsonSerializer.Serialize(request);// 创建HTTP请求内容var content = new StringContent(json, Encoding.UTF8, "application/json");// 发送POST请求var response = await _httpClient.PostAsync("/api/generate", content);// 确保请求成功response.EnsureSuccessStatusCode();// 读取并返回响应内容string responseString = await response.Content.ReadAsStringAsync();///解析相应字符串ResponseModel results = JsonSerializer.Deserialize<ResponseModel>(responseString);//返回结果return results.Response;}catch (HttpRequestException e){throw new Exception($"Request failed: {e.Message}");}}/// <summary>/// 异步流式生成文本/// </summary>public async IAsyncEnumerable<string> StreamGenerateTextAsync(string model, string prompt){//创建请求体:模型名称、提示语、是否流式生成var request = new RequestModel{Model = model,Prompt = prompt, Stream = true};// 将请求体序列化为JSONvar json = JsonSerializer.Serialize(request);//创建HTTP请求内容var content = new StringContent(json, Encoding.UTF8, "application/json");//发送POST请求using var response = await _httpClient.PostAsync("/api/generate", content);// 确保请求成功response.EnsureSuccessStatusCode();// 读取流并解析为ResponseModelusing var stream = await response.Content.ReadAsStreamAsync();// 创建流读取器using var reader = new StreamReader(stream);// 循环读取流while (!reader.EndOfStream){// 读取一行var line = await reader.ReadLineAsync();// 如果行不为空,则解析为ResponseModel并返回if (!string.IsNullOrEmpty(line)){var partial = JsonSerializer.Deserialize<ResponseModel>(line);yield return partial.Response;}}}/// <summary>/// 异步获取本地模型列表/// </summary>public async Task<IEnumerable<Model>> ListLocalModelsAsync(){//相应请求HttpResponseMessage responseMessage = await _httpClient.GetAsync("/api/tags").ConfigureAwait(false);;//确保请求成功responseMessage.EnsureSuccessStatusCode();//读取响应string response = await responseMessage.Content.ReadAsStringAsync();//读取流并解析为LocalModelsLocalModels localModel = JsonSerializer.Deserialize<LocalModels>(response);await Task.Delay(3000);//返回结果ModelList = localModel.Models;return localModel.Models;}// <summary>/// 执行CMD指令:用于启动Ollama服务,/// </summary>public static bool ExecuteCommand(string command){// 创建一个新的进程启动信息ProcessStartInfo processStartInfo = new ProcessStartInfo{FileName = "cmd.exe",           // 设置要启动的程序为cmd.exeArguments = $"/C {command}",    // 设置要执行的命令UseShellExecute = true,         // 使用操作系统shell启动进程CreateNoWindow = false,         //不创建窗体};try{Process process = Process.Start(processStartInfo);// 启动进程process.WaitForExit();    // 等待进程退出process.Close();          // 返回是否成功执行return process.ExitCode == 0;}catch (Exception ex){Debug.WriteLine($"发生错误: {ex.Message}");// 其他异常处理return false;}}}

请求模型:RequestModel

/// <summary>
/// 请求模型
/// </summary>
public class RequestModel
{public string Model { get; set; }public string Prompt { get; set; }public bool Stream { get; set; }
}

响应模型:ResponseModel

/// <summary>
/// 响应模型
/// </summary>
public class ResponseModel
{/// <summary>/// 模型名称/// </summary>[JsonPropertyName("model")]public string Model { get; set; }/// <summary>/// 创建时间/// </summary>[JsonPropertyName("created_at")]public string CreatedTime { get; set; }/// <summary>/// 响应:返回文本/// </summary>[JsonPropertyName("response")]public string Response { get; set; }/// <summary>/// 是否结束/// </summary>[JsonPropertyName("done")]public bool Done { get; set; }/// <summary>/// 结束原因/// </summary>[JsonPropertyName("done_reason")]public string Done_Reason { get; set; }/// <summary>/// 上下文/// </summary>[JsonPropertyName("context")]public List<int> Context { get; set; }/// <summary>/// 总耗时/// </summary>[JsonPropertyName("total_duration")]public long TotalDuration { get; set; }/// <summary>/// 加载耗时/// </summary>[JsonPropertyName("load_duration")]public long LoadDuration { get; set; }/// <summary>/// 提示词评估次数/// </summary>[JsonPropertyName("prompt_eval_count")]public long PromptEvalCount { get; set; }/// <summary>/// 提示词评估耗时/// </summary>[JsonPropertyName("prompt_eval_duration")]public long PromptEvalDuration { get; set; }/// <summary>/// 评估次数/// </summary>[JsonPropertyName("eval_count")]public long EvalCount { get; set; }/// <summary>/// 评估耗时/// </summary>[JsonPropertyName("eval_duration")]public long EvalDuration { get; set; }
}

结果模型:LocalModels | Model

/// <summary>
/// 本地模型
/// </summary>
public class LocalModels
{[JsonPropertyName("models")]public IEnumerable<Model> Models { get; set; }
}
/// <summary>
/// 模型
/// </summary>
public class Model
{/// <summary>/// 模型名称/// </summary>[JsonPropertyName("name")]public string Name { get; set; }/// <summary>/// 模型名称/// </summary>[JsonPropertyName("model")]public string ModelName { get; set; }/// <summary>/// 修改时间/// </summary>[JsonPropertyName("modified_at")]public DateTime ModifiedAt { get; set; }/// <summary>/// 大小/// </summary>[JsonPropertyName("size")]public long Size { get; set; }/// <summary>/// /// </summary>[JsonPropertyName("digest")]public string Digest { get; set; }/// <summary>/// 模型细节/// </summary>[JsonPropertyName("details")]public ModelDetails Details { get; set; }
}/// <summary>
/// 模型细节
/// </summary>
public class ModelDetails
{/// <summary>/// 父模型/// </summary>[JsonPropertyName("parent_model")]public string ParentModel { get; set; }/// <summary>/// 格式/// </summary>[JsonPropertyName("format")]public string Format { get; set; }/// <summary>/// /// </summary>[JsonPropertyName("family")]public string Family { get; set; }/// <summary>/// /// </summary>[JsonPropertyName("families")]public List<string> Families { get; set; }/// <summary>/// 参数大小/// </summary>[JsonPropertyName("parameter_size")]public string ParameterSize { get; set; }/// <summary>/// 质量等级/// </summary>[JsonPropertyName("quantization_level")]public string QuantizationLevel { get; set; }
}

简单的界面

MainWindow

<Window.DataContext><local:MainWindowViewModel x:Name="ViewModel"/>
</Window.DataContext>
<Grid><Grid.RowDefinitions><RowDefinition Height="50"/><RowDefinition Height="*"/><RowDefinition Height="300"/></Grid.RowDefinitions><Grid Grid.Row="0"><WrapPanel VerticalAlignment="Center" Margin="5"><Label Content="模型列表" Margin="5"/><ComboBox Width="200" Margin="5" Name="ModelListBox"ItemsSource="{Binding ModelCollection}"SelectedItem="{Binding SelectedModel}"/></WrapPanel></Grid><Grid Grid.Row="1"><TextBox x:Name="OutputBox" Text="{Binding OutputText}"ScrollViewer.HorizontalScrollBarVisibility="Visible"ScrollViewer.VerticalScrollBarVisibility="Visible"/></Grid><Grid Grid.Row="2"><Grid.RowDefinitions><RowDefinition Height="*"/><RowDefinition Height="50"/></Grid.RowDefinitions><TextBox Grid.Row="0" x:Name="InputBox" Background="#AAAAAA"Text="{Binding InputText}"TextWrapping="WrapWithOverflow"ScrollViewer.VerticalScrollBarVisibility="Auto"ScrollViewer.HorizontalScrollBarVisibility="Auto" ></TextBox><WrapPanel Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="5"><Button  Grid.Row="1"  Width="100" Height="30" x:Name="Btn_Submit" Command="{Binding SendQuestionCommand}">发送</Button></WrapPanel></Grid>
</Grid>

MainWindowViewModel

public class MainWindowViewModel: PropertyChangedBase
{#region 字段、属性private string _inputText = "";         //输入文本private string _outputText = "";        //输出文本private OllamaClient _ollama;            //Ollama客户端private string _selectedModel = "deepseek-r1:1.5b";     //选择模型private ObservableCollection<string> _modelCollection;  //模型列表#region 属性public ObservableCollection<string> ModelCollection{get => _modelCollection;set{if (_modelCollection != value){_modelCollection = value;OnPropertyChanged();}}}public string SelectedModel{get => _selectedModel;set{if (_selectedModel != value){_selectedModel = value;OnPropertyChanged();}}}private OllamaClient Ollama { get => _ollama; }public string OutputText{get => _outputText;set{if (_outputText != value){_outputText = value;OnPropertyChanged();}}}public string InputText{get => _inputText;set{if (_inputText != value){_inputText = value;OnPropertyChanged();}}}public ICommand SendQuestionCommand { get; set; }#endregion#endregionpublic MainWindowViewModel(){Initialze();}/// <summary>/// 初始化/// </summary>private void Initialze(){_ollama = new OllamaClient();_modelCollection = new ObservableCollection<string>();SelectedModel = "deepseek-r1:1.5b";var models = Ollama.ListLocalModelsAsync();AppendLine($"模型列表;{Environment.NewLine}");foreach (var model in models.Result){ModelCollection.Add(model.ModelName);AppendLine($"{model.ModelName}{FormatFileSize(model.Size)}\r\n");}SendQuestionCommand = new ParameterlessCommand(OnSendQuestion);}/// <summary>/// 格式化文件大小/// </summary>private string FormatFileSize(long bytes){string[] sizes = { "B", "KB", "MB", "GB", "TB" };int order = 0;while (bytes >= 1024 && order < sizes.Length - 1){order++;bytes = bytes / 1024;}return $"{bytes:0.##} {sizes[order]}";}/// <summary>/// 发送文本/// </summary>public async void OnSendQuestion(){try{AppendLine($"【用户】{InputText}\r\n\r\n");AppendLine($"【AI】\r\n\r\n");await foreach (var answerToken in Ollama.StreamGenerateTextAsync(SelectedModel, InputText)){AppendText(answerToken);}AppendLine($"\r\n");}catch (Exception ex){AppendText($"Error: {ex.Message}");}}/// <summary>/// 附加文本/// </summary>private async void AppendText(string text){Debug.Print($"{text}");OutputText += text;}/// <summary>/// 附加文本行/// </summary>private async void AppendLine(string text){Debug.Print($"{text}");OutputText += $"{text}\r\n";}
}
 /// <summary>/// 属性变更/// </summary>public class PropertyChangedBase : INotifyPropertyChanged{public event PropertyChangedEventHandler PropertyChanged;protected void OnPropertyChanged([CallerMemberName] string propertyName = null){PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));}}

总结

案例代码实现了与Ollama的HTTP交互,通过使用HttpClient、JSON序列化和错误处理,提供了一个简洁的异步文本生成接口。适合直接调用本地Ollama服务的场景,更多功能,可以后续拓展。

相关文章:

【C#实现手写Ollama服务交互,实现本地模型对话】

前言 C#手写Ollama服务交互&#xff0c;实现本地模型对话 最近使用C#调用OllamaSharpe库实现Ollama本地对话&#xff0c;然后思考着能否自己实现这个功能。经过一番查找&#xff0c;和查看OllamaSharpe源码发现确实可以。其实就是开启Ollama服务后&#xff0c;发送HTTP请求&a…...

Android Glide 框架线程管理模块原理的源码级别深入分析

一、引言 在现代的 Android 应用开发中&#xff0c;图片加载是一个常见且重要的功能。Glide 作为一款广泛使用的图片加载框架&#xff0c;以其高效、灵活和易用的特点受到了开发者的青睐。其中&#xff0c;线程管理模块是 Glide 框架中至关重要的一部分&#xff0c;它负责协调…...

每天记录一道Java面试题---day32

MySQL索引的数据结构、各自优劣 回答重点 B树&#xff1a;是一个平衡的多叉树&#xff0c;从根节点到每个叶子节点的高度差不超过1&#xff0c;而且同层级的节点间有指针相互连接。在B树上的常规检索&#xff0c;从根节点到叶子节点的搜索效率基本相当&#xff0c;不会出现大…...

Vue3 Pinia 符合直觉的Vue.js状态管理库

Pinia 符合直觉的Vue.js状态管理库 什么时候使用Pinia 当两个关系非常远的组件&#xff0c;要传递参数时使用Pinia组件的公共参数使用Pinia...

深度学习与大模型基础-向量

大家好&#xff01;今天我们来聊聊向量&#xff08;Vector&#xff09;。别被这个词吓到&#xff0c;其实向量在我们的生活中无处不在&#xff0c;只是我们没注意罢了。 1. 向量是什么&#xff1f; 简单来说&#xff0c;向量就是有大小和方向的量。比如你从家走到学校&#x…...

【网络编程】完成端口 IOCP

10.11 完成端口 10.11.1 基本概念 完成端口的全称是I/O 完成端口&#xff0c;英文为IOCP(I/O Completion Port) 。IOCP是一个异 步I/O 的 API, 可以高效地将I/O 事件通知给应用程序。与使用select() 或是其他异步方法不同 的是&#xff0c;一个套接字与一个完成端口关联了起来…...

《苍穹外卖》SpringBoot后端开发项目重点知识整理(DAY1 to DAY3)

目录 一、在本地部署并启动Nginx服务1. 解压Nginx压缩包2. 启动Nginx服务3. 验证Nginx是否启动成功&#xff1a; 二、导入接口文档1. 黑马程序员提供的YApi平台2. YApi Pro平台3. 推荐工具&#xff1a;Apifox 三、Swagger1. 常用注解1.1 Api与ApiModel1.2 ApiModelProperty与Ap…...

管理网络安全

防火墙在 Linux 系统安全中有哪些重要的作用&#xff1f; 防火墙作为网络安全的第一道防线&#xff0c;能够根据预设的规则&#xff0c;对进出系统的网络流量进行严格筛选。它可以阻止未经授权的外部访问&#xff0c;只允许符合规则的流量进入系统&#xff0c;从而保护系统免受…...

明日直播|Go IoT 开发平台,开启万物智联新征程

在物联网技术飞速发展的当下&#xff0c;物联网行业却深受协议碎片化、生态封闭、开发低效等难题的困扰。企业和开发者们渴望找到一个能突破这些困境&#xff0c;实现高效、便捷开发的有力工具。 3 月 11 日&#xff08;星期二&#xff09;19:00&#xff0c;GitCode 特别邀请独…...

系统架构设计师—系统架构设计篇—软件架构风格

文章目录 概述经典体系结构风格数据流风格批处理管道过滤器对比 调用/返回风格主程序/子程序面向对象架构风格层次架构风格 独立构件风格进程通信事件驱动的系统 虚拟机风格解释器基于规则的系统 仓库风格&#xff08;数据共享风格&#xff09;数据库系统黑板系统超文本系统 闭…...

【MySQL_04】数据库基本操作(用户管理--配置文件--远程连接--数据库信息查看、创建、删除)

文章目录 一、MySQL 用户管理1.1 用户管理1.11 mysql.user表详解1.12 添加用户1.13 修改用户权限1.14 删除用户1.15 密码问题 二、MySQL 配置文件2.1 配置文件位置2.2 配置文件结构2.3 常用配置参数 三、MySQL远程连接四、数据库的查看、创建、删除4.1 查看数据库4.2 创建、删除…...

【Zinx】Day5-Part4:Zinx 的连接属性设置

目录 Day5-Part4&#xff1a;Zinx 的连接属性设置给连接添加连接配置的接口连接属性方法的实现 测试 Zinx-v1.0总结 Day5-Part4&#xff1a;Zinx 的连接属性设置 在 Zinx 当中&#xff0c;我们使用 Server 来开启服务并监听指定的端口&#xff0c;当接收到来自客户端的连接请求…...

【英伟达AI论文】多模态大型语言模型的高效长视频理解

摘要&#xff1a;近年来&#xff0c;基于视频的多模态大型语言模型&#xff08;Video-LLMs&#xff09;通过将视频处理为图像帧序列&#xff0c;显著提升了视频理解能力。然而&#xff0c;许多现有方法在视觉主干网络中独立处理各帧&#xff0c;缺乏显式的时序建模&#xff0c;…...

小程序事件系统 —— 32 事件系统 - 事件分类以及阻止事件冒泡

在微信小程序中&#xff0c;事件分为 冒泡事件 和 非冒泡事件 &#xff1a; 冒泡事件&#xff1a;当一个组件的事件被触发后&#xff0c;该事件会向父节点传递&#xff1b;&#xff08;如果父节点中也绑定了一个事件&#xff0c;父节点事件也会被触发&#xff0c;也就是说子组…...

全球首款 5G-A 人形机器人发布

全球首款 5G-A 人形机器人于世界移动通信大会&#xff08;MWC2025&#xff09;上由中国移动、华为、乐聚联合发布。以下是关于这款机器人的详细介绍&#xff1a; 名称与背景 名称9&#xff1a;这款人形机器人名为 “夸父”&#xff0c;是中国移动、华为与乐聚机器人在 GTI 平台…...

Tomcat 新手入门指南

Tomcat 新手入门指南 Apache Tomcat 是一个开源的 Java Servlet 容器和 Web 服务器&#xff0c;广泛用于部署和运行 Java Web 应用程序。以下是 Tomcat 的入门指南&#xff0c;帮助你快速上手。 1. 安装 Tomcat 步骤 1: 下载 Tomcat 访问 Apache Tomcat 官网。选择适合的版…...

Flink-DataStreamAPI-生成水印

下面我们将学习Flink提供的用于处理事件时间戳和水印的API&#xff0c;也会介绍有关事件时间、流转时长和摄取时间&#xff0c;下面就让我们跟着官网来学习吧 一、水印策略介绍 为了处理事件时间&#xff0c;Flink需要知道事件时间戳&#xff0c;这意味着流中的每个元素都需要…...

【单片机】ARM 处理器简介

ARM 公司简介 ARM&#xff08;Advanced RISC Machine&#xff09; 是英国 ARM 公司&#xff08;原 Acorn RISC Machine&#xff09; 开发的一种精简指令集&#xff08;RISC&#xff09; 处理器架构。ARM 处理器因其低功耗、高性能、广泛适用性&#xff0c;成为嵌入式系统、移动…...

Flutter——最详细原生交互(MethodChannel、EventChannel、BasicMessageChannel)使用教程

MethodChannel&#xff08;方法通道&#xff09; 用途&#xff1a;实现 双向通信&#xff0c;用于调用原生平台提供的 API 并获取返回结果。 场景&#xff1a;适合一次性操作&#xff0c;如调用相机、获取设备信息等。 使用步骤&#xff1a; Flutter 端&#xff1a;通过 Meth…...

Kafka常用指令(详细)

Kafka常用指令&#xff08;详细&#xff09; 启停命令 前台启动 前台启动命令 ./bin/kafka-server-start.sh config/server.properties 后台启动方式1 后台启动命令加上参数-daemon&#xff0c;窗口关闭之后kafka后台程序继续运行 ./bin/kafka-server-start.sh -daemon co…...

国防科技大学计算机基础课程笔记02信息编码

1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制&#xff0c;因此这个了16进制的数据既可以翻译成为这个机器码&#xff0c;也可以翻译成为这个国标码&#xff0c;所以这个时候很容易会出现这个歧义的情况&#xff1b; 因此&#xff0c;我们的这个国…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...

优选算法第十二讲:队列 + 宽搜 优先级队列

优选算法第十二讲&#xff1a;队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

Typeerror: cannot read properties of undefined (reading ‘XXX‘)

最近需要在离线机器上运行软件&#xff0c;所以得把软件用docker打包起来&#xff0c;大部分功能都没问题&#xff0c;出了一个奇怪的事情。同样的代码&#xff0c;在本机上用vscode可以运行起来&#xff0c;但是打包之后在docker里出现了问题。使用的是dialog组件&#xff0c;…...

C# 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案

这个问题我看其他博主也写了&#xff0c;要么要会员、要么写的乱七八糟。这里我整理一下&#xff0c;把问题说清楚并且给出代码&#xff0c;拿去用就行&#xff0c;照着葫芦画瓢。 问题 在继承QWebEngineView后&#xff0c;重写mousePressEvent或event函数无法捕获鼠标按下事…...

Yolov8 目标检测蒸馏学习记录

yolov8系列模型蒸馏基本流程&#xff0c;代码下载&#xff1a;这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中&#xff0c;**知识蒸馏&#xff08;Knowledge Distillation&#xff09;**被广泛应用&#xff0c;作为提升模型…...

WebRTC从入门到实践 - 零基础教程

WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC&#xff1f; WebRTC&#xff08;Web Real-Time Communication&#xff09;是一个支持网页浏览器进行实时语音…...