QT百度智能云API鉴权,查询 文心一言 服务调用情况

百度智能云API鉴权

做了一个利用Qt实现调用文字大模型的API 小软件 AI.xyz

想通过api直接访问国产语言大模型的调用情况,翻了半天 豆包、通义、文心 的官方文档。最后只找到百度提供通过api读取访问的功能。

一开始只看到 python 的sdk,试了试还可以,用 Qt 实现了下并集成进了AI.xyz。

python 复制代码
resp = resources.Service.V2.describe_preset_services(
    service_ids=['svcp-7d6044e91474', 'svcp-7940ab471306']
)
print(json.dumps(resp.body, indent=4))


resp = resources.Service.V2.service_metric(
    "2024-07-04T15:51:00Z", "2024-08-04T15:51:00Z",service_id=[],app_id= ["94470723"] )
print(json.dumps(resp.body, indent=4))
print(json.dumps(resp.headers, indent=4))

软件内简单做了个页面显示。

希望豆包、通义赶紧增加对应接口,要不然只能统计本地调用的tokens。

最后写完发现官方也提供了SDK,没去编译,照着官方的又改了下自己写的。


百度智能云API鉴权

鉴权的主要目的是用于校验调用者的身份信息。调用千帆平台功能OpenAPI需使用基于安全认证AK/SK进行签名计算鉴权。

百度智能云鉴权简介

百度智能云提供的在线生成签名工具

1 使用 QT 计算鉴权Authorization

cpp 复制代码
#ifndef ModelApiMetrics_H
#define ModelApiMetrics_H

#include <QJsonObject>
#include <QCryptographicHash>
#include <QMessageAuthenticationCode>
#include <QString>
#include <QByteArray>

#include "hv/HttpClient.h"

// 大模型服务度量指标

// 百度鉴权 https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Sly8bm96d
// 百度签名计算工具 https://cloud.baidu.com/signature/index.html

class ModelApiMetrics {
public:

	// 生成百度服务度量指标
	static QMap<QString, QList<int> >GenerateBaiDuServiceMetric(
		const QString& ak, const QString& sk, const QString& appId);

private:

	// 生成百度服务的认证签名
	static QString GenerateBaiDuAuth(HttpRequestPtr& req, QString ak, QString sk, int expireSeconds = 300);

	// 使用 HMAC-SHA256 算法生成十六进制签名。
	static QString HmacSha256Hex(const QString& key, const QString& message);

	// 对字符串进行 URL 编码。
	static QString UrlEncode(const QString& src, bool encodeSlash = false);

	// 去掉字符串首尾指定的字符。
	static QString Trim(const QString& s, const QString& chars = QStringLiteral(" \t\n\r\f\v"));
};

#endif // ifndef ModelApiMetrics_H
cpp 复制代码
QString ModelApiMetrics::GenerateBaiDuAuth(HttpRequestPtr& req, QString ak, QString sk, int expireSeconds)
{
	QString authStr;
	QString signTime = QDateTime::currentDateTimeUtc().toString(Qt::ISODate);
	authStr = QString("bce-auth-v1/%1/%2/%3")
	          .arg(ak)
	          .arg(signTime)
	          .arg(expireSeconds);

	QString canonicalReq;

	// method
	req->method = HTTP_POST;
	switch (req->method) {
	case HTTP_GET:
		canonicalReq += QString("GET\n");
		break;

	case HTTP_POST:
		canonicalReq += QString("POST\n");
		break;

	case HTTP_PUT:
		canonicalReq += QString("PUT\n");
		break;

	default:
		break;
	}

	// url
	canonicalReq += QString("%1\n").arg(UrlEncode(QString::fromStdString(req->url)));

	// query string
	hv::QueryParams params = req->query_params;
	if (0 != params.size()) {
		QStringList paramList;
		for (auto& pair : params) {
			QString encodedKey = UrlEncode(Trim(QString::fromStdString(pair.first)));
			QString encodedValue = UrlEncode(Trim(QString::fromStdString(pair.second)));
			paramList.append(QString("%1=%2").arg(encodedKey, encodedValue));
		}
		std::sort(paramList.begin(), paramList.end());
		canonicalReq += QString("%1\n").arg(paramList.join("&"));
	} else {
		canonicalReq += '\n';
	}

	// header
	canonicalReq += QString("host:%1").arg(UrlEncode(QString::fromStdString(req->headers["Host"])));
	QString signKey = HmacSha256Hex(sk, authStr);
	QString signature = HmacSha256Hex(signKey, canonicalReq);

	authStr += QString("/host/%1").arg(signature);
	return authStr;
}

QString ModelApiMetrics::HmacSha256Hex(const QString& key, const QString& message)
{
	QByteArray keyBytes = key.toUtf8();
	QByteArray messageBytes = message.toUtf8();
	QByteArray hmac = QMessageAuthenticationCode::hash(messageBytes, keyBytes, QCryptographicHash::Sha256);
	return QString(hmac.toHex());
}

QString ModelApiMetrics::UrlEncode(const QString& src, bool encodeSlash)
{
	QByteArray encodedBytes;

	for (QChar c : src) {
		if ((c.isLetterOrNumber() || (c == '_') || (c == '-') || (c == '~') || (c == '.')) ||
		    ((c == '/') && !encodeSlash)) {
			encodedBytes.append(c.toLatin1());
		} else {
			encodedBytes.append('%');
			QByteArray hex = QByteArray::number(c.unicode(), 16).toUpper();
			if (hex.size() == 1) {
				encodedBytes.append('0');
			}
			encodedBytes.append(hex);
		}
	}

	return QString::fromUtf8(encodedBytes);
}

QString ModelApiMetrics::Trim(const QString& s, const QString& chars)
{
	int start = 0;
	int end = s.size() - 1;
	while (start <= end && chars.contains(s[start])) {
		++start;
	}
	while (end >= start && chars.contains(s[end])) {
		--end;
	}
	return s.mid(start, end - start + 1);
}

2 通过 Libhv 查询 文心一言 服务调用情况

查询服务调用情况

cpp 复制代码
QMap<QString, QList<int> >ModelApiMetrics::GenerateBaiDuServiceMetric(
	const QString& ak, const QString& sk, const QString& appId)
{
	QMap<QString, QList<int> > resultMap;

	HttpRequestPtr req(new HttpRequest);
	req->url = "/v2/service";
	req->method = HTTP_POST;
	req->headers["Host"] = "qianfan.baidubce.com";
	req->headers["Content-Type"] = "application/json";
	req->query_params["Action"] = "DescribeServiceMetric";
	req->headers["Authorization"] = GenerateBaiDuAuth(req, ak, sk).toLocal8Bit();
	req->url = "https://qianfan.baidubce.com/v2/service";

	QDateTime   currentDateTimeUtc = QDateTime::currentDateTimeUtc();
	QDateTime   dateTime20DaysAgo = currentDateTimeUtc.addDays(-20);
	QJsonObject jsonObject;
	jsonObject["startTime"] = dateTime20DaysAgo.toString(Qt::ISODate);
	jsonObject["endTime"] = currentDateTimeUtc.toString(Qt::ISODate);
	jsonObject["appId"] = QJsonArray{ appId };
	QJsonDocument jsonDocument(jsonObject);
	QByteArray    jsonData = jsonDocument.toJson(QJsonDocument::Compact);
	req->body = jsonData;

	hv::HttpClient client;
	HttpResponse   resp;
	int ret = client.send(req.get(), &resp);
	if (ret != 0) {
		return resultMap;
	}


	QJsonParseError jsonError;
	QJsonDocument   jsonDoc = QJsonDocument::fromJson(resp.body.c_str(), &jsonError);
	if (jsonDoc.isNull() || (jsonError.error != QJsonParseError::NoError)) {
		return resultMap;
	}
	QJsonObject resultObject = jsonDoc.object();
	QJsonObject result = resultObject["result"].toObject();
	QJsonArray  serviceList = result["serviceList"].toArray();

	for (const QJsonValue& serviceVal : serviceList) {
		QJsonObject serviceObj = serviceVal.toObject();
		QString     serviceName = serviceObj["serviceName"].toString();
		QJsonArray  appList = serviceObj["appList"].toArray();
		for (const QJsonValue& appVal : appList) {
			QJsonObject appObj = appVal.toObject();
			QJsonObject metric = appObj["metric"].toObject();

			QList<int> metricsList;
			metricsList.append(metric["inputTokensTotal"].toInt());
			metricsList.append(metric["outputTokensTotal"].toInt());
			metricsList.append(metric["tokensTotal"].toInt());
			metricsList.append(metric["succeedCallTotal"].toInt());
			metricsList.append(metric["failureCallTotal"].toInt());
			metricsList.append(metric["callTotal"].toInt());

			resultMap[serviceName] = metricsList;
		}
	}
	return resultMap;
}

3 使用返回结果

cpp 复制代码
void SettingsPanelWid::ServiceMetric()
{
	ConfigManager::GetInstance().WriteValue("ernie_ak", ui->ernie_ak->text());
	ConfigManager::GetInstance().WriteValue("ernie_sk", ui->ernie_sk->text());
	ConfigManager::GetInstance().WriteValue("ernie_appId", ui->ernie_appId->text());

	QMap<QString, QList<int> > resMap = ModelApiMetrics::GenerateBaiDuServiceMetric(
		ui->ernie_ak->text(), ui->ernie_sk->text(), ui->ernie_appId->text());


	QString labName = QString("lab_transfer_%1_%2");
	foreach(auto& name, resMap.keys())
	{
		int model = static_cast<int>(ModelInfoManager::GetModel(name));
		for (int i = 0; i < resMap[name].size(); i++) {
			QString labObjName = labName.arg(model).arg(i + 1);
			QLabel* lab = ui->tab_4->findChild<QLabel *>(labObjName);
			if (lab) {
				lab->setText(QString::number(resMap[name][i]));
			}
		}
	}
}
相关推荐
钱彬 (Qian Bin)37 分钟前
项目实践17—全球证件智能识别系统(开发基于LabelMe标注的可视化审核接口)
qt·fastapi·全球证件识别
look ahead to9 小时前
关于PYQT qt designer的网格布局 单控件占多行的处理
开发语言·qt·pyqt
Lution Young11 小时前
Qt隐式共享产生的问题
开发语言·qt
AI工具测评大师11 小时前
如何有效降低英文文本的Turnitin AI检测率?安全指南与工具推荐
人工智能·深度学习·自然语言处理·文心一言·ai写作·ai自动写作
少控科技13 小时前
QT进阶日记009
开发语言·qt
CodeCraft Studio13 小时前
从框架到体验:Qt + Qtitan 构建制造业嵌入式UI整体解决方案
开发语言·qt·ui·gui·嵌入式开发·hmi·制造业嵌入式ui
深蓝海拓13 小时前
PyQt5/PySide6的moveToThread:移动到线程
笔记·python·qt·学习·pyqt
少控科技13 小时前
QT高阶日记007
开发语言·qt
余衫马14 小时前
Qt for Python:PySide6 入门指南(中篇)
开发语言·c++·python·qt
njsgcs14 小时前
python qt做ai透明对话框
人工智能·python·qt