ChatUI:使用Gradio.NET为LLamaWorker快速创建大模型演示界面

Gradio.NET 是 Gradio 的.NET 移植版本。它是一个能够助力迅速搭建机器学习模型演示界面的库,其提供了简洁的 API,仅需寥寥数行代码就能创建出一个具备交互性的界面。在本篇文章中,我们将会阐述如何借助 Gradio.NET 为 LLamaWorker 快捷地创建一个大型模型演示界面。

1. 背景

前面一篇文章我们认识了 LLamaWorker 项目,它是一个专为 .NET 开发者设计的大型语言模型服务。LLamaWorker 提供了与 OpenAI 类似的 API,支持多模型切换、流式响应、嵌入支持等特性。此外,LLamaWorker 还提供了一个基于 Gradio.NET 的 UI 演示,使得开发者能够更快地体验和调试模型。

2. Gradio.NET 简介

Gradio.NET 是 Gradio 的.NET 移植版本。Gradio 作为一个开源 Python 包,允许为机器学习模型、API 或任何任意 Python 函数快速构建演示或 Web 应用程序,无需具备 JavaScript、CSS 经验。使用 Gradio,能够基于机器学习模型或数据科学工作流迅速创建一个用户友好的界面,让用户可以通过浏览器进行诸如拖放图像、粘贴文本、录制声音等操作,并与演示程序进行交互。

3. 为什么选择 Gradio.NET

LLamaWorker 是提供有 swagger 页面的 API 服务,但是 swagger 页面并不能直观地展示模型的效果。提供一个直观的演示界面,能够让用户更快地了解模型的效果,同时也能够帮助开发者更快地调试模型,是我一直在考虑的问题。

当然,选择技术框架是一个关键的决策。起初,我考虑使用 Vue3 从零开始搭建,但这需要耗费大量的时间和精力。恰好在这个时候,我发现了社区新推出的开源项目 Gradio.NET。

我抱着学习新技术的心态尝试了一下,同时也想为开发者们测试一下这个新框架,发现问题并提出改进的建议。对于初次接触 Gradio 的人,比如我来说,可能会在初期感到有些吃力。然而,如果之前就熟悉 Python 的 Gradio,那么使用 Gradio.NET 将会变得非常轻松。

需要注意的是,目前 Gradio.NET 仍在不断完善之中,还有许多库尚未完成迁移。但我相信,只要大家共同努力,积极参与建设,一定能够让 Gradio.NET 变得更加完善和强大。

4. 为 LLamaWorker 创建演示界面

接下来,我们将会为 LLamaWorker 创建一个简单的演示界面。整体代码包含注释不过 300 行,但却能够实现一个具有交互性的界面。在这个界面中,我们可以输入文本,然后点击“生成”按钮,即可获取模型的回复。

在 ChatUI 项目中,我们使用了 Gradio.NET 多个组件和相关功能,期间也发现并提交了多个 issues 到 Gradio.NET。对于学习 Gradio.NET 的同学来说,这个实际的使用案例将会非常有帮助。特别是刷新 Dropdown,网络请求,以及流式响应的处理等。

4.1. 服务设置

LLamaWorker 提供了API Key 的支持,并提供了模型配置信息获取的接口,在 ChatUI 项目中,我们将会使用这些接口来获取模型的配置信息。

在页面的顶部,我们设置了一个输入框用于输入 LLamaWorker 服务的 URL,一个输入框用于输入 API Key,一个按钮用于获取模型配置信息,以及一个下拉框用于选择模型。

gr.Markdown("# LLamaWorker");
Textbox input,token;
Dropdown model;
Button btnset;using (gr.Row())
{input = gr.Textbox("http://localhost:5000", placeholder: "LLamaWorker Server URL", label: "Server");token = gr.Textbox(placeholder: "API Key", label: "API Key",  maxLines:1, type:TextboxType.Password);btnset = gr.Button("Get Models", variant: ButtonVariant.Primary);model = gr.Dropdown(choices: [], label: "Model Select", allowCustomValue:true);
}

在上面的代码中,我们设置了一个输入框用于输入 API Key,并惊奇设置为密码输入框 TextboxType.Password,以便隐藏输入的内容。这里的 Dropdown 组件我们没有设置选项,并且允许其可以获取用户的自定义值 allowCustomValue:true,方便用户输入自定义的模型名称,同时也可以使 ChatUI 项目调用其他的服务,比如阿里灵积的大模型服务等。

请添加图片描述

上图展示的是在移动端的界面,Gradio.NET 会自动处理流式布局,使得界面在不同设备上都能够正常显示。

在设置好基础界面后,我们需要为按钮添加点击事件,以便获取模型配置信息。在 Gradio.NET 中,可以通过 ButtonClick 事件来实现。

btnset?.Click(update_models, inputs: [input, token], outputs: [model]);

在点击按钮后,会调用 update_models 方法,该方法会向 LLamaWorker 服务发送请求,获取模型配置信息,并更新下拉框的选项。

static async Task<Output> update_models(Input input)
{string server = Textbox.Payload(input.Data[0]);string token = Textbox.Payload(input.Data[1]);if (server == ""){throw new Exception("Server URL cannot be empty.");}if (!string.IsNullOrWhiteSpace(token)){Utils.client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);}var res = await Utils.client.GetFromJsonAsync<ConfigModels>(server + "/models/config");if (res?.Models == null || res.Models.Count==0){throw new Exception("Failed to fetch models from the server.");}Utils.config = res;var models = res.Models.Select(x => x.Name).ToList();return gr.Output(gr.Dropdown(choices: models,value: models[res.Current], interactive: true));
}

update_models 方法中,我们首先获取输入的服务 URL 和 API Key,然后向服务发送请求获取模型配置信息。如果请求成功,我们将会更新下拉框的选项。在这个过程中,我们还会根据服务返回的当前模型,设置下拉框的默认值。

这里的网络请求使用了Utils类中HttpClient的单例模式,以便在整个项目中共享一个HttpClient实例。HttpClient实例是设计为可以被多个请求重用的,这有助于减少资源消耗和提高应用程序的性能。

4.2. Dropdown 组件的模型切换

在获取到模型配置信息后,我们需要为下拉框的选项添加点击事件,以便切换模型。在 Gradio.NET 中,可以通过 DropdownChange 事件来实现。

model?.Change(change_models, inputs: [input, model], outputs: [model]);

在点击下拉框选项后,会调用 change_models 方法,该方法会向 LLamaWorker 服务发送请求,切换模型。

static async Task<Output> change_models(Input input)
{string server = Textbox.Payload(input.Data[0]);string model = Dropdown.Payload(input.Data[1]).Single();var models = Utils.config?.Models?.Select(x => x.Name).ToList();// 未使用服务端模型配置,允许自定义模型if (models == null){return gr.Output(gr.Dropdown(choices: [model], value: model, interactive: true, allowCustomValue: true));}if (server == ""){throw new Exception("Server URL cannot be empty.");}// 取得模型是第几个var index = models.IndexOf(model);if (index == -1){throw new Exception("Model not found in the list of available models.");}if (Utils.config.Current == index){// 没有切换模型return gr.Output(gr.Dropdown(choices: models, value: model, interactive: true));}var res = await Utils.client.PutAsync($"{server}/models/{index}/switch", null);// 请求失败if (!res.IsSuccessStatusCode){// 错误信息未返回gr.Warning("Failed to switch model.");await Task.Delay(2000);return gr.Output(gr.Dropdown(choices: models, value: models[Utils.config.Current], interactive: true));}Utils.config.Current = index;return gr.Output(gr.Dropdown(choices: models, value: model, interactive: true));
}

change_models 方法中,我们首先获取模型配置信息,然后获取输入的服务 URL 和模型名称,向服务发送请求切换模型。如果请求成功,我们将会更新下拉框的选项。同时在不存在服务端模型配置的情况下,我们允许用户自定义模型。

这里需要注意的是,在切换失败的情况下,我们会展示一个警告信息,并在2秒后恢复下拉框的选项。但是,恢复下拉框的选项会重复调用Change事件,这样会造成Warning提示框不显示,所以需要在Warning提示框显示后延迟2秒再恢复下拉框的选项,重复调用倒是不算大问题。

4.3. 模型交互

在设置好服务和模型切换后,我们添加一个Tab组件,用于展示模型的不同能力对话和文本生成。

using (gr.Tab("Chat"))
{// Chat 交互界面组件
}
using (gr.Tab("Completion"))
{// Completion 交互界面组件
}

在 Chat 交互界面中,我们可以直接使用 Chatbot 组件,用于展示对话消息列表,并添加一个输入框用于输入文本,同时提供三个按钮用于发送文本、重新生成和清空对话。

Chatbot chatBot = gr.Chatbot(label: "LLamaWorker Chat", showCopyButton: true, placeholder: "Chat history",height:520);
Textbox userInput = gr.Textbox(label: "Input", placeholder: "Type a message...");Button sendButton, resetButton, regenerateButton;using (gr.Row())
{sendButton = gr.Button("✉️ Send", variant: ButtonVariant.Primary);regenerateButton = gr.Button("🔃 Retry", variant: ButtonVariant.Secondary);resetButton = gr.Button("🗑️  Clear", variant: ButtonVariant.Stop);
}

接下来我们添加三个按钮的点击事件,以便发送文本、重新生成和清空对话。

sendButton?.Click(streamingFn: i =>
{string server = Textbox.Payload(i.Data[0]);string token = Textbox.Payload(i.Data[3]);string model = Dropdown.Payload(i.Data[4]).Single();IList<ChatbotMessagePair> chatHistory = Chatbot.Payload(i.Data[1]);string userInput = Textbox.Payload(i.Data[2]);return ProcessChatMessages(server, token, model, chatHistory, userInput);
}, inputs: [input, chatBot, userInput, token, model], outputs: [userInput, chatBot]);
regenerateButton?.Click(streamingFn: i =>
{string server = Textbox.Payload(i.Data[0]);string token = Textbox.Payload(i.Data[2]);string model = Dropdown.Payload(i.Data[3]).Single();IList<ChatbotMessagePair> chatHistory = Chatbot.Payload(i.Data[1]);if (chatHistory.Count == 0){throw new Exception("No chat history available for regeneration.");}string userInput = chatHistory[^1].HumanMessage.TextMessage;chatHistory.RemoveAt(chatHistory.Count - 1);return ProcessChatMessages(server, token, model, chatHistory, userInput);
}, inputs: [input, chatBot, token, model], outputs: [userInput, chatBot]);
resetButton?.Click(i => Task.FromResult(gr.Output(Array.Empty<ChatbotMessagePair>(), "")), outputs: [chatBot, userInput]);

在点击按钮后,会调用 ProcessChatMessages 方法,该方法会向 LLamaWorker 服务发送请求,获取模型的回复,并更新对话消息列表。

static async IAsyncEnumerable<Output> ProcessChatMessages(string server, string token, string model, IList<ChatbotMessagePair> chatHistory, string message)
{if (message == ""){yield return gr.Output("", chatHistory);yield break;}// 添加用户输入到历史记录chatHistory.Add(new ChatbotMessagePair(message, ""));// sse 请求var request = new HttpRequestMessage(HttpMethod.Post, $"{server}/v1/chat/completions");request.Headers.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("text/event-stream"));if (!string.IsNullOrWhiteSpace(token)){Utils.client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);}var messages =new List<ChatCompletionMessage>();foreach (var item in chatHistory){messages.Add(new ChatCompletionMessage{role = "user",content = item.HumanMessage.TextMessage});messages.Add(new ChatCompletionMessage{role = "assistant",content = item.AiMessage.TextMessage});}messages.Add(new ChatCompletionMessage{role = "user",content = message});request.Content = new StringContent(JsonSerializer.Serialize(new ChatCompletionRequest{stream = true,messages = messages.ToArray(),model = model,max_tokens = 1024,temperature = 0.9f,top_p = 0.9f,}), Encoding.UTF8, "application/json");using var response = await Utils.client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);response.EnsureSuccessStatusCode();using (var stream = await response.Content.ReadAsStreamAsync())using (var reader = new System.IO.StreamReader(stream)){while (!reader.EndOfStream){var line = await reader.ReadLineAsync();if (line.StartsWith("data:")){var data = line.Substring(5).Trim();// 结束if(data == "[DONE]"){yield break;}// 解析返回的数据var completionResponse = JsonSerializer.Deserialize<ChatCompletionChunkResponse>(data);var text = completionResponse?.choices[0]?.delta?.content;if (string.IsNullOrEmpty(text)){continue;}chatHistory[^1].AiMessage.TextMessage += text;yield return gr.Output("", chatHistory);}}}
}

ProcessChatMessages 方法中,我们首先获取输入的服务 URL、API Key、对话消息列表和文本,然后向服务发送请求获取模型的回复。在这个过程中,我们使用了 SSE 请求,以便实现流式响应。在获取到模型的回复后,我们将会更新对话消息列表。

对于文本生成界面,我们可以直接使用 Textbox 组件,用于输入文本,同时添加一个按钮用于生成文本。其相关的事件处理和流程与 Chat 交互界面类似,这里不再赘述。完整的代码可以在 LLamaWorker 项目的 ChatUI 中查看。

5. 效果

在运行 LLamaWorker 服务后,我们可以在 ChatUI 项目中输入服务 URL 和 API Key(若有配置),然后点击“Get Models”按钮,即可获取模型配置信息。接着,我们可以选择模型,然后在 Chat 交互界面中输入文本,点击“Send”按钮,即可获取模型的回复。

当然你也可以选择其他服务,比如阿里灵积的大模型服务,只需要修改服务 URL:https://dashscope.aliyuncs.com/compatible-mode 和 API Key,通过手动输入你要体验的模型,如 “qwen-long” 即可体验阿里灵积的大模型服务。

请添加图片描述

6. 总结

在本篇文章中,我们阐述了如何使用 Gradio.NET 为 LLamaWorker 快捷地创建一个大型模型演示界面。通过 Gradio.NET,我们可以快速搭建一个具备交互性的界面,帮助开发者更快地了解和体验模型的效果。同时,我们还展示了如何使用 Gradio.NET 的多个组件和相关功能,以及如何处理网络请求和流式响应。希望这个实际的使用案例能够帮助大家更好地学习和使用 Gradio.NET。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/35728.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在java中,使用数组如何防止操作对象的引用造成错误

情况一、 List<Grid> grids new ArrayList<>(); // 添加一些元素到 grids List<Grid> newList grids&#xff1b; // 在 grids 中添加新元素 grids.add(new Grid());在这种情况下&#xff0c;newList 和 grids 实际上引用的是同一个对象。也就是说&#x…

新需求:如何实现一个ShardingSphere分库分表平台

大家好&#xff0c;目前我们正面对一个既具挑战又令人兴奋的任务——构建一套高效、稳定的数据处理系统&#xff0c;特别是一个结合了SpringBoot、ShardingSphere、MyBatisPlus和MySQL技术的综合数据分库分表平台。简单来说&#xff0c;我们要做的就是打造一个能轻松应对大数据…

企智汇软件:机电工程项目管理系统智能化管理,洞悉项目全貌!

在机电工程领域&#xff0c;项目管理的复杂性要求系统不仅要能够处理大量的数据和信息&#xff0c;还要能够提供实时的洞察和分析&#xff0c;以支持快速而明智的决策。企智汇机电工程项目管理系统正是为了满足这些需求而设计的&#xff0c;它通过一系列先进的功能&#xff0c;…

计算机专业课面试常见问题-计算机网络篇

目录 1. 计算机网络分为哪 5 层&#xff1f; 2. TCP 协议简述&#xff1f; 3. TCP 和 UDP 的区别&#xff1f;->不同的应用场景&#xff1f; 4. 从浏览器输入网址到显示页…

ES6深潜指南:解锁JavaScript类与继承的高级技巧,让您的代码更加优雅

前言 随着前端技术的迅猛发展&#xff0c;JavaScript已经成为构建现代Web应用不可或缺的编程语言。ES6&#xff08;ECMAScript 2015&#xff09;引入了许多期待已久的特性&#xff0c;其中类&#xff08;Classes&#xff09;和继承机制的引入&#xff0c;极大地增强了JavaScrip…

如何在 qmake(QtCreator)中指定 Mac 平台

在 Qt 项目文件(.pro 文件)中设置针对 Mac OS 的配置项。通常情况下,我们可以使用如下方式为 Windows 和 Unix 系统分别添加源文件: win32 {SOURCES += hellowin.cpp } unix {SOURCES += hellounix.cpp }虽然 Mac OS 是类 Unix 系统,但有时我们仍然需要区分它和 Linux 系…

基于 elementUI / elementUI plus,实现 主要色(主题色)的一件换色(换肤)

一、效果图 二、方法 改变elementUI 的主要色 --el-color-primary 为自己选择的颜色&#xff0c;核心代码如下&#xff1a; // 处理主题样式 export function handleThemeStyle(theme) {document.documentElement.style.setProperty(--el-color-primary, theme) } 三、全部代…

【高考志愿】电子科学与技术

高考志愿选择电子科学与技术专业&#xff0c;无疑是向着科技创新的前沿迈出坚定步伐的明智之选。这一专业以其深厚的理论基础、前沿的技术应用和广泛的就业前景&#xff0c;吸引了众多有志于投身科技领域的学子。 首先&#xff0c;电子科学与技术专业所涵盖的内容丰富而深入。它…

OutOfMemoryError能被catch(Exception)捕获吗?

背景 写了一个 Kafka 消费者程序&#xff0c;Kafka 集群中数据量过大时&#xff0c;消费线程无故退出了&#xff0c;日志打印了心跳 OOM 异常信息&#xff1a; 但是消费线程里面的 run 方法里面明明包含了 catch (Exception e) &#xff0c;结尾信息没有打印异常&#xff0c;…

2024全网最全面及最新且最为详细的网络安全技巧四 之 sql注入以及mysql绕过技巧 (2)———— 作者:LJS

目录 4.5 DNS记录类型介绍(A记录、MX记录、NS记录等&#xff0c;TXT&#xff0c;CNAME&#xff0c;PTR) 4.5.1 DNS 4.5.2 A记录 4.5.3NS记录 4.5.4 MX记录 4.5.5 CNAME记录 4.5.6 TXT记录 4.5.7 泛域名与泛解析 4.5.8域名绑定 4.5.9 域名转向 4.6 Mysql报错注入之floor报错详解…

【Mac】王国保卫战:起源 for mac(塔防策略游戏)游戏介绍和安装教程

游戏介绍 《王国保卫战&#xff1a;起源》&#xff08;Kingdom: Origins&#xff09;是一款策略塔防游戏&#xff0c;其核心玩法融合了塔防、策略管理和资源管理元素。游戏的主要目标是在一个开放的像素化世界中建立和管理自己的王国&#xff0c;并抵御夜晚来袭的怪物入侵。 …

一文学会LVS:概念、架构、原理、搭建过程、常用命令及实战案例

引言 随着互联网技术的飞速发展&#xff0c;服务器负载均衡技术变得越来越重要。LVS&#xff08;Linux Virtual Server&#xff09;作为一种高效的负载均衡解决方案&#xff0c;广泛应用于各大企业的生产环境中。本文将深入探讨LVS的概念、架构、工作原理&#xff0c;详细讲解其…

英语中have和have got区别

文章目录 探讨英语中“Have”与“Have Got”的区别1. 基本用法与定义1.1 “Have”1.2 “Have Got” 2. 语法结构的比较2.1 时态与形式2.2 否定和疑问形式 3. 语用功能的差异3.1 强调与感情色彩3.2 地域偏好 4. 使用场景 探讨英语中“Have”与“Have Got”的区别 英语中“have”…

深度学习展示交互笔记

交互库gradio https://zhuanlan.zhihu.com/p/679668818 pip install gradio import gradio as gr print(gr.__version__) # 4.15.0 import gradio as grdef greet(name):return "Hello " name "!" iface gr.Interface(fngreet, inputsgr.Textbox(), ou…

v0.9.6 开源跨平台个人知识管理工具 TidGi-Desktop

在这个信息爆炸的时代&#xff0c;知识管理变得尤为重要。太记(TidGi)&#xff0c;一款基于太微(TiddlyWiki)的知识管理桌面应用&#xff0c;正是为了满足人们对信息整理、知识管理和个人隐私保护的需求而设计的。它不仅能够帮助用户高效地管理和整理信息&#xff0c;还能够自动…

儿童悬吊训练系统的安全性介绍

儿童悬吊训练系统以其独特的优势成为了孩子们康复训练的好帮手。它不仅为孩子们提供了一个全新的锻炼方式&#xff0c;更在安全性上做了全面的考虑和设计&#xff0c;确保孩子们在享受训练乐趣的同时&#xff0c;也能得到充分的保护。 儿童悬吊训练系统的安全性介绍 高强度材料…

4.sql注入攻击(OWASP实战训练)

4.sql注入攻击&#xff08;OWASP实战训练&#xff09; 引言1&#xff0c;实验环境owasp&#xff0c;kali Linux。2&#xff0c;sql注入危害3&#xff0c;sql基础回顾4&#xff0c;登录owasp5&#xff0c;查询实例&#xff08;1&#xff09;简单查询实例&#xff08;2&#xff0…

go中的方法 func-----数据类型

本文是java学习者学go种产生的容易记混点的笔记,所以有其他编译语言的基础更好 go的方法有点像js 基础 func main() {fmt.Println("Starting")var p *string new(string)*p "hello world"demo : "demo"fmt.Println(*&demo) //这样既然也…

《饮食业油烟排放标准》:油烟净化器行业的机遇与挑战

我最近分析了餐饮市场的油烟净化器等产品报告&#xff0c;解决了餐饮业厨房油腻的难题&#xff0c;更加方便了在餐饮业和商业场所有需求的小伙伴们。 随着《饮食业油烟排放标准》的出台和严格实施&#xff0c;油烟净化器行业迎来了新的发展机遇&#xff0c;也面临着诸多挑战。…

【文献及模型、制图分享】汾河流域新型城镇化与生态韧性耦合协调时空演变及协调影响力研究

公众号新功能 目前公众号新增以下等功能 1、处理GIS出图、Python制图、区位图、土地利用现状图、土地利用动态度和重心迁移图等等 2、核密度分析、网络od分析、地形分析、空间分析等等 3、地理加权回归、地理探测器、生态环境质量指数、地理加权回归模型影响因素分析、计算…