From 39b978b749eb4156731eb0669544f9b58022e114 Mon Sep 17 00:00:00 2001 From: zhangsan <646228430@qq.com> Date: Sat, 11 May 2024 11:06:19 +0800 Subject: [PATCH] =?UTF-8?q?AI=E5=8A=9F=E8=83=BD=E5=9F=BA=E6=9C=AC=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=E5=AE=8C=E6=AF=95=EF=BC=8C=E4=BD=86=E7=9B=AE=E5=89=8D?= =?UTF-8?q?=E4=BB=85=E6=98=AF=E9=9D=9E=E6=B5=81=E5=BC=8F=E5=9B=9E=E7=AD=94?= =?UTF-8?q?=EF=BC=8C=E5=8F=A6=E5=A4=96=E5=AE=9E=E7=8E=B0=E4=BA=86=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E4=B8=8A=E4=B8=80=E7=95=8C=E9=9D=A2=E7=9A=84=E5=8E=9F?= =?UTF-8?q?=E6=9D=A5=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Activity/Author_introductionActivity.kt | 8 +- .../Activity/BookInformationActivity.kt | 18 +- .../jianshu/Activity/GoodBookActivity.kt | 4 +- .../zjgsu/jianshu/Activity/HotBookActivity.kt | 4 +- .../jianshu/Activity/LiteratureActivity.kt | 3 +- .../jianshu/Activity/ManagementActivity.kt | 3 +- .../jianshu/Activity/PhilosophyActivity.kt | 3 +- .../jianshu/Activity/PsychologyActivity.kt | 3 +- .../zjgsu/jianshu/Activity/ScienceActivity.kt | 3 +- .../layout/activity_anthor_introduction.xml | 2 +- .../main/res/layout/activity_categorypage.xml | 5 +- app/src/main/res/layout/bookinfo_title.xml | 1 + .../txtreaderlib/adapter/MessageAdapter.java | 69 ++- .../txtreaderlib/bean/ChatMessage_bmob.java | 4 + .../bifan/txtreaderlib/bean/ChatResponse.java | 8 + .../txtreaderlib/bean/GenerateQue_bmob.java | 60 +++ .../txtreaderlib/ui/ChatWithGptActivity.java | 434 +++++++++++++++--- .../src/main/res/drawable/ic_loading.png | Bin 0 -> 965 bytes .../src/main/res/drawable/ic_return.png | Bin 0 -> 2720 bytes .../src/main/res/drawable/ic_send.png | Bin 0 -> 687 bytes .../drawable/rounded_question_background.xml | 9 + .../main/res/layout/activity_chatwithgpt.xml | 127 +++-- .../src/main/res/layout/item_message_bot.xml | 2 - 23 files changed, 651 insertions(+), 119 deletions(-) create mode 100644 hwtxtreaderlib/src/main/java/com/bifan/txtreaderlib/bean/GenerateQue_bmob.java create mode 100644 hwtxtreaderlib/src/main/res/drawable/ic_loading.png create mode 100644 hwtxtreaderlib/src/main/res/drawable/ic_return.png create mode 100644 hwtxtreaderlib/src/main/res/drawable/ic_send.png create mode 100644 hwtxtreaderlib/src/main/res/drawable/rounded_question_background.xml diff --git a/app/src/main/java/com/zjgsu/jianshu/Activity/Author_introductionActivity.kt b/app/src/main/java/com/zjgsu/jianshu/Activity/Author_introductionActivity.kt index 9d2536f..5242f99 100644 --- a/app/src/main/java/com/zjgsu/jianshu/Activity/Author_introductionActivity.kt +++ b/app/src/main/java/com/zjgsu/jianshu/Activity/Author_introductionActivity.kt @@ -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() } } diff --git a/app/src/main/java/com/zjgsu/jianshu/Activity/BookInformationActivity.kt b/app/src/main/java/com/zjgsu/jianshu/Activity/BookInformationActivity.kt index 37fe275..d626e8b 100644 --- a/app/src/main/java/com/zjgsu/jianshu/Activity/BookInformationActivity.kt +++ b/app/src/main/java/com/zjgsu/jianshu/Activity/BookInformationActivity.kt @@ -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 { diff --git a/app/src/main/java/com/zjgsu/jianshu/Activity/GoodBookActivity.kt b/app/src/main/java/com/zjgsu/jianshu/Activity/GoodBookActivity.kt index 2f6688f..01fe9db 100644 --- a/app/src/main/java/com/zjgsu/jianshu/Activity/GoodBookActivity.kt +++ b/app/src/main/java/com/zjgsu/jianshu/Activity/GoodBookActivity.kt @@ -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() // 结束当前页面 } } diff --git a/app/src/main/java/com/zjgsu/jianshu/Activity/HotBookActivity.kt b/app/src/main/java/com/zjgsu/jianshu/Activity/HotBookActivity.kt index 3b1b331..738f229 100644 --- a/app/src/main/java/com/zjgsu/jianshu/Activity/HotBookActivity.kt +++ b/app/src/main/java/com/zjgsu/jianshu/Activity/HotBookActivity.kt @@ -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() // 结束当前页面 } } diff --git a/app/src/main/java/com/zjgsu/jianshu/Activity/LiteratureActivity.kt b/app/src/main/java/com/zjgsu/jianshu/Activity/LiteratureActivity.kt index 320ade8..eaae30c 100644 --- a/app/src/main/java/com/zjgsu/jianshu/Activity/LiteratureActivity.kt +++ b/app/src/main/java/com/zjgsu/jianshu/Activity/LiteratureActivity.kt @@ -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() } } diff --git a/app/src/main/java/com/zjgsu/jianshu/Activity/ManagementActivity.kt b/app/src/main/java/com/zjgsu/jianshu/Activity/ManagementActivity.kt index d2ab39e..0669e51 100644 --- a/app/src/main/java/com/zjgsu/jianshu/Activity/ManagementActivity.kt +++ b/app/src/main/java/com/zjgsu/jianshu/Activity/ManagementActivity.kt @@ -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() } } diff --git a/app/src/main/java/com/zjgsu/jianshu/Activity/PhilosophyActivity.kt b/app/src/main/java/com/zjgsu/jianshu/Activity/PhilosophyActivity.kt index 182b922..d1b8480 100644 --- a/app/src/main/java/com/zjgsu/jianshu/Activity/PhilosophyActivity.kt +++ b/app/src/main/java/com/zjgsu/jianshu/Activity/PhilosophyActivity.kt @@ -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() } } diff --git a/app/src/main/java/com/zjgsu/jianshu/Activity/PsychologyActivity.kt b/app/src/main/java/com/zjgsu/jianshu/Activity/PsychologyActivity.kt index bd2a295..726ea44 100644 --- a/app/src/main/java/com/zjgsu/jianshu/Activity/PsychologyActivity.kt +++ b/app/src/main/java/com/zjgsu/jianshu/Activity/PsychologyActivity.kt @@ -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() } } diff --git a/app/src/main/java/com/zjgsu/jianshu/Activity/ScienceActivity.kt b/app/src/main/java/com/zjgsu/jianshu/Activity/ScienceActivity.kt index 008cf9e..c17cac2 100644 --- a/app/src/main/java/com/zjgsu/jianshu/Activity/ScienceActivity.kt +++ b/app/src/main/java/com/zjgsu/jianshu/Activity/ScienceActivity.kt @@ -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() } } diff --git a/app/src/main/res/layout/activity_anthor_introduction.xml b/app/src/main/res/layout/activity_anthor_introduction.xml index 544ac97..a7908b2 100644 --- a/app/src/main/res/layout/activity_anthor_introduction.xml +++ b/app/src/main/res/layout/activity_anthor_introduction.xml @@ -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" /> diff --git a/app/src/main/res/layout/bookinfo_title.xml b/app/src/main/res/layout/bookinfo_title.xml index 2fe849e..2466c26 100644 --- a/app/src/main/res/layout/bookinfo_title.xml +++ b/app/src/main/res/layout/bookinfo_title.xml @@ -8,6 +8,7 @@ android:id="@+id/bookinfo_return" android:layout_width="40dp" android:layout_height="40dp" + android:padding="4dp" android:src="@drawable/return1" /> { private List messages; + private Context context; + private OnRegenerateClickListener onRegenerateClickListener; + public void setOnRegenerateClickListener(OnRegenerateClickListener listener) { + this.onRegenerateClickListener = listener; + } - public MessageAdapter(List messages) { + public interface OnRegenerateClickListener { + void onRegenerateClick(int position); + } + + public MessageAdapter(List messages, Context context) { this.messages = messages; + this.context = context; } @Override @@ -38,17 +53,52 @@ public class MessageAdapter extends RecyclerView.Adapter= 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 choices; + public List getChoices() { + return choices; + } + + public void setChoices(List choices) { + this.choices = choices; + } + public static class Choice { int index; public Message message; diff --git a/hwtxtreaderlib/src/main/java/com/bifan/txtreaderlib/bean/GenerateQue_bmob.java b/hwtxtreaderlib/src/main/java/com/bifan/txtreaderlib/bean/GenerateQue_bmob.java new file mode 100644 index 0000000..02c0461 --- /dev/null +++ b/hwtxtreaderlib/src/main/java/com/bifan/txtreaderlib/bean/GenerateQue_bmob.java @@ -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; + } +} diff --git a/hwtxtreaderlib/src/main/java/com/bifan/txtreaderlib/ui/ChatWithGptActivity.java b/hwtxtreaderlib/src/main/java/com/bifan/txtreaderlib/ui/ChatWithGptActivity.java index 2da2636..375ac00 100644 --- a/hwtxtreaderlib/src/main/java/com/bifan/txtreaderlib/ui/ChatWithGptActivity.java +++ b/hwtxtreaderlib/src/main/java/com/bifan/txtreaderlib/ui/ChatWithGptActivity.java @@ -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 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() { - @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() { + @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 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() { + @Override + public void done(List 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 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() { @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 bmobQuery = new BmobQuery<>(); + bmobQuery.addWhereEqualTo("relatedBook", bookName); + bmobQuery.addWhereEqualTo("userid", userid); + bmobQuery.addWhereEqualTo("isuser", 1); + bmobQuery.findObjects(new FindListener() { + @Override + public void done(List messages, BmobException e) { + if (e == null && messages != null) { + if (!messages.isEmpty()) { + BmobQuery bmobQueryGen = new BmobQuery<>(); + bmobQueryGen.addWhereEqualTo("relatedBook", bookName); + bmobQueryGen.addWhereEqualTo("userid", userid); + bmobQueryGen.findObjects(new FindListener() { + @Override + public void done(List 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 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() { @Override public void done(List 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 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() { @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() { - @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 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 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() { + @Override + public void done(List 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 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() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful() && response.body() != null) { + ChatResponse chatResponse = response.body(); + List 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 call, Throwable t) { Log.e("ChatGPT", "Failure: " + t.getMessage()); @@ -233,5 +474,88 @@ public class ChatWithGptActivity extends AppCompatActivity { }); } + // 提取问题 + private List extractQuestions(ChatResponse response) { + GenerateQue_bmob generateQue_bmob = new GenerateQue_bmob(); + generateQue_bmob.setQues1("请告诉我更多。"); + generateQue_bmob.setUserid(userid); + generateQue_bmob.setRelatedBook(bookName); + List 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 bmobQuery = new BmobQuery<>(); + bmobQuery.addWhereEqualTo("relatedBook", bookName); + bmobQuery.addWhereEqualTo("userid", userid); + bmobQuery.findObjects(new FindListener() { + @Override + public void done(List 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() { + @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 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); + } + } } diff --git a/hwtxtreaderlib/src/main/res/drawable/ic_loading.png b/hwtxtreaderlib/src/main/res/drawable/ic_loading.png new file mode 100644 index 0000000000000000000000000000000000000000..c606f9419fe7f3b35b84637c8203fa2ddea4da6b GIT binary patch literal 965 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 Y>xe5^<660}4_rBM9FMK6D)%t#A8L%a9RL6T literal 0 HcmV?d00001 diff --git a/hwtxtreaderlib/src/main/res/drawable/ic_send.png b/hwtxtreaderlib/src/main/res/drawable/ic_send.png new file mode 100644 index 0000000000000000000000000000000000000000..533e7c33bf657299ee40963f3f8f9d56662b4b56 GIT binary patch literal 687 zcmV;g0#N;lP)Px%X-PyuRA@u(SkZ05Fc9^HMPLIIGXP8iorHFh!X$-%jM$)AB)GlEM#ebtIkp2x zvBVc9y!YznQtU#m!qlF>`jQ;q`RbW1!PcN5CMP>F91Q2vl z6l(z3Fvg~gu}TOrqmXzS0SD+iyg~>PHqs@E5|ldz=p|zeU#;h*2$W^H1pu@LTEu&# zlpp8wdFQ>zSiW7zQ2Ubt#Jp42^^DrcNi9SKT}df-9ThnUAy!n<(F8(3U$56aD$6NQGh&{|Okc=Y2$Dd-~unDJOTh#1kX+g z@jsC~!;Q2ohd^6MZ_)pfn{C5B6Rt+XjjsC~!; z@S@6cJ?d>Pm@0d!Z8Z3@EH^Rs2_k@(RUa$?VBIoF(N14_2z4os&*Pk9RdK+vKK2PF zV9Ks+wQY$*+$Qm5t_yb!x>zihQcCoHbEvC>UHV=zY7WEqAWHs#r04rDjP~tQh0S6IXk%!&hYTn-ViRytabyR<#znu-5%0Af$sMs|l@~#T0 z?30y%J^ZxKQ`#ph0hROS*4Z?3O8aCd;HrX|{e4!4_0BhFjCvF~iIJ&g3y_ z6S60+e!uVPFn9%2FWgpU4IqVmviE=nYbVeDjuiB}x67v4Ereh08*IKldO87Xu#x{Z zq!1gV0_L9N`}IZvJ!lGr0t&r9Xaz#SQSOffC@ST=Ggcs{x|C;+6`-h;^Um8>;18NL VOh8L-9h?9F002ovPDHLkV1i)oGU5OL literal 0 HcmV?d00001 diff --git a/hwtxtreaderlib/src/main/res/drawable/rounded_question_background.xml b/hwtxtreaderlib/src/main/res/drawable/rounded_question_background.xml new file mode 100644 index 0000000..5daee35 --- /dev/null +++ b/hwtxtreaderlib/src/main/res/drawable/rounded_question_background.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/hwtxtreaderlib/src/main/res/layout/activity_chatwithgpt.xml b/hwtxtreaderlib/src/main/res/layout/activity_chatwithgpt.xml index 4ff46d3..bf5d540 100644 --- a/hwtxtreaderlib/src/main/res/layout/activity_chatwithgpt.xml +++ b/hwtxtreaderlib/src/main/res/layout/activity_chatwithgpt.xml @@ -1,4 +1,3 @@ - + + + + + + + + + + + + + + + + + + + + + + - - - + 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" /> + app:layout_constraintRight_toLeftOf="@id/sendButton" /> - -