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

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

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 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的使用(以实现一个简单的动态聊天界面为例),下边大多数都是无关的代码,主要就那几行):

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

效果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/482646.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

分布式搜索引擎-DSL查询文档

分布式搜索引擎-DSL查询文档 文章目录 分布式搜索引擎-DSL查询文档1、DSL Query的分类1.1、全文检索查询1.2、精确查询1.3、地理查询1.4、复合查询1.5、Function Score Query1.6、复合查询Boolean Query 2、搜索结果处理2.1、排序2.2、分页2.3、深度分页2.4、高亮 1、DSL Query…

鸿蒙OpenHarmony开发实战:【MiniCanvas】

介绍 基于OpenHarmony的Cavas组件封装了一版极简操作的MiniCanvas&#xff0c;屏蔽了原有Canvas内部复杂的调用流程&#xff0c;支持一个API就可以实现相应的绘制能力&#xff0c;该库还在继续完善中&#xff0c;也欢迎PR。 使用说明 添加MiniCanvas依赖 在项目entry目录执行…

混合云构建-使用 Azure ExpressRoute 建立从本地到 Azure 虚拟网络的专用连接

如果有大量业务数据需要在本地数据中心和azure私有网络进行传输&#xff0c;同时保证带宽和时延的情况需要使用 ExpressRoute 设置从本地网络到 Azure 中的虚拟网络的专用连接。以下是实操步骤供参考&#xff1a; 一、创建和预配 ExpressRoute 线路 登录 Azure 门户。 在页面…

为什么独享ip会更高效?

随着互联网的蓬勃发展&#xff0c;代理IP因其特性&#xff0c;也备受关注&#xff0c;代理IP又有分共享代理IP和独享代理IP&#xff0c;但&#xff0c;无论是在数据采集方面&#xff0c;还是在其他业务场景上&#xff0c;独享代理IP似乎会更受用户欢迎一点&#xff0c;这到底是…

【Flask】Flask数据迁移操作

Flask数据迁移操作 前提条件 安装第三方包&#xff1a; # ORM pip install flask-sqlalchemy # 数据迁移 pip install flask-migrate # MySQL驱动 pip install pymysql # 安装失败&#xff0c;指定如下镜像源即可 # pip install flask-sqlalchemy https://pypi.tuna.tsinghu…

Typecho如何去掉/隐藏index.php

Typecho后台设置永久链接后&#xff0c;会在域名后加上index.php&#xff0c;很多人都接受不了。例如如下网址&#xff1a;https://www.jichun29.cn/index.php/archives/37/&#xff0c;但我们希望最终的形式是这样&#xff1a;https://www.jichun29.cn/archives/37.html。那么…

Lua热更新(Lua)

-- [[]] print 下载Lua For Windows Sublime Text&#xff08;仅用于演示&#xff0c;实际项目使用VsCode&#xff09; CtrlB运行 语法基础 基础类型&#xff1a;nil number string boolean 运算符&#xff1a;and-or-not ~ ^ if-then-end-elseif-else while-do-…

Kotlin零基础入门到进阶实战

教程介绍 Kotlin现在是Google官方认定Android一级开发语言&#xff0c;与Java100%互通&#xff0c;并具备诸多Java尚不支持的新特性&#xff0c;每个Android程序员必备的Kotlin课程&#xff0c;每个Java程序员都需要了解的Kotlin&#xff0c;掌握kotlin可以开发Web前端、Web后…

【机器学习300问】46、什么是ROC曲线?

一、二分类器的常用评估指标有哪些&#xff1f; 二分类器是机器学习领域中最常见的也是应用最广泛的分类器。评价二分类器的指标也很多&#xff0c;下面列出几个我之前重点写文章介绍过的指标。 &#xff08;1&#xff09;准确率&#xff08;Accuracy&#xff09; 定义为分类正…

VSGitHub项目联动(上传和克隆),创建你的第一个仓库,小白配置

目录&#xff1a; 前言一&#xff0c;基本说明1.1名词概念1.2必配条件 二&#xff0c;配置方法2.1本地生成密钥2.2云端代码托管平台SSH配置添加&#xff08;GitHub&#xff09;2.3VS项目配置 三&#xff0c;参考四&#xff0c;一些讨论 前言 &#x1f308;在编写VS代码项目时&a…

详细安装步骤:vue.js 三种方式安装(vue-cli)

Vue.js&#xff08;读音 /vjuː/, 类似于 view&#xff09;是一个构建数据驱动的 web 界面的渐进式框架。Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。它不仅易于上手&#xff0c;还便于与第三方库或既有项目整合。 三种 Vue.js 的安装方法&…

Git Commit 提交规范,变更日志、版本发布自动化和 Emoji 提交标准

前言 Git Commit 是开发的日常操作, 一个优秀的 Commit Message 不仅有助于他人 Review, 还可以有效的输出 CHANGELOG, 对项目的管理实际至关重要, 但是实际工作中却常常被大家忽略&#xff0c;希望通过本文&#xff0c;能够帮助大家规范 Git Commit&#xff0c;并且展示相关 …

03_Mybatis

文章目录 入门案例JDBCMybatis MybatisMybatis介绍Mybatis的环境搭建动态代理增删改查示例事务 Mybatis的配置propertiessettingstypeAliasesenvironmentsmappers 输入映射一个参数多个参数按位置传值对象传值使用Map进行传值 #{}和${}的区别输出映射一个参数多个参数单个对象多…

笔记1-Hadoop之HDFS

Hadoop 开源版本的HADOOP和其他框架的对应关系很混乱&#xff0c;要注意。 Hadoop四大模块&#xff1a;Common HDFS MapReduce Yarn Hadoop能对大量的数据进行分布式处理&#xff0c;可以轻松的从一台服务器扩展到千台服务器&#xff0c;并且 每一台服务器都能进行本地计算和…

Flutter开发进阶之瞧瞧BuildOwner

Flutter开发进阶之瞧瞧BuildOwner 上回说到关于Element Tree的构建还缺最后一块拼图&#xff0c;build的重要过程中会调用_element!.markNeedsBuild();&#xff0c;而markNeedsBuild会调用owner!.scheduleBuildFor(this);。 在Flutter框架中&#xff0c;BuildOwner负责管理构建…

【ai技术】(4):在树莓派上,使用qwen0.5b大模型+chatgptweb,搭建本地大模型聊天环境,速度飞快,非常不错!

1&#xff0c;视频地址 https://www.bilibili.com/video/BV1VK421i7CZ/ 2&#xff0c;下载镜像 raspberry-pi-os-64-bit https://blog.csdn.net/freewebsys/article/details/136921703 项目地址&#xff1a; https://www.raspberrypi.com/software/operating-systems/#rasp…

【JAVA重要知识 | 第九篇】ConCurrentHashMap源码分析

文章目录 9.ConCurrentHashMap源码分析9.1 ConCurrentHashMap 1.79.1.1存储结构9.1.2初始化9.1.3put流程&#xff08;1&#xff09;判断是否要put(key,value)流程&#xff08;2&#xff09;put(key,value)&#xff08;3&#xff09;自旋获取hash位置的HashEntry 9.1.4 rehash扩…

【力扣hot100】1. 两数之和 49.字母异位词分组 128. 最长连续序列

目录 1. 两数之和题目描述做题思路参考代码 49.字母异位词分组题目描述做题思路参考代码 128. 最长连续序列题目描述做题思路参考代码 1. 两数之和 题目描述 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数…

子网掩码,网段,网关

IP地址、子网掩码、网段、网关【网络常识 2】_哔哩哔哩_bilibili 网关&#xff1a; 什么时候需要用到网关&#xff1a; 若目标IP在同一网段则可以直接通信不需要经过网关&#xff0c;否则需要。 怎么判断对方的ip是否与我在同一网段呢&#xff1f; 判断网络号是否相同。 电…

Android Studio 和 lombok 的版本适配、gradle依赖配置、插件安装及使用

文章目录 Intro注意事项Android Studio 和 lombok 的版本选择及下载下载链接 在 Android Studio 中安装一次 lombok 插件在每个 gradle 项目中添加 lombok 相关依赖(如要用到)使用ref Intro 用惯了 JavaMavenIDEA 开发后端服务&#xff0c;突然有一天用 JavaGradleAndroidStud…