最近本人花了不到一天的时间,开发了一个简单的 AI 角色 Android 小软件,可以实现 AI 角色的云端化,可以指定大量的 AI 角色和对应 prompt 。闲话少说,先直接上图,再简单分解开发过程。如果你对文章没兴趣,可以跳过下面的内容,直接获取源码。
https://github.com/bmob/Bmob-Android-AI-Prompt
登录 Bmob 后端云账号,创建应用之后,创建角色表( Character ):
聊天内容表( Message ):
创建和数据表对应的 Character 、Message 和 User 的 java bean 。
Character 类的代码如下:
public class Character extends BmobObject {
/**
* 这个 AI 助手有多少人在用
*/
String userNum;
/**
* AI 助手的名称
*/
String title;
/**
* 角色的英文名
*/
String name;
/**
* AI 助手的图片
*/
String img;
/**
* AI 助手的 prompt
*/
String prompt;
/**
* AI 助手的描述信息
*/
String description;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getImg() {
return img;
}
public void setImg(String img) {
this.img = img;
}
public String getPrompt() {
return prompt;
}
public void setPrompt(String prompt) {
this.prompt = prompt;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getUserNum() {
return userNum;
}
public void setUserNum(String userNum) {
this.userNum = userNum;
}
}
Message 类的代码如下:
/**
* 聊天内容类
*/
public class Message extends BmobObject {
public static String SEND_BY_ME="me";
public static String SEND_BY_BOT="bot";
/**
* 会话
*/
String session;
/**
* 内容的归属权
*/
String username;
/**
* 发送的内容
*/
String message;
/**
* 发送者( me 和 bot 两种类型)
*/
String sendBy;
/**
* 获取用户的名字
* @return
*/
public String getUsername() {
return username;
}
/**
* 设置用户的名字
* @param username
*/
public void setUsername(String username) {
this.username = username;
}
/**
* 获取会话信息
* @return
*/
public String getSession() {
return session;
}
/**
* 设置会话信息
* @param session
*/
public void setSession(String session) {
this.session = session;
}
/**
* 获取聊天内容
* @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;
}
/**
* 聊天内容的构造函数
* @param message 聊天内容
* @param sendBy 发送者
*/
public Message(String message, String sendBy,String session,String username) {
this.message = message;
this.sendBy = sendBy;
this.session = session;
this.username = username;
}
}
User 类的代码如下:
public class User extends BmobUser {
}
创建 BmobApp 类,继承自 Application 类,代码如下:
public class BmobApp extends Application {
public static BmobAI bmobAI;
@Override
public void onCreate() {
super.onCreate();
//初始化 Bmob 后端云
Bmob.initialize(this,"这个替换为你自己的 application id");
//初始化 AI
bmobAI = new BmobAI();
}
}
登录页面直接调用了 BmobSMS 类的发送方法( requestSMSCode )和 BmobUser 类的短信验证码自动注册登录方法( signOrLoginByMobilePhone )。
public void onClick(View v) {
if(v==getCodeBt){
if(!radioButton.isChecked()){
Toast.makeText(v.getContext(),"请同意以上服务条款",Toast.LENGTH_SHORT).show();
return;
}
//获取验证码
String phone = phoneEdit.getText().toString().trim();
//这里不检查 phone 的更多合规性问题,自行补上
if(phone.length()!=11){
Toast.makeText(v.getContext(),"请输入正确的手机号码",Toast.LENGTH_SHORT).show();
return;
}
//发送验证码
BmobSMS.requestSMSCode(phone, "", new QueryListener<Integer>() {
@Override
public void done(Integer integer, BmobException e) {
if(e==null){
//获取到验证码
Toast.makeText(v.getContext(),"验证码发送成功",Toast.LENGTH_SHORT).show();
}
}
});
}else if(v==submitBt){
//注册登录
String phone = phoneEdit.getText().toString().trim();
String code = codeEdit.getText().toString().trim();
if(code.isEmpty() || code.length()!=6){
Toast.makeText(v.getContext(),"请输入验证码",Toast.LENGTH_SHORT).show();
return;
}
//执行登录操作
BmobUser.signOrLoginByMobilePhone(phone, code, new LogInListener<BmobUser>() {
@Override
public void done(BmobUser o, BmobException e) {
if(e==null){
startActivity(new Intent(LoginActivity.this,MainActivity.class));
}
else{
Toast.makeText(v.getContext(),"短信验证失败",Toast.LENGTH_SHORT).show();
}
}
});
}
}
角色列表页面主要是从 Bmob 后端云上面获取角色列表,呈现在 RecycleView 上面。代码如下:
//从 Bmob 上面获取 AI 角色信息
BmobQuery<Character> query = new BmobQuery<>();
query.findObjects(new FindListener<Character>() {
@Override
public void done(List<Character> characterList, BmobException e) {
CharacterAdapter characterAdapter = new CharacterAdapter(characterList,getContext());
prompt_recycle_view.setAdapter(characterAdapter);
LinearLayoutManager llm = new LinearLayoutManager(getActivity());
llm.setStackFromEnd(true);
prompt_recycle_view.setLayoutManager(llm);
}
});
获取历史聊天记录的代码如下:
BmobQuery<Message> query = new BmobQuery<>();
query.addWhereEqualTo("username",username);
query.addWhereEqualTo("session",session);
query.findObjects(new FindListener<Message>() {
@Override
public void done(List<Message> list, BmobException e) {
if(e==null && list!=null){
messageList.addAll(list);
}
chatAdapter = new ChatAdapter(messageList,logo);
recyclerView.setAdapter(chatAdapter);
LinearLayoutManager llm = new LinearLayoutManager(getApplicationContext());
llm.setStackFromEnd(true);
recyclerView.setLayoutManager(llm);
}
});
聊天对话的核心代码如下(主要是通过设置 prompt 实现角色):
//设置 prompt 信息
if(prompt!=null && !prompt.isEmpty())
BmobApp.bmobAI.setPrompt(prompt);
//点击发送提问到 AI 服务器的按钮
sendButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//获取问题
String quesion = messageEditText.getText().toString().trim();
if(quesion.isEmpty() || quesion.trim()=="")
return;
//连接 AI 服务器(这个代码为了防止 AI 连接中断)
BmobApp.bmobAI.Connect();
//显示问题
addToChat(quesion,Message.SEND_BY_ME);
messageEditText.setText("");
//发送内容到 AI 中
BmobApp.bmobAI.Chat(quesion, session, 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);
Message newmessage = new Message(s,Message.SEND_BY_BOT,session,username);
newmessage.save(new SaveListener<String>() {
@Override
public void done(String s, BmobException e) {
}
});
sendButton.setEnabled(true);
}
@Override
public void onError(String s) {
//OpenAI 的密钥错误或者超过 OpenAI 并发时,会返回这个错误
Log.d("ai",s);
sendButton.setEnabled(true);
}
@Override
public void onClose() {
//连接关闭了
Log.d("ai","close");
sendButton.setEnabled(true);
}
});
}
});
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.