OpenAI Assistant API 允许客户端在文件中上传额外的“知识”,以便 Assistant 与 ChatGPT 配合提供更多定制/私人 AI 响应。
我的客户端是 QT Creator IDE 中基于 C 的代码。我使用 QT 6.5,它具有 QT 类 QNetWorkManager 和 QNetworkRequest,它提供 REST API GET/POST/PUT 接口(因此我不需要使用curl 库)。我正在尝试编写类似于 OpenAI 的基于 Python 的 OpenAI 库的包装函数(pip install openai)。我确实知道如何通过 Python OpenAI 库实现上传,但 (libai) C 库中的支持是非官方且稀缺的,并且不涵盖 Assistant API 函数。因此我决定自己尝试一下。
OpenAI API 参考的实现非常简单,除了一个(至少对我来说)。那就是文件上传。 OpenAI 参考位于:https://platform.openai.com/docs/api-reference/files/create
OpenAI 特别指出:
上传文件 发布 https://api.openai.com/v1/files
我尝试通过 QNetWorkManager 和 QNetworkRequest 调用 url 没有成功。感谢您的帮助。
以下是QT中代码的关键摘录。我将代码精简为仅解决问题的基本要素。
#define OpenAI_UPLOAD_FILE_URL "https://api.openai.com/v1/files"
/*
* Supporting function only
* Pretty Print API response from JSON Object
*/
void AI_Dialog::printJson(QJsonObject json){
QJsonDocument doc(json);
QString jsonString = doc.toJson(QJsonDocument::Indented);
qDebug().noquote() << jsonString.toStdString().c_str();
}
/*
* Wrapper function to OpenAI to upload a file
* Note: reply is defined in AI_Dialog class as QNetworkReply *reply.
* OpenAI_apiKey is key to OpenAI key (not shown)
*/
bool AI_Dialog::upload_file()
{
QUrl APIurl(OpenAI_UPLOAD_FILE_URL);
QNetworkRequest request(APIurl);
bool status = false;
//If not API key do not proceed
if (this->OpenAI_apiKey.isEmpty())
return false;
//Setup RestAPI Header
request.setHeader(QNetworkRequest::ContentTypeHeader, QByteArray("multipart/form-data"));
request.setRawHeader("Authorization", "Bearer " + this->OpenAI_apiKey.toUtf8());
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart valuePart;
valuePart.setRawHeader("purpose", "assistants");
multiPart->append(valuePart);
valuePart.setRawHeader("file", "@contents.json");
valuePart.setBody("bla bla");
multiPart->append(valuePart);
// Do REST API Post operation
reply = this->network_access_manager.post(request, multiPart);
//Setup REST AI completion callbacks. Mian one is ReadyRead
status = connect(reply, &QNetworkReply::readyRead, this, &AI_Dialog::readyRead);
return true;
}
//Rest API callback completion for POST, GET etc to OPenAI
void AI_Dialog::readyRead()
{
QUrl url;
QJsonArray array;
QJsonObject ar1;
if (reply->error() == QNetworkReply::NoError){
//Get Data from reply
QString reply_str = reply->readAll();
QByteArray byte_array = reply_str.toUtf8();
QJsonDocument doc = QJsonDocument::fromJson(byte_array);
QJsonObject obj = doc.object();
//Debug Only
printJson(obj);
}
}
响应结果(通过 printJson) { “错误”: { “代码”:空, "message": "'file' 是必需的属性", “参数”:空, “类型”:“无效请求错误” } }
跟进:这有效(代码摘录)
QHttpMultiPart *multiPart = new
QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart valuePart;
valuePart.setHeader(QNetworkRequest::ContentTypeHeader, "text/plain");
valuePart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\"purpose\"");
valuePart.setBody("assistants");
multiPart->append(valuePart);
QHttpPart filePart;
filePart.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
filePart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\"file\"; filename=\"Hello_There.json\"");
filePart.setBody("{bla bla}");
multiPart->append(filePart);
以下代码摘录对我有用:
QHttpMultiPart *multiPart = new
QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart valuePart;
valuePart.setHeader(QNetworkRequest::ContentTypeHeader, "text/plain");
valuePart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data;
name=\"purpose\"");
valuePart.setBody("assistants");
multiPart->append(valuePart);
QHttpPart filePart;
filePart.setHeader(QNetworkRequest::ContentTypeHeader,
"application/json");
filePart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data;
name=\"file\"; filename=\"Hello_There.json\"");
filePart.setBody("{bla bla}");
multiPart->append(filePart);