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]));
			}
		}
	}
}
相关推荐
陈思杰系统思考Jason4 小时前
系统思考—深层结构
百度·微信·微信公众平台·新浪微博·微信开放平台
徒步僧11 小时前
ThingsBoard规则链节点:RPC Call Reply节点详解
qt·microsoft·rpc
可峰科技12 小时前
斗破QT编程入门系列之一:认识Qt:初步使用(四星斗师)
开发语言·qt
我喜欢就喜欢12 小时前
基于qt vs下的视频播放
开发语言·qt·音视频
CP-DD13 小时前
Qt的架构设计
qt
阿_旭13 小时前
基于YOLO11/v10/v8/v5深度学习的维修工具检测识别系统设计与实现【python源码+Pyqt5界面+数据集+训练代码】
人工智能·python·深度学习·qt·ai
福大大架构师每日一题13 小时前
文心一言 VS 讯飞星火 VS chatgpt (384)-- 算法导论24.5 4题
算法·文心一言
Bruce小鬼17 小时前
QT创建按钮篇
开发语言·qt
martian66519 小时前
QT开发:掌握现代UI动画技术:深入解析QML和Qt Quick中的动画效果
开发语言·c++·qt·ui
墨染新瑞21 小时前
两个有趣的小东西(qt和类型转换)
开发语言·网络·qt