百度文心一言(ERNIE bot)API接入Android应用

百度文心一言(ERNIE bot)API接入Android应用实践 - 拾一贰叁 - 博客园 (cnblogs.com)

Preface:

现在生成式AI越来越强大了,想在android上实现一个对话助手的功能,大概摸索了一下接入百度文心一言API的方法。

与AI助手交换信息的方式可以这么理解:

我向文心一言发送一个message:你好啊:

bash 复制代码
[
  {
    "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里需要实现文心一言的对话功能只需调用这个类就好了。

java 复制代码
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 APP_ID = "56****59";//这个似乎还用不到
    public static final String API_KEY = "oQtU**********wePzF";//填你自己应用的apikey
    public static final String SECRET_KEY = "LxfNE*************W2UW0eX";//填你自己应用的secretkey

    public JSONArray Dialogue_Content;//用来储存对话内容,当然初始是空的

    WenXin(){
        //构造函数,先初始化Dialogue_Content一下,此时里边是空的啥也没有
        //不过也可以预先添加对话,以实现一些希望的业务功能
        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");
        //这是一行参考代码,只能进行一次对话,要想多次对话就必须动态添加历史对话的内容
        //RequestBody body = RequestBody.create(mediaType,  "{\"messages\":[{\"role\":\"user\",\"content\":\"你好啊\"}],\"disable_search\":false,\"enable_citation\":false}");

        RequestBody body = RequestBody.create(mediaType,  "{\"messages\":" +
                Dialogue_Content.toString() +
                ",\"disable_search\":false,\"enable_citation\":false}");


        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());
        //这里在开发的时候遇到了一个问题,注意response在上一行被取出里边的内容之后就自动关闭了,不能多次传参。
        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的使用(以实现一个简单的动态聊天界面为例),下边大多数都是无关的代码,主要就那几行):

java 复制代码
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部分的代码即可。

效果:

相关推荐
飞猿_SIR5 分钟前
基于海思Hi3798MV200Android7.0聊聊HDMI色深模式和电视HDR
android·嵌入式硬件·音视频
come112341 小时前
ptyhon 基础语法学习(对比php)
android·学习
ClassOps1 小时前
Android 12 SplashScreen启动屏
android·kotlin
一直向钱1 小时前
android 增强版 RecyclerView
android
sun0077001 小时前
网络配置config.xml的android.mk解析
android·xml
Digitally3 小时前
如何将照片从Mac传输到安卓设备
android·macos
教程分享大师3 小时前
当贝安卓9.0_创维E900S_e910V10C_3798mv310处理器线刷烧录包可救砖带adb功能
android·adb
2501_916008894 小时前
iOS 不上架怎么安装?多种应用分发方式解析,ipa 文件安装、企业签名、Ad Hoc 与 TestFlight 实战经验
android·macos·ios·小程序·uni-app·cocoa·iphone
百锦再5 小时前
从 .NET 到 Java 的转型指南:详细学习路线与实践建议
android·java·前端·数据库·学习·.net·数据库架构