百度文心一言(ERNIE bot)API接入Android应用实践 - 拾一贰叁 - 博客园 (cnblogs.com)
需要完整代码的话:https://gitee.com/liyizhe2002/we-are-speakers
Preface:
现在生成式AI越来越强大了,想在android上实现一个对话助手的功能,大概摸索了一下接入百度文心一言API的方法。
与AI助手交换信息的方式可以这么理解:
我向文心一言发送一个message:你好啊:
[ { "role": "user", "content": "你好啊" } ]
文心一言回答我:你好,很高兴与你交流。请问你有什么具体的问题或需要帮助吗?我会尽力回答你的问题或与你对话:
{ "id":"as-n24a5sytuz", "object":"chat.completion", "created":1711203238, "result":"你好,请问有什么我可以帮助你的吗?如果你有任何问题或需要帮助,请随时告诉我,我会尽力回答和提供帮助。", "is_truncated":false, "need_clear_history":false, "finish_reason":"normal", "usage":{ "prompt_tokens":1, "completion_tokens":28, "total_tokens":29 } }
接着我继续发送message:今天是几号呢?......
[ { "role": "user", "content": "你好啊" }, { "role": "assistant", "content": "你好,很高兴与你交流。请问你有什么具体的问题或需要帮助吗?我会尽力回答你的问题或与你对话。" }, { "role": "user", "content": "今天是几号呢" } ]
每一次发送message,都要带上之前的对话,这样才能实现连续对话的功能。
具体实现
在Android应用的AndroidManifest.xml
文件中添加网络访问权限:
<uses-permission android:name="android.permission.INTERNET" />
在build.gradle中添加必要的依赖:
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
接下来注册开发者账户、往里边充钱啥的,完成这些之后,在百度智能云控制台 (baidu.com)创建一个新应用,
如上图所示,我们主要需要API Key和Secret Key这俩东西
创建一个新的类以处理文心一言的API信息:WenXin.java,在Activity里需要实现文心一言的对话功能只需调用这个类就好了。
package com.example.wearespeakers; import android.view.View; import com.google.gson.Gson; import okhttp3.*; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.*; /**主要用于实现对接文心一言API的功能 */ public class WenXin{ public static final String API_KEY = "oQtUE*********rwePzF"; public static final String SECRET_KEY = "LxfNEC************L4W2UW0eX"; View view; public JSONArray Dialogue_Content;//用来储存对话内容,当然初始是空的 Gson gson = new Gson(); WenXin(){ Dialogue_Content=new JSONArray(); //初始化 } static final OkHttpClient HTTP_CLIENT = new OkHttpClient().newBuilder().build(); public String GetAnswer(String user_msg) throws IOException, JSONException { JSONObject jsonObject = new JSONObject(); jsonObject.put("role", "user"); jsonObject.put("content", user_msg); // 将JSONObject添加到JSONArray中 Dialogue_Content.put(jsonObject); MediaType mediaType = MediaType.parse("application/json"); //这是一行参考代码,只能进行一次对话,要想多次对话就必须动态调整content的内容 //RequestBody body = RequestBody.create(mediaType, "{\"messages\":[{\"role\":\"user\",\"content\":\"你好啊\"}],\"disable_search\":false,\"enable_citation\":false}"); RequestBody body = RequestBody.create(mediaType, "{\"messages\":" + Dialogue_Content.toString() + ",\"system\":\"你的名字是ERNIE,你是一位英语对话练习助手,你只能以英语进行回答\",\"disable_search\":false,\"enable_citation\":false}"); //预先设定AI的角色功能啥的 Request request = new Request.Builder() .url("https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions?access_token=" + getAccessToken()) .method("POST", body) .addHeader("Content-Type", "application/json") .build(); Response response = HTTP_CLIENT.newCall(request).execute(); //解析出文心一言的回答 JSONObject json_feedback = new JSONObject(response.body().string()); String re=json_feedback.getString("result"); //把文心一言的回答加入到Dialogue_Content中 JSONObject jsontmp=new JSONObject(); jsontmp.put("assistant",re); Dialogue_Content.put(jsontmp); return re; } /** * 从用户的AK,SK生成鉴权签名(Access Token) * * @return 鉴权签名(Access Token) * @throws IOException IO异常 */ public String getAccessToken() throws IOException, JSONException { MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded"); RequestBody body = RequestBody.create(mediaType, "grant_type=client_credentials&client_id=" + API_KEY + "&client_secret=" + SECRET_KEY); Request request = new Request.Builder() .url("https://aip.baidubce.com/oauth/2.0/token") .method("POST", body) .addHeader("Content-Type", "application/x-www-form-urlencoded") .build(); Response response = HTTP_CLIENT.newCall(request).execute(); return new JSONObject(response.body().string()).getString("access_token"); } }
在Activity中是这样写的(Activity里的RecyclerView对话界面参考Android RecyclerView的使用(以实现一个简单的动态聊天界面为例),下边大多数都是无关的代码,主要就那几行):
package com.example.wearespeakers; import android.app.Activity; import android.content.Intent; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.view.View; import android.widget.Button; import android.widget.EditText; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import org.json.JSONException; import java.io.IOException; import java.util.ArrayList; import java.util.List; import static java.security.AccessController.getContext; //此activity主要用来实现聊天界面 public class ChatActivity extends Activity { private EditText et_chat; private Button btn_send,btn_chat_return; private ChatlistAdapter chatAdapter; private List<Chatlist> mDatas; private RecyclerView rc_chatlist; final int MESSAGE_UPDATE_VIEW = 1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_chat); init(); //聊天信息 mDatas = new ArrayList<Chatlist>(); Chatlist C1; C1=new Chatlist("ABC:","Hello,world!"); mDatas.add(C1); Chatlist C2; C2=new Chatlist("DEF:","This is a new app."); mDatas.add(C2); //可以通过数据库插入数据 chatAdapter=new ChatlistAdapter(this,mDatas); LinearLayoutManager layoutManager = new LinearLayoutManager(this ); rc_chatlist.setLayoutManager(layoutManager); //如果可以确定每个item的高度是固定的,设置这个选项可以提高性能 rc_chatlist.setHasFixedSize(true); //创建并设置Adapter rc_chatlist.setAdapter(chatAdapter); //点击btn_send发送聊天信息 btn_send.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //用户的提问 String user_ask=et_chat.getText().toString();//获取输入框里的信息 Chatlist C3; C3=new Chatlist("User:",user_ask); mDatas.add(C3); chatAdapter.ResetChatlistAdapter(mDatas); rc_chatlist.setAdapter(chatAdapter); //文心一言的回答(以下才是用到WenXin.java的地方) new Thread(new Runnable(){ @Override public void run() { //请求详情 Chatlist C4; try { WenXin wx=new WenXin(); C4=new Chatlist("WenXin:",wx.GetAnswer(user_ask)); } catch (IOException | JSONException e) { throw new RuntimeException(e); } finally { } mDatas.add(C4); chatAdapter.ResetChatlistAdapter(mDatas); Message msg = new Message(); msg.what = MESSAGE_UPDATE_VIEW; ChatActivity.this.gHandler.sendMessage(msg); } }).start(); /*为什么要弄new Thread...这样呢? 因为像这种网络请求往往有延迟,需要新开一个进程去处理,与下面的gHandler相对应 当app收到来自文心一言的回答后,就去通知gHandler更新界面,把回答的段落显示出来 */ } }); //点击返回,返回mainActivity btn_chat_return.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent=new Intent(ChatActivity.this,MainActivity.class); startActivity(intent); ChatActivity.this.finish(); } }); } private void init(){//执行一些初始化操作 btn_send=findViewById(R.id.btn_send); et_chat=findViewById(R.id.et_chat); btn_chat_return=findViewById(R.id.btn_chat_return); rc_chatlist=(RecyclerView) findViewById(R.id.rc_chatlist); } public Handler gHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { if (msg.what == MESSAGE_UPDATE_VIEW) { rc_chatlist.setAdapter(chatAdapter);//更新对话界面 } } }; }
其实只需要关注new Thread和gHandler部分的代码即可。
效果:
chatjsonroiclitokenappapijavautmivacreateideurlbaiducode聊天界面parseassistant对话界面android应用