当前位置:AIGC资讯 > AIGC > 正文

Vs使用C++调用文心一言api接口

Vs使用C++调用文心一言api接口

开发环境的选择:visual studio 2022,可以通过visual studio installer进行安装,安装时需要包含组件为“使用C++的桌面开发”(图0-1),需要其它的组件也可以自行下载。

图0-1

Vs installer可以在官网下载:Visual Studio: 面向软件开发人员和 Teams 的 IDE 和代码编辑器 (microsoft.com)

图0-2

如图0-2,直接下载即可。下载完成可能会要求账号登录,不需要,直接免费使用即可,若是有微软账号也可以登录。在创建项目时直接选择控制台程序(图0-3)。

图0-3

获取文心使用资格

百度智能云能提供文心一言api接口,网站:百度智能云-云智一体深入产业 (baidu.com),注册账号并登录后进入控制台:百度智能云控制台 (baidu.com),页面如图1-1。

图1-1

要调用api接口要先创建应用,点击图中创建应用按钮,编写应用名称(按自己喜欢起)和介绍,并选择服务后确定即可(图1-2)。

图1-2

创建完成后页面如图1-1所示,其中apikey和secretkey要记录,在下面编程中需要用到它们进行鉴权确认身份以便于调用接口。各种服务可以免费测试,在后续的编写中若是有大项目可以再额外购买。

代码实现

这里的代码调用的数据模型为ERNIE-Tiny-8K,需要其它模型可以根据api文档更改数据。

引入头文件,编写回调函数
#include <iostream>

#include <string>

#include <curl/curl.h>

#include "json/json.h"

#include "json/json-forwards.h"

这里json的引入,我在安装时是直接将源码加入到库中,此外还需要编写一段回调函数供下面保存服务器返回的数据:

size_t loaddata(void* data, size_t size, size_t num, std::string* localstr)

{//服务器返回的数据、单个数据块字节大小、数据字节数目、你要存储的地址指针

    size_t message_size = size * num;

    localstr->append((char*)data, message_size);//这里做了简单处理,把data拼接到本地字符串结尾

    return message_size;//返回数据总大小

}

其中void* data意思是任意变量的指针,传入的data可以是char*也可以是别的,由于不知道是什么类型的,所以下面需要注明。如果直接声明char* data,则下面append函数中可以直接写data不用再前面注明(char*)。

函数可以根据需要修改,如保存的地点不是string类型变量是文件夹,则为FILE* file,后面的代码也需要按要求更改。

声明变量

将前面获取到的apikey和secretkey粘贴到代码中,并为其声明变量方便使用;声明其它变量。

std::string apikey = "你的apikey";

std::string secretkey = "你的secretkey";

std::string result;

CURL* curl = NULL;

curl = curl_easy_init();//创建curl实例

CURLcode res;//返回参数,用于鉴定网络访问成功与否

curl_slist* headers = NULL;//存储头部信息

Json::Value json_message;//存储json字符串

std::string error;//存储解析错误信息

Json::CharReaderBuilder crbuilder;//创建工程对象

crbuilder["emitUTF8"] = true;//设置json读取时支持utf8编码

std::unique_ptr<Json::CharReader> reader(crbuilder.newCharReader());//创建阅读工具对象

std::string access_token;//存储token

std::string question = "{\"messages\":[{\"role\":\"user\",\"content\":\"";//存储用户提问信息和返回信息

std::string userin;//存储用户输入

std::string answer;//存储返回信息

std::string data;//作为发送给服务器的变量
获取accesstoken

先检测curl是否成功创建,失败抛出异常。要使用文心一言的api,首先要对调用用户进行鉴权,然后才能访问专门的api接口。

if (curl) {//确认curl是否成功创建,若失败curl为null

...

}

else {

    throw "curl创建失败!!";//抛出异常

}

完善第一次请求代码,使用curl_easy_setpot()设置参数,并通过curl_easy_perform()完成访问(其中的各个参数可以通过查阅官方获取accesstoken文档获得):

curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");//请求方式设置为post(官方推荐)

curl_easy_setopt(curl, CURLOPT_URL, ("https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=" + apikey + "&client_secret=" + secretkey).c_str());

//查阅官方资料可知网址,在其中加入鉴权信息,这里有个坑是c_str()

//c_str()作用是返回一个指向c字符串(char[])的指针,内容与原string相同,但是指向的是新的变量

headers = curl_slist_append(headers, "Content-Type:application/json");//查阅官网可知头部固定值,返回指针

curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);//设置头部信息

curl_easy_setopt(curl, CURLOPT_WRITEDATA, &result);//存储数据

curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, loaddata);//调用前面写的记录函数

res = curl_easy_perform(curl);//进行网络连接,并将连接情况存入res

其中CURLOPT_URL后面需要加入的参数为指向c类型字符串的指针,原参数为string类型,调用c_str()可以将其转化为指向char[]的指针。这其中包含的apikey和secretkey为上面获取的参数,如果不希望使用string和c_str()也可以直接使用char*:

const char* url =

"https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=你的apicky&client_secret=你的secretkey";

然后直接在下方参数处填入url即可。

完成后即可处理返回的信息,并从中提取accesstoken:

reader->parse(result.data(), result.data() + result.size(), &json_message, &error);

access_token = json_message["access_token"].asString();//把json数据中的token转化为字符串并保存

现在cout测试一下是否成功连接并且获取到accesstoken(图2.3-1)。

std::cout << result << std::endl << access_token << std::endl;

图2.3-1

可见已经获取成功。

调用api接口
int con = 0;//用于控制问答的结束

curl_easy_setopt(curl, CURLOPT_URL, ("https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/ernie-tiny-8k?access_token=" + access_token).c_str());

//查阅官方资料可知网址,在其中加入鉴权信息,这里有个坑是c_str()

//下面的头部和gettoken一样,不用额外设置,请求的url需要再api文档上查找

curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);//url更改了,这里需要重新设置头部

因为请求api和获取accesstoken的url地址不同,所以这里需要重新设置url和头部。

使用while让问答可以持续进行,并且加入代码获取用户输入,将输入信息存入请求参数中,其中question、answer如果没有让文心一言联系上文回答需求可以不进行设立,按照api文档要求输入data数据即可。需要特别注意getline的使用以及c_str()返回指针的使用:

while (con == 0) {

    result = "";

    std::cout << "用户:";

    std::getline(std::cin, userin);//读取一行的数据

    question.append(userin);//按照api文档的格式将信息填入data

    question.append("\"}");

    data =  question + "]}";//先将处理完的数据存变量,如果直接输入(question + "]}").c_str()

    //会导致c_str()返回的const char*指针指向空区域,因为执行完后(question + "]}")会被删除

    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());

    res = curl_easy_perform(curl);//进行网络连接,并将连接情况存入res

    reader->parse(result.data(), result.data() + result.size(), &json_message, &error);

    //解析字符串内容,将其存入json字符串中

    answer = json_message["result"].asString();

    std::cout << "文心一言:" << answer << std::endl;

    question.append(",{\"role\":\"assistant\",\"content\":\"");

    question.append(answer);

    question.append("\"},{\"role\":\"user\",\"content\":\"");//存储上一次获取的数据

    //这里只做了简单的处理,使用的字符串,作用是可以训练ai使之能联系上文给出回答

    //若是要深入处理需要额外进行文件的创建与编写以便于保存数据

    std::cout << "继续0,停止1:";

    std::cin >> con;

    std::getline(std::cin, userin);//这里多读一行,因为getline有bug

    //getline有个抽象的它只读到\n,但是不读\n,也就是说下次读会先读\n导致输入错误,所以放个把\n读了

}

在结束后清理指针:

curl_slist_free_all(headers);//清理headers指针

curl_easy_cleanup(curl);//清理curl

在装饰一下代码后运行代码测试一下效果(图2.4-1):

图2.4-1

到目前为止接口的调用等各个功能已经基本实现,但是程序依然有许多问题。

小结

上述代码由于是个人编写,可能会有不规范等问题,可以在文心一言文档-自助服务-示例代码中心处查看官方示例代码(图3-1~图3-3)。地址:百度智能云产品_云计算_数据库_智能大数据_人工智能-百度智能云 (baidu.com)、百度智能云控制台 (baidu.com)

图3-1

图3-2

图3-3

程序问题

程序虽然能建立连接并且调用接口,但是并不能发送和接收中文信息,正在研究解决。

测试记录:

User:

hi,nice to meet you

文心:

您好!很高兴能够在此与您相识。为了表达对您热情的问候,我发送了以下信息:

“hi, nice to meet you!”

如果您有任何问题或需要帮助,请随时告诉我。

Vs接受:

鎮ㄥソ锛佸緢楂樺叴鑳藉鍦ㄦ涓庢偍鐩歌瘑銆備负浜嗚〃杈惧鎮ㄧ儹鎯呯殑闂€欙紝鎴戝彂閫佷簡浠ヤ笅淇℃伅锛?

鈥渉i, nice to meet you锛佲€?

濡傛灉鎮ㄦ湁浠讳綍闂鎴栭渶瑕佸府鍔╋紝璇烽殢鏃跺憡璇夋垜銆

通过对比可知,问题出现在本机的转码上,文心一言可以正常接收和发送中文数据,但本机对于数据处理出现了问题。以下是提问文心一言得到的结果。

问:

我编写了c++代码来调用文心一言库,使用了libcurl8.8.0和jsoncpp库,调用成功,但是中文部分出了点问题,我向文心发送了“hi,nice to meet you”,文心回复的内容本来是:您好!很高兴能够在此与您相识。为了表达对您热情的问候,我发送了以下信息: “hi, nice to meet you!” 如果您有任何问题或需要帮助,请随时告诉我。但是在我的系统中变成了:鎮ㄥソ锛佸緢楂樺叴鑳藉鍦ㄦ涓庢偍鐩歌瘑銆備负浜嗚〃杈惧鎮ㄧ儹鎯呯殑闂€欙紝鎴戝彂閫佷簡浠ヤ笅淇℃伅锛? 鈥渉i, nice to meet you锛佲€? 濡傛灉鎮ㄦ湁浠讳綍闂鎴栭渶瑕佸府鍔╋紝璇烽殢鏃跺憡璇夋垜銆。请问是我电脑的字符编码出了问题吗

答:

您遇到的问题很可能是由于字符编码不一致或处理不当导致的。文心一言(或类似的服务)通常返回的是UTF-8编码的文本,而您的系统或程序可能没有正确地处理这种编码。

以下是一些可能的解决方案:

确保libcurl设置正确:

当您使用libcurl发送请求和接收响应时,需要确保它正确地处理了字符编码。对于libcurl,您可能不需要特别设置什么,因为libcurl默认会处理HTTP响应的内容类型,并尝试以正确的编码读取数据。但是,如果您在请求中设置了特定的Accept-Charset头部,或者您知道响应的确切编码,您可以检查这些设置是否正确。

处理JSON响应时确保编码正确:

当您使用jsoncpp解析响应时,确保它正确地处理了UTF-8编码的字符串。jsoncpp应该能够很好地处理UTF-8,但如果您在解析过程中进行了任何字符编码转换,可能会导致问题。

检查控制台或输出设备的编码设置:

如果您在控制台中打印了响应,那么控制台可能无法正确地显示UTF-8编码的文本。确保您的控制台设置为支持UTF-8编码。在Windows上,您可能需要使用支持UTF-8的终端,如Windows Terminal或第三方终端(如Cygwin、MinGW的MSYS2终端等)。在Linux和macOS上,大多数终端默认都支持UTF-8。

检查文件或数据库的编码设置:

如果您将响应保存到文件或数据库中,请确保文件或数据库的编码设置与UTF-8兼容。

使用适当的编码转换函数:

如果您需要在不同编码之间进行转换(例如,从UTF-8转换到本地编码),请使用适当的编码转换函数(如iconv库在Linux上,或Windows API中的相关函数)。但是,通常最好保持所有内容都使用UTF-8编码,以避免编码问题。

查看API文档:

最后,确保您查看了文心一言的API文档,并遵循了所有关于字符编码的建议和最佳实践。

希望这些建议能帮助您解决问题!

文章性质为本人学习后做的笔记,如有侵权请联系本人删除。

更新时间 2024-06-27