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]));
			}
		}
	}
}
相关推荐
天青白_11 小时前
day1 QT
开发语言·qt
牵牛老人11 小时前
Qt多语言/多语种详细开发教程
开发语言·数据库·qt
gopher951111 小时前
QT/QML 简介
qt
洛阳泰山14 小时前
Chainlit结合百度飞浆的ocr识别和nlp自然语言处理做图片文字信息提取
百度·自然语言处理·ocr·paddlepaddle·chainlit
胖虎江16 小时前
9.7(QT.Day 1)
数据库·qt
InJre19 小时前
QT readyRead()函数,数据分包不完整解决办法
开发语言·qt·串口·readall
SlanderMC1 天前
[QT] QT事件与事件重写
开发语言·qt
SunkingYang1 天前
QT中tr的作用是什么
qt·作用·功能·tr
只会掉头发的程序猿1 天前
QT实战项目之音乐播放器
开发语言·qt·qt实战项目
jacklood2 天前
QT新建项目并运行操作步骤
开发语言·qt