AI功能基本实现完毕,但目前仅是非流式回答,另外实现了返回上一界面的原来位置

This commit is contained in:
zhangsan 2024-05-11 11:06:19 +08:00
parent 54a8a8304d
commit 39b978b749
23 changed files with 651 additions and 119 deletions

View File

@ -33,10 +33,10 @@ class Author_introductionActivity : AppCompatActivity() {
authorwork_recyclerView.adapter = adapter
inits()
author_back.setOnClickListener {
val bookName=intent.getStringExtra("book_name")
val intent = Intent(this, BookInformationActivity::class.java)
intent.putExtra("Book_name", bookName)
startActivity(intent)
// val bookName=intent.getStringExtra("book_name")
// val intent = Intent(this, BookInformationActivity::class.java)
// intent.putExtra("Book_name", bookName)
// startActivity(intent)
finish()
}
}

View File

@ -156,15 +156,15 @@ class BookInformationActivity : AppCompatActivity() {
}
//TODO:不一定回到MainActivity::class后面还要在跳转前保存上一个页面
bookinfo_return.setOnClickListener {
if (sourceActivityClass != null) {
// 返回到上一个页面
val intent = Intent(this, sourceActivityClass!!)
startActivity(intent)
} else {
// 如果没有来源页面信息,则返回到 MainActivity
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
}
// if (sourceActivityClass != null) {
// // 返回到上一个页面
// val intent = Intent(this, sourceActivityClass!!)
// startActivity(intent)
// } else {
// // 如果没有来源页面信息,则返回到 MainActivity
// val intent = Intent(this, MainActivity::class.java)
// startActivity(intent)
// }
finish()
}
addBook2.setOnClickListener {

View File

@ -92,8 +92,8 @@ class GoodBookActivity : AppCompatActivity() {
}
private fun returnTOCity() {
bookrank_return.setOnClickListener {
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
// val intent = Intent(this, MainActivity::class.java)
// startActivity(intent)
finish() // 结束当前页面
}
}

View File

@ -79,8 +79,8 @@ class HotBookActivity: AppCompatActivity() {
//TODO未来添加一个返回到上个页面指定位置的功能
private fun returnTOCity() {
bookrank_return.setOnClickListener {
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
// val intent = Intent(this, MainActivity::class.java)
// startActivity(intent)
finish() // 结束当前页面
}
}

View File

@ -97,7 +97,8 @@ class LiteratureActivity : AppCompatActivity() {
}
private fun returnToBookcity(){
categoryPage_back.setOnClickListener{
startActivity(Intent(this, MainActivity::class.java))
// startActivity(Intent(this, MainActivity::class.java))
finish()
}
}

View File

@ -95,7 +95,8 @@ class ManagementActivity:AppCompatActivity() {
}
private fun returnToBookcity(){
categoryPage_back.setOnClickListener{
startActivity(Intent(this, MainActivity::class.java))
// startActivity(Intent(this, MainActivity::class.java))
finish()
}
}

View File

@ -96,7 +96,8 @@ class PhilosophyActivity:AppCompatActivity() {
}
private fun returnToBookcity(){
categoryPage_back.setOnClickListener{
startActivity(Intent(this, MainActivity::class.java))
// startActivity(Intent(this, MainActivity::class.java))
finish()
}
}

View File

@ -95,7 +95,8 @@ class PsychologyActivity:AppCompatActivity() {
}
private fun returnToBookcity(){
categoryPage_back.setOnClickListener{
startActivity(Intent(this, MainActivity::class.java))
// startActivity(Intent(this, MainActivity::class.java))
finish()
}
}

View File

@ -96,7 +96,8 @@ class ScienceActivity:AppCompatActivity() {
}
private fun returnToBookcity(){
categoryPage_back.setOnClickListener{
startActivity(Intent(this, MainActivity::class.java))
// startActivity(Intent(this, MainActivity::class.java))
finish()
}
}

View File

@ -20,7 +20,7 @@
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="10dp"
android:padding="8dp"
android:padding="4dp"
android:src="@drawable/return1" />
<TextView

View File

@ -19,8 +19,9 @@
<ImageView
android:id="@+id/categoryPage_back"
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_width="40dp"
android:layout_height="40dp"
android:padding="4dp"
android:src="@drawable/return1" />
</LinearLayout>

View File

@ -8,6 +8,7 @@
android:id="@+id/bookinfo_return"
android:layout_width="40dp"
android:layout_height="40dp"
android:padding="4dp"
android:src="@drawable/return1" />
<TextView

View File

@ -1,12 +1,17 @@
package com.bifan.txtreaderlib.adapter;
import android.annotation.SuppressLint;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.bifan.txtreaderlib.R;
import com.bifan.txtreaderlib.bean.Message;
@ -14,9 +19,19 @@ import java.util.List;
public class MessageAdapter extends RecyclerView.Adapter<MessageAdapter.MessageViewHolder> {
private List<Message> messages;
private Context context;
private OnRegenerateClickListener onRegenerateClickListener;
public void setOnRegenerateClickListener(OnRegenerateClickListener listener) {
this.onRegenerateClickListener = listener;
}
public MessageAdapter(List<Message> messages) {
public interface OnRegenerateClickListener {
void onRegenerateClick(int position);
}
public MessageAdapter(List<Message> messages, Context context) {
this.messages = messages;
this.context = context;
}
@Override
@ -38,17 +53,52 @@ public class MessageAdapter extends RecyclerView.Adapter<MessageAdapter.MessageV
return new MessageViewHolder(view, viewType);
}
@Override
public void onBindViewHolder(@NonNull MessageViewHolder holder, int position) {
public void onBindViewHolder(@NonNull MessageViewHolder holder, @SuppressLint("RecyclerView") int position) {
Message message = messages.get(position);
if (message.getIsuser() == 1) {
if (message.getIsuser() == 1) { // user
holder.textViewMessage.setText(message.getContent());
} else {
} else { // bot
holder.textViewMessage.setText(message.getContent());
// 检查是否为最后一条机器人消息
if (position == getLastBotMessagePosition()) {
holder.imageViewRegenerate.setVisibility(View.VISIBLE);
} else {
holder.imageViewRegenerate.setVisibility(View.GONE);
}
setupClickListeners(holder, message, position);
}
}
// 获取最后一条机器人消息的位置
public int getLastBotMessagePosition() {
for (int i = messages.size() - 1; i >= 0; i--) {
if (messages.get(i).getIsuser() == 0) { // Assuming 0 is the bot
return i;
}
}
return -1;
}
private void setupClickListeners(MessageViewHolder holder, Message message, int position) {
holder.imageViewCopy.setOnClickListener(v -> {
copyTextToClipboard(message.getContent());
});
holder.imageViewRegenerate.setOnClickListener(view -> {
if (onRegenerateClickListener != null) {
onRegenerateClickListener.onRegenerateClick(position);
}
});
}
private void copyTextToClipboard(String text) {
ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clipData = ClipData.newPlainText("copiedText", text);
clipboardManager.setPrimaryClip(clipData);
Toast.makeText(context, "已复制到剪贴板", Toast.LENGTH_SHORT).show();
}
@Override
public int getItemCount() {
return messages.size();
@ -56,14 +106,17 @@ public class MessageAdapter extends RecyclerView.Adapter<MessageAdapter.MessageV
static class MessageViewHolder extends RecyclerView.ViewHolder {
TextView textViewMessage;
ImageView imageViewCopy;
ImageView imageViewRegenerate;
MessageViewHolder(View itemView, int viewType) {
super(itemView);
if (viewType == 1) { // 假设 1 是用户消息
textViewMessage = itemView.findViewById(R.id.textViewMessageUser);
} else { // 1 即机器人消息
textViewMessage = itemView.findViewById(R.id.textViewMessageBot);
imageViewCopy = itemView.findViewById(R.id.imageViewCopy);
imageViewRegenerate=itemView.findViewById(R.id.imageViewRegenerate);
}
}
}
}
}

View File

@ -8,6 +8,10 @@ public class ChatMessage_bmob extends BmobObject {
private String relatedBook;
private String userid;
public ChatMessage_bmob() {
}
public String getContent() {
return content;
}

View File

@ -32,6 +32,14 @@ public class ChatResponse {
String model;
public List<Choice> choices;
public List<Choice> getChoices() {
return choices;
}
public void setChoices(List<Choice> choices) {
this.choices = choices;
}
public static class Choice {
int index;
public Message message;

View File

@ -0,0 +1,60 @@
package com.bifan.txtreaderlib.bean;
import cn.bmob.v3.BmobObject;
public class GenerateQue_bmob extends BmobObject {
private String relatedBook;
private String userid;
private String ques1;
private String ques2;
private String ques3;
public GenerateQue_bmob(String relatedBook, String userid, String ques1, String ques2, String ques3) {
this.relatedBook = relatedBook;
this.userid = userid;
this.ques1 = ques1;
this.ques2 = ques2;
this.ques3 = ques3;
}
public GenerateQue_bmob(){}
public String getRelatedBook() {
return relatedBook;
}
public void setRelatedBook(String relatedBook) {
this.relatedBook = relatedBook;
}
public String getUserid() {
return userid;
}
public void setUserid(String userid) {
this.userid = userid;
}
public String getQues1() {
return ques1;
}
public void setQues1(String ques1) {
this.ques1 = ques1;
}
public String getQues2() {
return ques2;
}
public void setQues2(String ques2) {
this.ques2 = ques2;
}
public String getQues3() {
return ques3;
}
public void setQues3(String ques3) {
this.ques3 = ques3;
}
}

View File

@ -1,16 +1,21 @@
package com.bifan.txtreaderlib.ui;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.widget.NestedScrollView;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@ -19,6 +24,7 @@ import com.bifan.txtreaderlib.adapter.MessageAdapter;
import com.bifan.txtreaderlib.bean.ChatMessage_bmob;
import com.bifan.txtreaderlib.bean.ChatRequest;
import com.bifan.txtreaderlib.bean.ChatResponse;
import com.bifan.txtreaderlib.bean.GenerateQue_bmob;
import com.bifan.txtreaderlib.bean.Message;
import com.bifan.txtreaderlib.interfaces.ChatGPTService;
@ -26,14 +32,18 @@ import org.json.JSONObject;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import cn.bmob.v3.Bmob;
import cn.bmob.v3.BmobQuery;
import cn.bmob.v3.exception.BmobException;
import cn.bmob.v3.listener.FindListener;
import cn.bmob.v3.listener.SaveListener;
import cn.bmob.v3.listener.UpdateListener;
import okhttp3.OkHttpClient;
import retrofit2.Call;
import retrofit2.Callback;
@ -41,15 +51,17 @@ import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class ChatWithGptActivity extends AppCompatActivity {
public class ChatWithGptActivity extends AppCompatActivity implements MessageAdapter.OnRegenerateClickListener {
private RecyclerView recyclerView;
private MessageAdapter messageAdapter;
private EditText editTextMessage;
private TextView chatbot_title;
private Button buttonSend;
private ImageView buttonSend,chat_return;
private String bookName = "";
private String userid="";
private String userid = "";
private String lastUserQuestion = ""; // 全局变量来存储最后一条用户消息
private ArrayList<Message> messageList = new ArrayList<>();
private TextView questionView1, questionView2, questionView3;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
@ -62,41 +74,99 @@ public class ChatWithGptActivity extends AppCompatActivity {
SharedPreferences sharedPreferences = getSharedPreferences("userinf", Context.MODE_PRIVATE);
String userIdFromPrefs = sharedPreferences.getString("user_id", "");
userid = userIdFromPrefs != null ? userIdFromPrefs : "";
recyclerView = findViewById(R.id.chatRecyclerView);
editTextMessage = findViewById(R.id.inputEditText);
buttonSend = findViewById(R.id.sendButton);
chatbot_title=findViewById(R.id.chatbot_title);
messageAdapter = new MessageAdapter(messageList);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(messageAdapter);
setupViews();
init();
buttonSend.setOnClickListener(new View.OnClickListener() {
initgenerateUserQuestions();
loadLastUserMessage();
setupListeners();
}
private void setupListeners() {
buttonSend.setOnClickListener(v -> sendandStoreMessage(editTextMessage.getText().toString()));
View.OnClickListener questionClickListener = view -> {
TextView questionView = (TextView) view;
String message = questionView.getText().toString();
clearQuestionsVisibility();
sendandStoreMessage(message);
};
questionView1.setOnClickListener(questionClickListener);
questionView2.setOnClickListener(questionClickListener);
questionView3.setOnClickListener(questionClickListener);
chat_return.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String text = editTextMessage.getText().toString();
if (!text.isEmpty()) {
messageList.add(new Message(text, 1)); // User message
messageAdapter.notifyItemInserted(messageList.size() - 1);
recyclerView.scrollToPosition(messageList.size() - 1);
editTextMessage.setText("");
sendMessageToChatGPT(text);
ChatMessage_bmob chatMessage_bmob=new ChatMessage_bmob(text,1,bookName,userid);
chatMessage_bmob.save(new SaveListener<String>() {
@Override
public void done(String objectId,BmobException e) {
if(e==null){
public void onClick(View view) {
finish();
}
});
}
private void clearQuestionsVisibility() {
questionView1.setVisibility(View.GONE);
questionView2.setVisibility(View.GONE);
questionView3.setVisibility(View.GONE);
}
private void sendandStoreMessage(String text) {
messageList.add(new Message(text, 1)); // User message
messageAdapter.notifyItemInserted(messageList.size() - 1);
editTextMessage.setText("");
sendMessageToChatGPT(text);
lastUserQuestion=text;
storeMessage(text,1);
}
private void storeMessage(String text,int isuser){
ChatMessage_bmob chatMessage_bmob = new ChatMessage_bmob(text, isuser, bookName, userid);
chatMessage_bmob.save(new SaveListener<String>() {
@Override
public void done(String objectId, BmobException e) {
if (e == null) {
// toast("添加数据成功返回objectId为"+objectId);
}else{
//toast("创建数据失败:" + e.getMessage());
}
}
});
} else {
//toast("创建数据失败:" + e.getMessage());
}
}
});
}
private void init(){
private void setupViews() {
recyclerView = findViewById(R.id.chatRecyclerView);
editTextMessage = findViewById(R.id.inputEditText);
buttonSend = findViewById(R.id.sendButton);
chatbot_title = findViewById(R.id.chatbot_title);
questionView1 = findViewById(R.id.question1);
questionView2 = findViewById(R.id.question2);
questionView3 = findViewById(R.id.question3);
chat_return=findViewById(R.id.chat_return);
messageAdapter = new MessageAdapter(messageList, this);
messageAdapter.setOnRegenerateClickListener(this);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(messageAdapter);
}
private void loadLastUserMessage() {
BmobQuery<ChatMessage_bmob> bmobQuery = new BmobQuery<>();
bmobQuery.addWhereEqualTo("relatedBook", bookName);
bmobQuery.addWhereEqualTo("userid", userid);
bmobQuery.addWhereEqualTo("isuser", 1); // 只查找用户的消息
bmobQuery.order("-createdAt"); // 按创建时间降序排列以确保最新的消息排在最前
bmobQuery.setLimit(1); // 只获取一条记录
bmobQuery.findObjects(new FindListener<ChatMessage_bmob>() {
@Override
public void done(List<ChatMessage_bmob> messages, BmobException e) {
if (e == null && messages != null && !messages.isEmpty()) {
lastUserQuestion = messages.get(0).getContent(); // 获取最新的用户消息
// 可以在此处更新界面或处理消息
} else {
Log.e("ChatActivity", "No recent user message found, or error fetching data: " + (e != null ? e.getMessage() : "No details"));
}
}
});
}
private void init() {
chatbot_title.setText(bookName);
BmobQuery<ChatMessage_bmob> bmobQuery = new BmobQuery<>();
bmobQuery.addWhereEqualTo("relatedBook", bookName);
@ -118,13 +188,13 @@ public class ChatWithGptActivity extends AppCompatActivity {
// 如果没有消息添加一条 bot 的欢迎消息
String welcomeMessage = "你好!我是你的阅读助手。我可以帮助你解答关于书籍的各种问题,比如内容概述、作者信息、主要主题和角色分析等。请随时向我提问,现在,你有什么关于《" + bookName + "》的问题吗?";
messageList.add(new Message(welcomeMessage, 0)); // 假设 0 表示系统或助手消息
ChatMessage_bmob chatMessage_bmob=new ChatMessage_bmob(welcomeMessage,0,bookName,userid);
ChatMessage_bmob chatMessage_bmob = new ChatMessage_bmob(welcomeMessage, 0, bookName, userid);
chatMessage_bmob.save(new SaveListener<String>() {
@Override
public void done(String objectId,BmobException e) {
if(e==null){
public void done(String objectId, BmobException e) {
if (e == null) {
// toast("添加数据成功返回objectId为"+objectId);
}else{
} else {
//toast("创建数据失败:" + e.getMessage());
}
}
@ -139,6 +209,58 @@ public class ChatWithGptActivity extends AppCompatActivity {
});
}
private void initgenerateUserQuestions() {
BmobQuery<ChatMessage_bmob> bmobQuery = new BmobQuery<>();
bmobQuery.addWhereEqualTo("relatedBook", bookName);
bmobQuery.addWhereEqualTo("userid", userid);
bmobQuery.addWhereEqualTo("isuser", 1);
bmobQuery.findObjects(new FindListener<ChatMessage_bmob>() {
@Override
public void done(List<ChatMessage_bmob> messages, BmobException e) {
if (e == null && messages != null) {
if (!messages.isEmpty()) {
BmobQuery<GenerateQue_bmob> bmobQueryGen = new BmobQuery<>();
bmobQueryGen.addWhereEqualTo("relatedBook", bookName);
bmobQueryGen.addWhereEqualTo("userid", userid);
bmobQueryGen.findObjects(new FindListener<GenerateQue_bmob>() {
@Override
public void done(List<GenerateQue_bmob> list, BmobException e) {
if (e == null) {
for (GenerateQue_bmob generateQue : list) {
if (generateQue.getQues1() != null) {
questionView1.setVisibility(View.VISIBLE);
questionView1.setText(generateQue.getQues1());
}
if (generateQue.getQues2() != null) {
questionView2.setVisibility(View.VISIBLE);
questionView2.setText(generateQue.getQues2());
}
if (generateQue.getQues2() != null) {
questionView3.setVisibility(View.VISIBLE);
questionView3.setText(generateQue.getQues3());
}
}
} else {
}
}
});
} else {
questionView1.setVisibility(View.VISIBLE);
questionView1.setText("请告诉我有关这本书的内容概述。");
questionView2.setVisibility(View.VISIBLE);
questionView2.setText("请告诉有关这本书作者的信息。");
questionView3.setVisibility(View.VISIBLE);
questionView3.setText("请告诉我这本书的主题是什么。");
}
messageAdapter.notifyDataSetChanged();
} else {
Log.e("BookInfo", "Error loading book info: " + (e != null ? e.getMessage() : ""));
}
}
});
}
/**
* 从数据库加载历史对话并构建消息列表
*/
@ -147,18 +269,17 @@ public class ChatWithGptActivity extends AppCompatActivity {
BmobQuery<ChatMessage_bmob> bmobQuery = new BmobQuery<>();
bmobQuery.addWhereEqualTo("relatedBook", bookName);
bmobQuery.addWhereEqualTo("userid", userId);
bmobQuery.order("createdAt");
bmobQuery.order("-createdAt");
bmobQuery.setLimit(10); //设置上下文最多10条历史对话
bmobQuery.findObjects(new FindListener<ChatMessage_bmob>() {
@Override
public void done(List<ChatMessage_bmob> chatMessages, BmobException e) {
if (e == null && chatMessages != null && !chatMessages.isEmpty()) {
for (ChatMessage_bmob item : chatMessages) {
// 根据消息来源判断角色假设 0 表示用户1 表示助手
String role = item.getIsuser() == 0 ? "user" : "assistant";
messages.add(new ChatRequest.Message(role, item.getContent()));
Log.d("test",item.getContent());
}
Collections.reverse(messages); // 反转列表以使消息按时间升序排列, 展示最近的10条数据按时间顺序
} else {
Log.e("BookInfo", "Error loading book info: " + (e != null ? e.getMessage() : "No error details."));
}
@ -168,6 +289,7 @@ public class ChatWithGptActivity extends AppCompatActivity {
}
private void sendMessageToChatGPT(String messageText) {
buttonSend.setImageResource(R.drawable.ic_loading);
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
@ -180,16 +302,25 @@ public class ChatWithGptActivity extends AppCompatActivity {
.build();
ChatGPTService service = retrofit.create(ChatGPTService.class);
List<ChatRequest.Message> messages = new ArrayList<>();
String prompt = "你好!我是你的阅读助手。我可以帮助你解答关于书籍的各种问题,比如内容概述、作者信息、主要主题和角色分析等。请随时向我提问,我会用中文简体来回答你。现在,你有什么关于《" + bookName + "》的问题吗?";
messages.add(new ChatRequest.Message("system", prompt));
String prompt = "你好!我是你的阅读助手。";
// messages.add(new ChatRequest.Message("system", "You are a reading assistant. The user will ask you questions about the book '" + bookName + "'."));
if (messageText.equals("请告诉我更多内容。") && !lastUserQuestion.isEmpty()) {
// 特别关注用户的上一个问题
prompt += "你之前问了关于《" + bookName + "》的'" + lastUserQuestion + "'。关于这个问题,你需要更多的哪方面信息?";
} else if (!lastUserQuestion.isEmpty()) {
// 处理正常的用户问题
prompt += "关于你之前的问题:" + lastUserQuestion + ",你需要我提供更多的信息吗?或者,你有其他关于《" + bookName + "》的新问题吗?";
} else {
// 没有历史问题的情况
prompt += "我可以帮助你解答关于《" + bookName + "》的各种问题,比如内容概述、作者信息、主要主题和角色分析等。请随时向我提问,现在,你有什么问题吗?";
}
messages.add(new ChatRequest.Message("system", prompt));
messages.addAll(loadMessagesFromDatabase(bookName, userid));
messages.add(new ChatRequest.Message("user", messageText)); // 添加用户消息
ChatRequest request = new ChatRequest(messages); // 使用消息列表创建请求
request.setModel("gpt-4-turbo"); // 根据需要选择不同的模型
request.setMaxTokens(200); // 设置最大 token 根据需要调整
request.setMaxTokens(50); // 设置最大 token 根据需要调整
request.setTemperature(0.5); // 设置适当的温度
service.postMessage(request).enqueue(new Callback<ChatResponse>() {
@Override
@ -201,19 +332,11 @@ public class ChatWithGptActivity extends AppCompatActivity {
String reply = message.content; // 这是从 GPT-3.5 响应中提取的内容
runOnUiThread(() -> {
messageList.add(new Message(reply, 0));
messageAdapter.notifyItemInserted(messageList.size() - 1);
recyclerView.scrollToPosition(messageList.size() - 1);
ChatMessage_bmob chatMessage_bmob = new ChatMessage_bmob(reply, 0, bookName, userid);
chatMessage_bmob.save(new SaveListener<String>() {
@Override
public void done(String objectId, BmobException e) {
if (e == null) {
// toast("添加数据成功返回objectId为" + objectId);
} else {
// toast("创建数据失败:" + e.getMessage());
}
}
});
messageAdapter.notifyDataSetChanged();
moveToNewest();
buttonSend.setImageResource(R.drawable.ic_send);
generateUserQuestions(reply);
storeMessage(reply,0);
});
}
} else {
@ -226,6 +349,124 @@ public class ChatWithGptActivity extends AppCompatActivity {
}
}
@Override
public void onFailure(Call<ChatResponse> call, Throwable t) {
String content="机器人响应超时,请重新生成回答!";
buttonSend.setImageResource(R.drawable.ic_send);
messageList.add(new Message(content, 0));
messageAdapter.notifyDataSetChanged();
moveToNewest();
storeMessage(content,0);
Log.e("ChatGPT", "Failure: " + t.getMessage());
}
});
}
//自动移动至最新回答
private void moveToNewest(){
NestedScrollView nestedScrollView = findViewById(R.id.nestedScrollView);
recyclerView.post(() -> {
// 确保最后一条消息可见
if (messageList.size() > 0) {
recyclerView.scrollToPosition(messageList.size() - 1);
recyclerView.post(() -> {
// 获取最后一个视图的引用
View lastChild = recyclerView.getChildAt(recyclerView.getChildCount() - 1);
int bottom = lastChild.getBottom() + recyclerView.getPaddingBottom();
int sy = nestedScrollView.getScrollY();
int sh = nestedScrollView.getHeight();
int delta = bottom - (sy + sh);
nestedScrollView.smoothScrollBy(0, delta);
});
}
});
}
//回调函数重新生成回答
@Override
public void onRegenerateClick(int position) {
questionView1.setVisibility(View.GONE);
questionView2.setVisibility(View.GONE);
questionView3.setVisibility(View.GONE);
BmobQuery<ChatMessage_bmob> bmobQuery = new BmobQuery<>();
bmobQuery.addWhereEqualTo("relatedBook", bookName);
bmobQuery.addWhereEqualTo("userid", userid);
bmobQuery.addWhereEqualTo("isuser", 0);
bmobQuery.order("-createdAt");
bmobQuery.setLimit(2);
bmobQuery.findObjects(new FindListener<ChatMessage_bmob>() {
@Override
public void done(List<ChatMessage_bmob> chatMessages, BmobException e) {
if (e == null && chatMessages != null && !chatMessages.isEmpty()) {
for (ChatMessage_bmob item : chatMessages) {
ChatMessage_bmob chatMessage_bmob = new ChatMessage_bmob();
chatMessage_bmob.setObjectId(item.getObjectId());
chatMessage_bmob.delete(new UpdateListener() {
@Override
public void done(BmobException e) {
if (e == null) {
// 删除成功
runOnUiThread(new Runnable() {
@Override
public void run() {
messageList.remove(position);
messageAdapter.notifyItemRemoved(position);
messageAdapter.notifyItemRangeChanged(position, messageList.size());
sendMessageToChatGPT(lastUserQuestion);
}
});
} else {
// 删除失败
}
}
});
}
}
}
});
}
//模拟生成用户回答
private void generateUserQuestions(String lastBotReply) {
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.build();
Retrofit retrofit = new Retrofit.Builder()
.client(client)
.baseUrl("https://api.openai-ch.top/")
.addConverterFactory(GsonConverterFactory.create())
.build();
ChatGPTService service = retrofit.create(ChatGPTService.class);
// 构建请求数据
List<ChatRequest.Message> messages = new ArrayList<>();
messages.add(new ChatRequest.Message("system", "请你模拟用户的口吻,基于《" + bookName + "" +
"的内容请根据上一条聊天机器人的回复生成两个读者可能的简短提问每个提问不多于20个字每个问题占一行,以序号开头示例如下1.勒庞是否提出了群体心理中的自我意识丧失和传染性特征?" +
"2.《乌合之众》是否强调了群体行为易受领导者情感诉求的影响?"));
messages.add(new ChatRequest.Message("user", lastBotReply)); // 模拟用户的提问
ChatRequest request = new ChatRequest(messages);
request.setModel("gpt-3.5-turbo");
request.setMaxTokens(60); // 增加 token 数以生成多个问题
request.setTemperature(0.9); // 较高温度以增加多样性
service.postMessage(request).enqueue(new Callback<ChatResponse>() {
@Override
public void onResponse(Call<ChatResponse> call, Response<ChatResponse> response) {
if (response.isSuccessful() && response.body() != null) {
ChatResponse chatResponse = response.body();
List<String> questions = extractQuestions(chatResponse);
runOnUiThread(() -> displayQuestions(questions));
} else {
try {
String errorBody = response.errorBody() != null ? response.errorBody().string() : "Unknown error";
Log.e("ChatGPT", "Error: " + errorBody);
} catch (IOException e) {
Log.e("ChatGPT", "Error reading error body", e);
}
}
}
@Override
public void onFailure(Call<ChatResponse> call, Throwable t) {
Log.e("ChatGPT", "Failure: " + t.getMessage());
@ -233,5 +474,88 @@ public class ChatWithGptActivity extends AppCompatActivity {
});
}
// 提取问题
private List<String> extractQuestions(ChatResponse response) {
GenerateQue_bmob generateQue_bmob = new GenerateQue_bmob();
generateQue_bmob.setQues1("请告诉我更多。");
generateQue_bmob.setUserid(userid);
generateQue_bmob.setRelatedBook(bookName);
List<String> questions = new ArrayList<>();
if (response.getChoices() != null && !response.getChoices().isEmpty()) {
String text = response.choices.get(0).message.content;
if (text != null && !text.trim().isEmpty()) {
Log.d("ChatGPT Response:", text);
String[] lines = text.trim().split("\\r?\\n");
int questionIndex = 2; // Start from ques2 since ques1 is set by default
for (String line : lines) {
if (line.matches("^\\d+\\.\\s+.*")) {
String cleanedLine = line.replaceFirst("^\\d+\\.\\s*", "");
if (!cleanedLine.trim().isEmpty()) {
questions.add(cleanedLine);
// Set questions to Bmob object based on availability
if (questionIndex == 2) {
generateQue_bmob.setQues2(cleanedLine);
questionIndex++;
} else if (questionIndex == 3) {
generateQue_bmob.setQues3(cleanedLine);
questionIndex++;
}
}
}
}
}
}
BmobQuery<GenerateQue_bmob> bmobQuery = new BmobQuery<>();
bmobQuery.addWhereEqualTo("relatedBook", bookName);
bmobQuery.addWhereEqualTo("userid", userid);
bmobQuery.findObjects(new FindListener<GenerateQue_bmob>() {
@Override
public void done(List<GenerateQue_bmob> list, BmobException e) {
if (e == null && !list.isEmpty()) {
generateQue_bmob.update(list.get(0).getObjectId(), new UpdateListener() {
@Override
public void done(BmobException e) {
if (e == null) {
//toast("更新成功:"+p2.getUpdatedAt());
} else {
//toast("更新失败:" + e.getMessage());
}
}
});
} else {
// Save the Bmob object to database
generateQue_bmob.save(new SaveListener<String>() {
@Override
public void done(String objectId, BmobException e) {
if (e == null) {
Log.d("Save Successful", "Object saved with objectId: " + objectId);
} else {
Log.e("Save Failed", "Error saving object: " + e.getMessage());
}
}
});
}
}
});
return questions;
}
// 将问题显示在 UI 上的逻辑
private void displayQuestions(List<String> questions) {
questionView1.setText("请告诉我更多内容。");
questionView1.setVisibility(View.VISIBLE);
// Display questions based on size
if (questions.size() > 0) {
questionView2.setText(questions.get(0));
questionView2.setVisibility(View.VISIBLE);
}
if (questions.size() > 1) {
questionView3.setText(questions.get(1));
questionView3.setVisibility(View.VISIBLE);
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 965 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 687 B

View File

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

View File

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
@ -6,52 +5,122 @@
android:layout_height="match_parent"
tools:context=".ui.ChatWithGptActivity">
<androidx.core.widget.NestedScrollView
android:id="@+id/nestedScrollView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/inputEditText"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/chatbot_title">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- RecyclerView 聊天区域 -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/chatRecyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<!-- Question Container -->
<LinearLayout
android:id="@+id/questionContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:orientation="vertical">
<TextView
android:id="@+id/question1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginBottom="8dp"
android:background="@drawable/rounded_question_background"
android:padding="4dp"
android:text="请告诉我更多。"
android:textColor="@android:color/black"
android:textSize="14sp" />
<TextView
android:id="@+id/question2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginBottom="8dp"
android:background="@drawable/rounded_question_background"
android:padding="4dp"
android:text="testtesttesttesttesttest"
android:textColor="@android:color/black"
android:textSize="14sp"
android:visibility="gone" />
<TextView
android:id="@+id/question3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginBottom="8dp"
android:background="@drawable/rounded_question_background"
android:padding="4dp"
android:text="testtesttesttesttesttest"
android:textColor="@android:color/black"
android:textSize="14sp"
android:visibility="gone" />
</LinearLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<ImageView
android:id="@+id/chat_return"
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/ic_return"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/chatbot_title"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="@id/chatbot_title" />
<!-- 标题栏 -->
<TextView
android:id="@+id/chatbot_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="书名"
android:textSize="20sp"
android:gravity="center"
android:layout_marginTop="16dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
<!-- RecyclerView 聊天区域 -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/chatRecyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="8dp"
app:layout_constraintTop_toBottomOf="@id/chatbot_title"
app:layout_constraintBottom_toTopOf="@id/inputEditText"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
android:text="书名"
android:textSize="22sp"
android:gravity="center"
app:layout_constraintStart_toEndOf="@id/chat_return"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!-- 输入框 -->
<EditText
android:id="@+id/inputEditText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="8dp"
android:layout_marginBottom="16dp"
android:hint="输入消息..."
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/sendButton"
android:layout_marginLeft="16dp"
android:layout_marginRight="8dp" />
app:layout_constraintRight_toLeftOf="@id/sendButton" />
<!-- 发送按钮 -->
<Button
<ImageView
android:id="@+id/sendButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发送"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="16dp"
android:src="@drawable/ic_send"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginRight="16dp" />
app:layout_constraintRight_toRightOf="parent"></ImageView>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -29,7 +29,6 @@
android:src="@drawable/ic_copy"
android:layout_marginLeft="5dp"
android:alpha="0.6"
android:visibility="gone"
android:contentDescription="Copy text" />
<ImageView
@ -39,7 +38,6 @@
android:src="@drawable/ic_regenerate"
android:layout_marginLeft="5dp"
android:alpha="0.6"
android:visibility="gone"
android:contentDescription="Regenerate response" />
</LinearLayout>
</LinearLayout>