使用 Gradio.NET 打造你的 通义千问 AI 聊天机器人

目录

代码讲解

结论


 

对于那些热衷于 AI 的爱好者来说,Gradio.NET 提供了一个绝佳的机会,通过访问 https://qwen.starworks.cc:88/,让他们能够与通义千问开源模型进行互动。

图片

这个 Web 应用不仅用户体验流畅,还能够记住会话历史,轻松识别语义,这一切都得益于其背后的先进技术。

该项目已开源,源代码地址:https://github.com/sdcb/Sdcb.DashScope(欢迎star)

代码讲解

对于 Web 应用开发者而言,这个项目展示了如何利用 Gradio.Net 和 .NET 开发出高效的 Web 应用。

整个页面的生成过程令人印象深刻,仅需 60 行 C# 代码就能完成,这在传统前端开发中实现同样的效果需要多少行代码(好奇🤔)

通过CreateBlocks方法,开发者能够快速构建出整个页面,无需编写复杂的前端代码。

static Blocks CreateBlocks(IServiceProvider sp)
{
    using Blocks blocks = gr.Blocks();
    Button sendButton, resetButton, regenerateButton;
    Textbox systemPrompt, userInput;
    Chatbot chatBot;
    Radio model;

    gr.Markdown("# 通义千问开源模型");
    model = gr.Radio(["qwen1.5-110b-chat", "qwen1.5-72b-chat", "qwen1.5-32b-chat", "qwen1.5-14b-chat", "qwen1.5-7b-chat", "qwen1.5-1.8b-chat", "qwen1.5-0.5b-chat", "codeqwen1.5-7b-chat"], label: "选择模型", value: "qwen1.5-110b-chat");
    using (gr.Row())
    {
        using (gr.Column(9))
        {
            systemPrompt = gr.Textbox("你是通义千问模型版本{model},请仔细遵循用户指令,用markdown回复,当前日期:{date}", label: "系统Prompt");
        }
        resetButton = gr.Button("🔄重置聊天", variant: ButtonVariant.Stop);
    }
    chatBot = gr.Chatbot(label: "聊天窗口", height: 700, showCopyButton: true, placeholder: "这里显示聊天历史记录");
    using (gr.Row())
    {
        using (gr.Column(scale: 9))
        {
            userInput = gr.Textbox(label: "用户输入", placeholder: "请输入你的问题或指令...");
        }
        sendButton = gr.Button("✉️发送", variant: ButtonVariant.Primary);
        regenerateButton = gr.Button("🔃重新生成", variant: ButtonVariant.Secondary);
    }
    using (gr.Row())
    {
        gr.Markdown("""
  ## Github: https://github.com/sdcb/Sdcb.DashScope
  """);

        gr.Markdown("""  
  ## QQ: 495782587
  """);
    }

    sendButton.Click(streamingFn: i =>
    {
        string model = Radio.Payload(i.Data[0]).Single();
        string systemPrompt = Textbox.Payload(i.Data[1]);
        IList<ChatbotMessagePair> chatHistory = Chatbot.Payload(i.Data[2]);
        string userInput = Textbox.Payload(i.Data[3]);

        return Respond(model, systemPrompt, chatHistory, userInput, sp);
    }, inputs: [model, systemPrompt, chatBot, userInput], outputs: [userInput, chatBot]);
    regenerateButton.Click(streamingFn: i =>
    {
        string model = Radio.Payload(i.Data[0]).Single();
        string systemPrompt = Textbox.Payload(i.Data[1]);
        IList<ChatbotMessagePair> chatHistory = Chatbot.Payload(i.Data[2]);
        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 Respond(model, systemPrompt, chatHistory, userInput, sp);
    }, inputs: [model, systemPrompt, chatBot], outputs: [userInput, chatBot]);
    resetButton.Click(i => Task.FromResult(gr.Output(new ChatbotMessagePair[0], "")), outputs: [chatBot, userInput]);

    return blocks;
}

通过简洁的Respond方法项目完成和通义千问模型的交互,利用 HttpClient 调用阿里云的模型服务灵积(DashScope),将会话历史转化为 DashScopeChatMessage 数组,从而获取模型的响应。

static async IAsyncEnumerable<Output> Respond(string model, string systemPrompt, IList<ChatbotMessagePair> chatHistory, string message, IServiceProvider sp)
{
    IConfiguration config = sp.GetRequiredService<IConfiguration>();
    string dashScopeApiKey = config["DashScope:ApiKey"] ?? throw new Exception("DashScope API key is not configured.");

    if (message == "")
    {
        yield return gr.Output("", chatHistory);
        yield break;
    }

    systemPrompt = systemPrompt.Replace("{model}", model).Replace("{date}", DateTime.Now.ToString("yyyy-MM-dd"));
    chatHistory.Add(new ChatbotMessagePair(message, ""));

    using DashScopeClient api = new(dashScopeApiKey);
    DashScopeChatMessage[] msgs =
    [
        DashScopeChatMessage.FromSystem(systemPrompt),
        ..chatHistory.SkipLast(1).SelectMany(p => new []
        {
            DashScopeChatMessage.FromUser(p.HumanMessage.TextMessage),
            DashScopeChatMessage.FromAssistant(p.AiMessage.TextMessage),
        }),
        DashScopeChatMessage.FromUser(message),
    ];
    await foreach (var item in api.TextGeneration.ChatStreamed(model, msgs, new()
    {
        //EnableSearch = true, 
        IncrementalOutput = true,
        Seed = (ulong)Random.Shared.Next()
    }))
    {
        chatHistory[^1].AiMessage.TextMessage += item.Output.Text;
        yield return gr.Output("", chatHistory);
        if (item.Output.FinishReason == "stop")
        {
            string? connectionString = config.GetValue<string>("ConnectionString");
            if (connectionString != null)
            {
                IHttpContextAccessor httpContextAccessor = sp.GetRequiredService<IHttpContextAccessor>();
                string clientIp =
                    httpContextAccessor.HttpContext!.Request.Headers["X-Forwarded-For"].FirstOrDefault() ??
                    httpContextAccessor.HttpContext!.Connection.RemoteIpAddress!.ToString();
                DashScopeChatMessage[] combinedMessages = [.. msgs, DashScopeChatMessage.FromAssistant(chatHistory[^1].AiMessage.TextMessage)];
                LogClientMessage(clientIp, model, combinedMessages, connectionString);
            }
            break;
        }
    }
}

Gradio.Net 的 Chatbot 组件负责记录和传递会话历史,省去了额外的存储代码。此外,为了模拟 ChatGPT 的打字效果,只需确保方法返回IAsyncEnumerable<Output>类型的值,具体的实现细节由 Gradio.Net 框架负责。

结论

总的来说,这个项目不仅为 AI 爱好者提供了一个与开源模型互动的平台,也为 Web 开发者展示了如何利用现代技术栈简化开发流程。

如果你对创建自己的聊天机器人应用感兴趣,那么现在就是一个好时机。

Gradio.NET(https://github.com/feiyun0112/Gradio.Net/)的目标是成为用于开发 Web 应用的 .NET 开发者的首选框架。它的设计理念是让开发变得更加简单,让每个人都能够参与到Web应用的创造中来。

添加微信GradioDotNet,通过加入技术讨论群,开发者们可以分享经验,解决问题,并共同推动.NET的发展。

图片

Gradio.NET和它的社区将继续成长,推动.NET生态系统的发展,帮助开发者们实现他们的创意和梦想。

如果你是.NET开发者,不妨考虑加入Gradio.NET的行列,体验这个框架带来的变革。

 引入地址

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值