使用Fyne构建Go语言OpenAI API中转测试工具

embedded/2025/1/12 12:34:40/

前言

在这篇博客中,我们将介绍如何使用Go语言和Fyne框架构建一个简易的API工具。该工具允许用户输入API URL和API Key,通过简易的GUI与API进行交互,获取账单信息、模型列表并测试模型。本项目展示了一些实用的Go编程技巧和Fyne的使用方法。

完整代码下载地址在文末!!!!

项目依赖

首先,我们需要确保已经安装了必要的依赖项:

  • Go编程语言
  • Fyne GUI框架

你可以通过如下命令来安装Fyne:

go get fyne.io/fyne/v2

项目结构

项目的主代码入口在main.go文件中,其核心组件包括以下几部分:

  • GUI组件初始化与布局
  • API请求及响应处理
  • 输入验证
  • 结果展示
    在这里插入图片描述

主函数

主函数初始化应用,并设置窗口和各个UI组件。

func main() {a := app.New()w := a.NewWindow("API工具")w.Resize(fyne.NewSize(600, 600))// 创建输入框和输出框apiURL := widget.NewEntry()apiURL.SetPlaceHolder("请输入API URL")apiKey := widget.NewEntry()apiKey.SetPlaceHolder("请输入您的API Key")output := widget.NewMultiLineEntry()output.SetPlaceHolder("输出将在这里展示...\n")output.SetMinRowsVisible(15)// 创建按钮getBalance := widget.NewButton("获取余额", func() {handleGetBalance(apiURL.Text, apiKey.Text, output, w)})getModels := widget.NewButton("获取模型列表", func() {handleGetModels(apiURL.Text, apiKey.Text, output, w)})testModel := widget.NewButton("测试模型", func() {showTestModelDialog(apiURL.Text, apiKey.Text, output, w)})// 布局组件layout := container.NewVBox(widget.NewLabel("API URL:"),apiURL,widget.NewLabel("API Key:"),apiKey,getBalance,getModels,testModel,container.NewMax(output),)w.SetContent(layout)w.ShowAndRun()
}

输入验证

为了确保API请求能够成功,我们需要对用户输入的API URL和API Key进行验证。

func validateInputs(apiURL, apiKey string) error {if apiURL == "" || apiKey == "" {return fmt.Errorf("请填写API URL和API Key")}return nil
}

获取余额

该功能涉及两个API请求:一个用于获取订阅信息,另一个用于获取账单信息。我们将这些内容展示在输出框中。

func handleGetBalance(apiURL, apiKey string, output *widget.Entry, w fyne.Window) {if err := validateInputs(apiURL, apiKey); err != nil {dialog.ShowError(err, w)return}// 获取订阅信息url := fmt.Sprintf("%s/v1/dashboard/billing/subscription", strings.TrimSpace(apiURL))req, _ := http.NewRequest("GET", url, nil)req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", strings.TrimSpace(apiKey)))req.Header.Set("Content-Type", "application/json")client := &http.Client{}resp, err := client.Do(req)if err != nil {dialog.ShowError(fmt.Errorf("请求失败: %v", err), w)return}defer resp.Body.Close()body, _ := ioutil.ReadAll(resp.Body)var data SubscriptionDataif err := json.Unmarshal(body, &data); err != nil {dialog.ShowError(fmt.Errorf("解析响应失败: %v", err), w)return}// 获取账单信息startDate := "2021-01-01"endDate := "2022-01-01"billingURL := fmt.Sprintf("%s/v1/dashboard/billing/usage?start_date=%s&end_date=%s", strings.TrimSpace(apiURL), startDate, endDate)req, _ = http.NewRequest("GET", billingURL, nil)req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", strings.TrimSpace(apiKey)))resp, err = client.Do(req)if err != nil {dialog.ShowError(fmt.Errorf("请求失败: %v", err), w)return}defer resp.Body.Close()billingBody, _ := ioutil.ReadAll(resp.Body)var billingData BillingDataif err := json.Unmarshal(billingBody, &billingData); err != nil {dialog.ShowError(fmt.Errorf("解析响应失败: %v", err), w)return}remaining := data.HardLimitUSD - billingData.TotalUsage/100text := fmt.Sprintf("总额: %.4f USD\n已用: %.4f USD\n剩余: %.4f USD", data.HardLimitUSD, billingData.TotalUsage/100, remaining)output.SetText(text)
}

获取模型列表

该功能通过API请求获取模型列表,并将结果展示在输出框中。

func handleGetModels(apiURL, apiKey string, output *widget.Entry, w fyne.Window) {if err := validateInputs(apiURL, apiKey); err != nil {dialog.ShowError(err, w)return}url := fmt.Sprintf("%s/v1/models", strings.TrimSpace(apiURL))req, _ := http.NewRequest("GET", url, nil)req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", strings.TrimSpace(apiKey)))client := &http.Client{}resp, err := client.Do(req)if err != nil {dialog.ShowError(fmt.Errorf("请求失败: %v", err), w)return}defer resp.Body.Close()body, _ := ioutil.ReadAll(resp.Body)var modelData ModelDataif err := json.Unmarshal(body, &modelData); err != nil {dialog.ShowError(fmt.Errorf("解析响应失败: %v", err), w)return}models := make([]string, len(modelData.Data))for i, model := range modelData.Data {models[i] = model.ID}text := fmt.Sprintf("模型列表:\n%s", strings.Join(models, "\n"))output.SetText(text)
}

测试模型

该功能展示了一个弹出的对话框,允许用户输入模型名称和选择是否返回完整的响应信息。

func showTestModelDialog(apiURL, apiKey string, output *widget.Entry, w fyne.Window) {modelNameEntry := widget.NewEntry()modelNameEntry.SetPlaceHolder("模型名称 (gpt-3.5-turbo)")fullResponseCheckbox := widget.NewCheck("返回完整信息", nil)var modal *widget.PopUpsubmitButton := widget.NewButton("提交", func() {modelName := modelNameEntry.Textif modelName == "" {modelName = "gpt-3.5-turbo"}testModelRequest(apiURL, apiKey, modelName, fullResponseCheckbox.Checked, output, w)if modal != nil {modal.Hide()}})content := container.NewVBox(widget.NewLabel("请输入模型名称 (默认使用 gpt-3.5-turbo):"),modelNameEntry,fullResponseCheckbox,)closeButton := widget.NewButton("关闭", func() {if modal != nil {modal.Hide()}})content.Add(container.NewHBox(submitButton, closeButton))modal = widget.NewModalPopUp(content, w.Canvas())modal.Resize(fyne.NewSize(300, 200))modal.Show()
}func testModelRequest(apiURL, apiKey, modelName string, fullResponse bool, output *widget.Entry, w fyne.Window) {if err := validateInputs(apiURL, apiKey); err != nil {dialog.ShowError(err, w)return}url := fmt.Sprintf("%s/v1/chat/completions", strings.TrimSpace(apiURL))data := map[string]interface{}{"model": modelName,"messages": []map[string]string{{"role": "user", "content": "say this is a test!"},},}jsonData, _ := json.Marshal(data)req, _ := http.NewRequest("POST", url, strings.NewReader(string(jsonData)))req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", strings.TrimSpace(apiKey)))req.Header.Set("Content-Type", "application/json")client := &http.Client{}resp, err := client.Do(req)if err != nil {dialog.ShowError(fmt.Errorf("请求失败: %v", err), w)return}defer resp.Body.Close()body, _ := ioutil.ReadAll(resp.Body)var completionResponse CompletionResponseif err := json.Unmarshal(body, &completionResponse); err != nil {dialog.ShowError(fmt.Errorf("解析响应失败: %v", err), w)return}if fullResponse {var prettyJSON bytes.Buffererror := json.Indent(&prettyJSON, body, "", "  ")if error != nil {output.SetText(fmt.Sprintf("格式化JSON失败: %v", error))} else {output.SetText(prettyJSON.String())}} else if len(completionResponse.Choices) > 0 {output.SetText(completionResponse.Choices[0].Message.Content)} else {output.SetText("未收到模型回应")}
}

技术要点

1. GUI组件的使用

Fyne 提供了一系列丰富的控件,比如 Entry, ButtonMultiLineEntry。通过配置这些控件,我们可以迅速搭建一个简单且实用的GUI界面。

2. 网络请求与JSON解析

利用 net/http 包来处理HTTP请求。通过自定义请求头和API地址,实现与服务端的数据交互。encoding/json 包用于解析和生成JSON数据,确保了数据格式的一致性。

3. 错误处理与用户反馈

采用对话框(dialog)来显示错误信息,增强了用户体验。当请求失败或JSON解析出错时,能够及时反馈给用户,减少用户的疑惑。

4. 弹出对话框与动态内容

使用 widget.NewModalPopUp 创建弹出对话框,使得应用更加灵活。用户可以输入具体的模型名称并选择是否需要完整的响应信息,这种动态交互增强了程序的自适应能力。

运行与调试

  1. 在你的Go项目目录中创建一个main.go文件,并将前文的代码粘贴进去。
  2. 确保你已经安装了Fyne框架。
  3. 运行你的程序:
go run main.go
  1. 按照提示输入API URL和API Key,然后点击各个按钮进行相应操作。

结尾

完整代码地址:https://github.com/stfghly/test-all-api/blob/main/test.go

通过这篇博客,我们了解了如何使用Go语言和Fyne构建一个简易的API工具。这不仅展示了Go语言强大的并发和网络处理能力,同时也展示了Fyne框架在构建桌面应用时的便利性。希望这篇博客对你有所帮助,如果你有任何问题或建议,欢迎在评论区交流讨论。
在这里插入图片描述


http://www.ppmy.cn/embedded/101548.html

相关文章

【数据结构-前缀异或和】力扣1177. 构建回文串检测

给你一个字符串 s,请你对 s 的子串进行检测。 每次检测,待检子串都可以表示为 queries[i] [left, right, k]。我们可以 重新排列 子串 s[left], …, s[right],并从中选择 最多 k 项替换成任何小写英文字母。 如果在上述检测过程中&#xf…

10080-0-监测文件夹并解压压缩包-支持zip-rar-7z压缩包的解压-不支持子文件夹/密码/多层嵌套压缩包解压-UI

程序功使用环境▶适用的系统环境说明:win7以上64位win系统注意:win32位系统/mac系统需要额外定制▶使用期限:无需注册、不绑电脑、无时间限制▶如何安装:不需要安装程序功能说明▶支持的文件格式:.zip, .rar, .7z▶【以…

JAVA基础面试题总结(十二)——JVM(上)

Java内存区域详解 如果没有特殊说明,都是针对的是 HotSpot 虚拟机。 本文基于《深入理解 Java 虚拟机:JVM 高级特性与最佳实践》进行总结补充 常见面试题: 介绍下 Java 内存区域(运行时数据区) JDK1.7 JDK1.8 线程…

[hostapd]conf配置ht

https://w1.fi/cgit/hostap/plain/hostapd/hostapd.conf “IEEE 802.11n related configuration” 修改配置文件ht_capab字段 函数hostapd_config_ht_capab() /* HT Capabilities Info field within HT Capabilities element */ #define HT_CAP_INFO_LDPC_CODING_CAP ((u16)…

信息打点-Web架构篇域名语言中间件数据库系统源码获取

知识点: 1、打点-Web架构-语言&中间件&数据库&系统等 2、打点-Web源码-CMS开源&闭源售卖&自主研发等 CMS:网站程序源码是可以通过搜索引擎搜索到并且下载的; 闭源售卖:不是一个开源的,要么从内…

Swift中的可选类型:揭开Optional的神秘面纱

标题:Swift中的可选类型:揭开Optional的神秘面纱 Swift语言以其安全性和现代性著称,而可选类型(Optional)是Swift中一个非常重要的特性,它允许开发者以一种非常优雅的方式处理可能不存在的值。本文将深入探…

【计算机网络】计算机网络的性能指标

1B/s 8bps ,MB/s 8Mbps 信道(Channel):表示向某一方向传送信息的通道(信道≠通信线路),一条通信线路在逻辑上往往对应一条发送信道和一条接收信道。

【C#】【EXCEL】BumblebeeComponentsAnalysisGH_Ex_Ana_CondBlank.cs

这段代码定义了一个名为 GH_Ex_Ana_CondBlank 的类,它是一个 Grasshopper 组件,用于在 Excel 工作表中为特定范围添加条件格式。具体功能和介绍如下: 功能概述: 这个组件用于在 Excel 中为指定的单元格范围添加基于空白值的条件格…