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 0000000..c606f94 Binary files /dev/null and b/hwtxtreaderlib/src/main/res/drawable/ic_loading.png differ diff --git a/hwtxtreaderlib/src/main/res/drawable/ic_return.png b/hwtxtreaderlib/src/main/res/drawable/ic_return.png new file mode 100644 index 0000000..04afdbd Binary files /dev/null and b/hwtxtreaderlib/src/main/res/drawable/ic_return.png differ 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 0000000..533e7c3 Binary files /dev/null and b/hwtxtreaderlib/src/main/res/drawable/ic_send.png differ 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" /> - -