Bootstrap

我用半个小时做了一个Android ChatGPT虚拟女友

拥有一个听自己话的女友,是每个程序员的梦想。在我和她的世界里,她永远都是那么可爱乖巧,不会嫌弃我们这些码农,在累的时候,她会安慰我们,在不开心的时候,她会给我们讲故事,永远忠诚幽默。

效果如下:

闲话少说,接下来就带领大家一步一步制作这样的虚拟女友。

一、创建应用


        打开网址:  https://www.bmobapp.com/

        注册登录进去之后,先进行实名认证(实名认证使用支付宝进行实名认证),然后创建应用,获取application id和rest api key。

        如下图所示:

 二、创建Android工程

这里选择创建一个java语言的Android工程。

三、创建资源文件

主页面布局文件(文件名:res/layout/activity_main.xml)如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".MainActivity"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.recyclerview.widget.RecyclerView
        android:layout_above="@id/bottom_layout"
        android:id="@+id/msg_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:padding="8dp"
        android:layout_alignParentBottom="true"
        android:id="@+id/bottom_layout">
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:id="@+id/message_edit_text"
            android:background="@drawable/rounded_corner"
            android:layout_toLeftOf="@id/send_bt"
            android:hint="输入问题"
            android:padding="16dp"/>
        <ImageButton
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:id="@+id/send_bt"
            android:layout_alignParentEnd="true"
            android:layout_centerInParent="true"
            android:padding="8dp"
            android:src="@drawable/baseline_send_24"
            android:background="?attr/selectableItemBackgroundBorderless"
            android:layout_marginStart="10dp"/>
    </RelativeLayout>

</RelativeLayout>

聊天组件资源文件(文件名:res/layout/chat_item.xml)如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="8dp">

    <LinearLayout
        android:id="@+id/left_chat_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="30dp"
        android:background="@drawable/rounded_corner"
        android:backgroundTint="#1E88E5"
        android:padding="15dp">

        <TextView
            android:id="@+id/left_chat_text_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text=""
            android:textColor="@color/white"
            android:textSize="18sp" />
    </LinearLayout>

    <LinearLayout
        android:layout_alignParentEnd="true"
        android:id="@+id/right_chat_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="30dp"
        android:background="@drawable/rounded_corner"
        android:backgroundTint="#7cb342"
        android:padding="15dp">

        <TextView
            android:id="@+id/right_chat_text_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text=""
            android:textColor="@color/white"
            android:textSize="18sp" />
    </LinearLayout>
</RelativeLayout>

发送按钮资源文件(文件名:res/drawable/baseline_send_24.xml)如下:

<vector android:autoMirrored="true" android:height="48dp"
    android:tint="#1A95BB" android:viewportHeight="24"
    android:viewportWidth="24" android:width="48dp" xmlns:android="http://schemas.android.com/apk/res/android">
    <path android:fillColor="@android:color/white" android:pathData="M2.01,21L23,12 2.01,3 2,10l15,2 -15,2z"/>
</vector>

圆角资源文件(文件名:res/drawable/rounded_corner.xml)如下:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners android:radius="10dp"/>
    <stroke android:width="1dp"/>
    <solid android:color="@color/white"/>

</shape>

四、导入Jar包

从Github中下载jar包(Libs文件夹下)和so包(JniLibs文件夹下),下载地址:Bmob-Android-AI/app/src/main at main · bmob/Bmob-Android-AI · GitHubBmob安卓AI示例. Contribute to bmob/Bmob-Android-AI development by creating an account on GitHub.https://github.com/bmob/Bmob-Android-AI/tree/main/app/src/main

下载之后,在自己的工程中相应创建同样的文件夹,并把对应的jar包和so包放进去。

五、新增依赖

修改build.gradle文件里面的dependencies节点,新增内容如下:

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation 'io.reactivex.rxjava2:rxjava:2.2.8'
    implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
    implementation 'com.squareup.okhttp3:okhttp:4.7.2'
    implementation 'com.squareup.okio:okio:2.2.2'
    implementation 'com.google.code.gson:gson:2.8.5'
    implementation 'androidx.recyclerview:recyclerview:1.3.0'
    implementation files('src\\main\\Libs\\BmobSDK_3.9.0.jar')
}

六、创建Application子类

新建一个类,名为BmobApp,继承自Application类,代码如下:

import android.app.Application;

import cn.bmob.v3.Bmob;

public class BmobApp extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        //初始化
        Bmob.initialize(this,"第一步获取的application id内容");
    }
}

七、新增聊天内容对象类

新建一个类,名为 Message,代码如下:

/**
 * 聊天内容类
 */
public class Message {
    public static String SEND_BY_ME="me";
    public static String SEND_BY_BOT="bot";

    String message;

    /**
     * 获取聊天内容
     * @return
     */
    public String getMessage() {
        return message;
    }

    /**
     * 设置聊天内容
     * @param message
     */
    public void setMessage(String message) {
        this.message = message;
    }

    /**
     * 获取发送者
     * @return
     */
    public String getSendBy() {
        return sendBy;
    }

    /**
     * 设置发送者
     * @param sendBy
     */
    public void setSendBy(String sendBy) {
        this.sendBy = sendBy;
    }

    /**
     * 发送者
     */
    String sendBy;

    /**
     * 聊天内容的构造函数
     * @param message 聊天内容
     * @param sendBy 发送者
     */
    public Message(String message, String sendBy) {
        this.message = message;
        this.sendBy = sendBy;
    }
}

八、新增RecycleView适配器的子类

新增一个类,名字为 MessageAdapter,代码如下:

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import java.util.List;

/**
 * 聊天内容的适配器类
 */
public class MessageAdapter extends RecyclerView.Adapter<MessageAdapter.MyViewHolder> {
    List<Message> messageList;
    public MessageAdapter(List<Message> messageList) {
        this.messageList = messageList;
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View chatView = LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_item,null);
        MyViewHolder myViewHolder = new MyViewHolder(chatView);

        return myViewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        Message message = messageList.get(position);
        if(message.getSendBy().equals(Message.SEND_BY_ME)){
            holder.leftChatView.setVisibility(View.GONE);
            holder.rightChatView.setVisibility(View.VISIBLE);
            holder.rightTextView.setText(message.getMessage());
        }else{
            holder.rightChatView.setVisibility(View.GONE);
            holder.leftChatView.setVisibility(View.VISIBLE);
            holder.leftTextView.setText(message.getMessage());
        }
    }

    @Override
    public int getItemCount() {
        return messageList.size();
    }

    public class MyViewHolder extends RecyclerView.ViewHolder{
        LinearLayout leftChatView,rightChatView;
        TextView leftTextView,rightTextView;

        public MyViewHolder(@NonNull View itemView) {
            super(itemView);

            leftChatView = itemView.findViewById(R.id.left_chat_view);
            rightChatView = itemView.findViewById(R.id.right_chat_view);

            leftTextView = itemView.findViewById(R.id.left_chat_text_view);
            rightTextView = itemView.findViewById(R.id.right_chat_text_view);
        }
    }
}

九、修改配置文件

修改AndroidManifest.xml配置文件,添加权限和application的名字。

新增权限如下:

    <!--允许联网 -->
    <uses-permission android:name="android.permission.INTERNET" />
    <!--获取GSM(2g)、WCDMA(联通3g)等网络状态的信息  -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <!--获取wifi网络状态的信息 -->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

application节点内新增android:name,代码如下:

android:name=".BmobApp"

application节点内新增provider节点,代码如下:

<application>
    <provider
        android:name="cn.bmob.v3.util.BmobContentProvider"
        android:authorities="你自己的应用包名.BmobContentProvider">
    </provider>
</application>

这里要改为你自己的应用包名。

十、修改主页面代码

修改MAinActivity类,代码如下:

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageButton;
import java.util.ArrayList;
import java.util.List;
import cn.bmob.v3.ai.BmobAI;
import cn.bmob.v3.ai.ChatMessageListener;

public class MainActivity extends AppCompatActivity {

    RecyclerView recyclerView;
    EditText messageEditText;
    ImageButton sendButton;

    List<Message> messageList;

    MessageAdapter messageAdapter;

    BmobAI bmobAI;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //创建Bmob AI实例
        bmobAI = new BmobAI();
        //初始化AI内容问答存储
        messageList = new ArrayList<>();

        recyclerView = findViewById(R.id.msg_recycler_view);
        messageEditText = findViewById(R.id.message_edit_text);
        sendButton = findViewById(R.id.send_bt);

        messageAdapter = new MessageAdapter(messageList);
        recyclerView.setAdapter(messageAdapter);
        LinearLayoutManager llm = new LinearLayoutManager(this);
        llm.setStackFromEnd(true);
        recyclerView.setLayoutManager(llm);

        bmobAI.setPrompt("你叫琪琪,是我的女朋友,年轻漂亮贴心,说话也很幽默,接下来的每一个回复,你都要叫我宝贝");

        //点击发送提问到AI服务器的按钮
        sendButton.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {

                sendButton.setEnabled(false);

                //获取问题
                String quesion = messageEditText.getText().toString().trim();
                if(quesion.isEmpty() || quesion.trim()=="")
                    return;
                //连接AI服务器(这个代码为了防止AI连接中断)
                bmobAI.Connect();

                //显示问题
                addToChat(quesion,Message.SEND_BY_ME);
                messageEditText.setText("");

                //发送内容到AI中
                bmobAI.Chat(quesion, "test_user",new ChatMessageListener() {
                    @Override
                    public void onMessage(String s) {
                        //消息流的形式返回AI的结果
                        addToLastMessage(s);
                        Log.d("ai",s);
                    }
                    @Override
                    public void onFinish(String s) {
                        //一次性返回全部结果,这个方法需要等待一段时间,友好性较差
                        //addToChat(s,Message.SEND_BY_BOT);
                        sendButton.setEnabled(true);
                    }

                    @Override
                    public void onClose() {
                        //连接关闭了
                        Log.d("ai","close");
                        sendButton.setEnabled(true);
                    }
                });
            }
        });

    }

    /**
     * 支持流的形式呈现内容到界面
     * @param s
     */
    public void addToLastMessage(String s)
    {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if(messageList.size()<=0) return;
                Message message =  messageList.get(messageList.size()-1);

                if(message.sendBy==Message.SEND_BY_ME){
                    Message newmessage = new Message(s,Message.SEND_BY_BOT);
                    messageList.add(newmessage);
                    messageAdapter.notifyDataSetChanged();
                    recyclerView.smoothScrollToPosition(messageAdapter.getItemCount());
                }else{
                    message.setMessage(message.getMessage() + s);
                    messageAdapter.notifyDataSetChanged();
                    recyclerView.smoothScrollToPosition(messageAdapter.getItemCount());
                }
            }
        });
    }

    /**
     * 一次性将全部内容呈现到界面
     * @param message
     * @param sendBy
     */
    void addToChat(String message,String sendBy){
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                messageList.add(new Message(message,sendBy));
                messageAdapter.notifyDataSetChanged();
                recyclerView.smoothScrollToPosition(messageAdapter.getItemCount());
            }
        });
    }
}

我们可以看到,最重要的一点就是,BmobAI.setPrompt方法,你可以设置一些你想要的调教词进去,做出各种有趣的产品出来。

最后的尾声

最后放出整个项目的源代码给大家:

https://www.bmobapp.com/欢迎大家私聊(wechat: xiaowon12 )AI改变生活的各种想法。

;