feat: 恢复模型直答功能及直答历史
Some checks failed
Flask 提示词大师 - CI/CD 流水线 / 代码质量检查 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 单元测试 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 集成测试 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 构建Docker镜像 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 部署到测试环境 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 部署到生产环境 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 部署监控系统 (push) Has been cancelled
Some checks failed
Flask 提示词大师 - CI/CD 流水线 / 代码质量检查 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 单元测试 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 集成测试 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 构建Docker镜像 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 部署到测试环境 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 部署到生产环境 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 部署监控系统 (push) Has been cancelled
This commit is contained in:
@@ -13,6 +13,7 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.button.MaterialButton;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.ruilaizi.example.adapter.DirectAnswerHistoryAdapter;
|
||||
import com.ruilaizi.example.adapter.GenerationHistoryAdapter;
|
||||
import com.ruilaizi.example.adapter.OptimizeHistoryAdapter;
|
||||
import com.ruilaizi.example.databinding.ActivityHistoryBinding;
|
||||
@@ -20,7 +21,7 @@ import com.ruilaizi.example.ui.HistoryViewModel;
|
||||
|
||||
|
||||
/**
|
||||
* 生成历史 / 优化历史 页面。
|
||||
* 生成历史 / 优化历史 / 直答历史 页面。
|
||||
*/
|
||||
public class HistoryActivity extends AppCompatActivity {
|
||||
|
||||
@@ -30,6 +31,7 @@ public class HistoryActivity extends AppCompatActivity {
|
||||
private HistoryViewModel viewModel;
|
||||
private OptimizeHistoryAdapter optimizeAdapter;
|
||||
private GenerationHistoryAdapter generationAdapter;
|
||||
private DirectAnswerHistoryAdapter directAnswerAdapter;
|
||||
private int currentTab = 0;
|
||||
|
||||
@Override
|
||||
@@ -63,16 +65,28 @@ public class HistoryActivity extends AppCompatActivity {
|
||||
finish();
|
||||
});
|
||||
|
||||
directAnswerAdapter = new DirectAnswerHistoryAdapter();
|
||||
directAnswerAdapter.setOnUseDirectAnswerListener(question -> {
|
||||
Intent data = new Intent();
|
||||
data.putExtra(EXTRA_USE_PROMPT, question);
|
||||
setResult(RESULT_OK, data);
|
||||
finish();
|
||||
});
|
||||
|
||||
binding.recyclerOptimize.setLayoutManager(new LinearLayoutManager(this));
|
||||
binding.recyclerOptimize.setAdapter(optimizeAdapter);
|
||||
|
||||
binding.recyclerGeneration.setLayoutManager(new LinearLayoutManager(this));
|
||||
binding.recyclerGeneration.setAdapter(generationAdapter);
|
||||
|
||||
binding.recyclerDirectAnswer.setLayoutManager(new LinearLayoutManager(this));
|
||||
binding.recyclerDirectAnswer.setAdapter(directAnswerAdapter);
|
||||
}
|
||||
|
||||
private void setupTabs() {
|
||||
binding.tabHistory.addTab(binding.tabHistory.newTab().setText(R.string.history_tab_optimize));
|
||||
binding.tabHistory.addTab(binding.tabHistory.newTab().setText(R.string.history_tab_generation));
|
||||
binding.tabHistory.addTab(binding.tabHistory.newTab().setText(R.string.history_tab_direct_answer));
|
||||
|
||||
binding.tabHistory.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
|
||||
@Override
|
||||
@@ -90,15 +104,10 @@ public class HistoryActivity extends AppCompatActivity {
|
||||
|
||||
private void switchTab(int index) {
|
||||
currentTab = index;
|
||||
if (index == 0) {
|
||||
binding.recyclerOptimize.setVisibility(View.VISIBLE);
|
||||
binding.recyclerGeneration.setVisibility(View.GONE);
|
||||
updateEmptyVisibility();
|
||||
} else {
|
||||
binding.recyclerOptimize.setVisibility(View.GONE);
|
||||
binding.recyclerGeneration.setVisibility(View.VISIBLE);
|
||||
updateEmptyVisibility();
|
||||
}
|
||||
binding.recyclerOptimize.setVisibility(index == 0 ? View.VISIBLE : View.GONE);
|
||||
binding.recyclerGeneration.setVisibility(index == 1 ? View.VISIBLE : View.GONE);
|
||||
binding.recyclerDirectAnswer.setVisibility(index == 2 ? View.VISIBLE : View.GONE);
|
||||
updateEmptyVisibility();
|
||||
}
|
||||
|
||||
private void setupBack() {
|
||||
@@ -114,12 +123,18 @@ public class HistoryActivity extends AppCompatActivity {
|
||||
generationAdapter.setData(list);
|
||||
updateEmptyVisibility();
|
||||
});
|
||||
viewModel.getDirectAnswerRecords().observe(this, list -> {
|
||||
directAnswerAdapter.setData(list);
|
||||
updateEmptyVisibility();
|
||||
});
|
||||
}
|
||||
|
||||
private void updateEmptyVisibility() {
|
||||
boolean optEmpty = optimizeAdapter.getItemCount() == 0;
|
||||
boolean genEmpty = generationAdapter.getItemCount() == 0;
|
||||
boolean directEmpty = directAnswerAdapter.getItemCount() == 0;
|
||||
binding.emptyOptimize.setVisibility(currentTab == 0 && optEmpty ? View.VISIBLE : View.GONE);
|
||||
binding.emptyGeneration.setVisibility(currentTab == 1 && genEmpty ? View.VISIBLE : View.GONE);
|
||||
binding.emptyDirectAnswer.setVisibility(currentTab == 2 && directEmpty ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,6 +115,10 @@ public class MainActivity extends AppCompatActivity {
|
||||
if (btnOptimize != null) {
|
||||
btnOptimize.setOnClickListener(v -> viewModel.optimizePrompt());
|
||||
}
|
||||
MaterialButton btnDirectAnswer = binding.btnDirectAnswer;
|
||||
if (btnDirectAnswer != null) {
|
||||
btnDirectAnswer.setOnClickListener(v -> viewModel.directAnswer());
|
||||
}
|
||||
}
|
||||
|
||||
private void setupResultAndActions() {
|
||||
@@ -144,9 +148,11 @@ public class MainActivity extends AppCompatActivity {
|
||||
ProgressBar progress = binding.progressBar;
|
||||
MaterialButton btn = binding.btnGenerate;
|
||||
MaterialButton btnOpt = binding.btnOptimize;
|
||||
MaterialButton btnDirect = binding.btnDirectAnswer;
|
||||
if (progress != null) progress.setVisibility(loading != null && loading ? View.VISIBLE : View.GONE);
|
||||
if (btn != null) btn.setEnabled(loading == null || !loading);
|
||||
if (btnOpt != null) btnOpt.setEnabled(loading == null || !loading);
|
||||
if (btnDirect != null) btnDirect.setEnabled(loading == null || !loading);
|
||||
});
|
||||
|
||||
viewModel.getErrorLiveData().observe(this, error -> {
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
package com.ruilaizi.example.adapter;
|
||||
|
||||
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.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.button.MaterialButton;
|
||||
import com.ruilaizi.example.R;
|
||||
import com.ruilaizi.example.data.db.DirectAnswerRecord;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class DirectAnswerHistoryAdapter extends RecyclerView.Adapter<DirectAnswerHistoryAdapter.ViewHolder> {
|
||||
|
||||
private final List<DirectAnswerRecord> list = new ArrayList<>();
|
||||
private OnUseDirectAnswerListener onUseDirectAnswerListener;
|
||||
|
||||
public interface OnUseDirectAnswerListener {
|
||||
void onUseQuestion(String question);
|
||||
}
|
||||
|
||||
public void setOnUseDirectAnswerListener(OnUseDirectAnswerListener listener) {
|
||||
this.onUseDirectAnswerListener = listener;
|
||||
}
|
||||
|
||||
public void setData(List<DirectAnswerRecord> data) {
|
||||
list.clear();
|
||||
if (data != null) {
|
||||
list.addAll(data);
|
||||
}
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_direct_answer_history, parent, false);
|
||||
return new ViewHolder(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
DirectAnswerRecord r = list.get(position);
|
||||
holder.tvQuestion.setText("问:" + truncate(r.question, 80));
|
||||
holder.tvAnswer.setText("答:" + truncate(r.answer, 150));
|
||||
holder.tvTime.setText(formatTime(r.createdAt));
|
||||
|
||||
holder.btnUse.setOnClickListener(v -> {
|
||||
if (onUseDirectAnswerListener != null && r.question != null) {
|
||||
onUseDirectAnswerListener.onUseQuestion(r.question);
|
||||
}
|
||||
});
|
||||
|
||||
holder.btnCopy.setOnClickListener(v -> {
|
||||
if (r.answer != null && !r.answer.isEmpty()) {
|
||||
ClipboardManager cm = (ClipboardManager) holder.itemView.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
if (cm != null) {
|
||||
cm.setPrimaryClip(ClipData.newPlainText("直答", r.answer));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
private static String truncate(String s, int maxLen) {
|
||||
if (s == null) return "";
|
||||
if (s.length() <= maxLen) return s;
|
||||
return s.substring(0, maxLen) + "…";
|
||||
}
|
||||
|
||||
private static String formatTime(long timestamp) {
|
||||
try {
|
||||
return new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault()).format(new Date(timestamp));
|
||||
} catch (Exception e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView tvQuestion, tvAnswer, tvTime;
|
||||
MaterialButton btnUse, btnCopy;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
tvQuestion = itemView.findViewById(R.id.tv_question);
|
||||
tvAnswer = itemView.findViewById(R.id.tv_answer);
|
||||
tvTime = itemView.findViewById(R.id.tv_time);
|
||||
btnUse = itemView.findViewById(R.id.btn_use);
|
||||
btnCopy = itemView.findViewById(R.id.btn_copy);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import androidx.room.Database;
|
||||
import androidx.room.Room;
|
||||
import androidx.room.RoomDatabase;
|
||||
|
||||
@Database(entities = {GenerationRecord.class, OptimizeRecord.class}, version = 2, exportSchema = false)
|
||||
@Database(entities = {GenerationRecord.class, OptimizeRecord.class, DirectAnswerRecord.class}, version = 3, exportSchema = false)
|
||||
public abstract class AppDatabase extends RoomDatabase {
|
||||
|
||||
private static volatile AppDatabase INSTANCE;
|
||||
@@ -28,4 +28,5 @@ public abstract class AppDatabase extends RoomDatabase {
|
||||
|
||||
public abstract GenerationRecordDao generationRecordDao();
|
||||
public abstract OptimizeRecordDao optimizeRecordDao();
|
||||
public abstract DirectAnswerRecordDao directAnswerRecordDao();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.ruilaizi.example.data.db;
|
||||
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.Ignore;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
/**
|
||||
* 模型直答记录:用户提问 + 模型回答。
|
||||
*/
|
||||
@Entity(tableName = "direct_answer_records")
|
||||
public class DirectAnswerRecord {
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
public long id;
|
||||
|
||||
/** 用户提问 */
|
||||
public String question;
|
||||
/** 模型回答 */
|
||||
public String answer;
|
||||
/** 创建时间戳 */
|
||||
public long createdAt;
|
||||
|
||||
public DirectAnswerRecord() {}
|
||||
|
||||
@Ignore
|
||||
public DirectAnswerRecord(String question, String answer) {
|
||||
this.question = question;
|
||||
this.answer = answer;
|
||||
this.createdAt = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.ruilaizi.example.data.db;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.Query;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Dao
|
||||
public interface DirectAnswerRecordDao {
|
||||
|
||||
@Insert
|
||||
long insert(DirectAnswerRecord record);
|
||||
|
||||
@Query("SELECT * FROM direct_answer_records ORDER BY createdAt DESC LIMIT 50")
|
||||
LiveData<List<DirectAnswerRecord>> getRecentRecords();
|
||||
|
||||
@Query("DELETE FROM direct_answer_records WHERE id NOT IN (SELECT id FROM direct_answer_records ORDER BY createdAt DESC LIMIT 50)")
|
||||
void keepOnlyRecent();
|
||||
}
|
||||
@@ -10,6 +10,8 @@ import com.ruilaizi.example.data.api.OpenAICompletionService;
|
||||
import com.ruilaizi.example.data.api.StreamCallback;
|
||||
import com.ruilaizi.example.data.db.AppDatabase;
|
||||
import com.ruilaizi.example.data.db.GenerationRecord;
|
||||
import com.ruilaizi.example.data.db.DirectAnswerRecord;
|
||||
import com.ruilaizi.example.data.db.DirectAnswerRecordDao;
|
||||
import com.ruilaizi.example.data.db.GenerationRecordDao;
|
||||
import com.ruilaizi.example.data.db.OptimizeRecord;
|
||||
import com.ruilaizi.example.data.db.OptimizeRecordDao;
|
||||
@@ -24,6 +26,7 @@ public class GenerationRepository {
|
||||
private final ApiKeyProvider apiKeyProvider;
|
||||
private final GenerationRecordDao generationDao;
|
||||
private final OptimizeRecordDao optimizeDao;
|
||||
private final DirectAnswerRecordDao directAnswerDao;
|
||||
private final PromptGenerator promptGenerator;
|
||||
|
||||
public GenerationRepository(Context context) {
|
||||
@@ -31,6 +34,7 @@ public class GenerationRepository {
|
||||
aiService = new com.ruilaizi.example.data.api.OpenAIStreamService(null);
|
||||
generationDao = AppDatabase.getInstance(context).generationRecordDao();
|
||||
optimizeDao = AppDatabase.getInstance(context).optimizeRecordDao();
|
||||
directAnswerDao = AppDatabase.getInstance(context).directAnswerRecordDao();
|
||||
promptGenerator = new PromptGenerator(new OpenAICompletionService(null), apiKeyProvider);
|
||||
}
|
||||
|
||||
@@ -92,10 +96,21 @@ public class GenerationRepository {
|
||||
return generationDao.getRecentRecords();
|
||||
}
|
||||
|
||||
public void saveDirectAnswerRecord(DirectAnswerRecord record) {
|
||||
new Thread(() -> {
|
||||
directAnswerDao.insert(record);
|
||||
directAnswerDao.keepOnlyRecent();
|
||||
}).start();
|
||||
}
|
||||
|
||||
public LiveData<java.util.List<OptimizeRecord>> getRecentOptimizeRecords() {
|
||||
return optimizeDao.getRecentRecords();
|
||||
}
|
||||
|
||||
public LiveData<java.util.List<DirectAnswerRecord>> getRecentDirectAnswerRecords() {
|
||||
return directAnswerDao.getRecentRecords();
|
||||
}
|
||||
|
||||
/**
|
||||
* 智能提示词优化(两阶段专家逻辑)。需在后台线程调用。
|
||||
*/
|
||||
|
||||
@@ -6,6 +6,7 @@ import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LiveData;
|
||||
|
||||
import com.ruilaizi.example.data.db.DirectAnswerRecord;
|
||||
import com.ruilaizi.example.data.db.GenerationRecord;
|
||||
import com.ruilaizi.example.data.db.OptimizeRecord;
|
||||
import com.ruilaizi.example.data.repository.GenerationRepository;
|
||||
@@ -31,4 +32,8 @@ public class HistoryViewModel extends AndroidViewModel {
|
||||
public LiveData<List<GenerationRecord>> getGenerationRecords() {
|
||||
return repository.getRecentRecords();
|
||||
}
|
||||
|
||||
public LiveData<List<DirectAnswerRecord>> getDirectAnswerRecords() {
|
||||
return repository.getRecentDirectAnswerRecords();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.ruilaizi.example.data.api.StreamCallback;
|
||||
import com.ruilaizi.example.data.db.DirectAnswerRecord;
|
||||
import com.ruilaizi.example.data.db.GenerationRecord;
|
||||
import com.ruilaizi.example.data.db.OptimizeRecord;
|
||||
import com.ruilaizi.example.data.prompt.PromptGenerator;
|
||||
@@ -154,6 +155,49 @@ public class MainViewModel extends AndroidViewModel {
|
||||
});
|
||||
}
|
||||
|
||||
/** 模型直答:直接以用户输入提问,流式返回回答并保存历史 */
|
||||
public void directAnswer() {
|
||||
String question = promptLiveData.getValue();
|
||||
if (question == null) question = "";
|
||||
question = question.trim();
|
||||
if (question.isEmpty()) {
|
||||
snackbarLiveData.setValue("请输入问题");
|
||||
return;
|
||||
}
|
||||
if (repository.getApiKey() == null || repository.getApiKey().isEmpty()) {
|
||||
errorLiveData.setValue("请先在设置中配置 API Key,或使用后端网关");
|
||||
return;
|
||||
}
|
||||
streamingBuffer.setLength(0);
|
||||
resultLiveData.setValue("");
|
||||
loadingLiveData.setValue(true);
|
||||
errorLiveData.setValue(null);
|
||||
final String questionForRecord = question;
|
||||
repository.requestStream(question, 1, 1, new StreamCallback() {
|
||||
@Override
|
||||
public void onChunk(String textChunk) {
|
||||
streamingBuffer.append(textChunk);
|
||||
resultLiveData.postValue(streamingBuffer.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
loadingLiveData.postValue(false);
|
||||
String full = streamingBuffer.toString();
|
||||
if (full.length() > 0) {
|
||||
repository.saveDirectAnswerRecord(new DirectAnswerRecord(questionForRecord, full));
|
||||
}
|
||||
snackbarLiveData.postValue("回答完成");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable t) {
|
||||
loadingLiveData.postValue(false);
|
||||
errorLiveData.postValue(t != null ? t.getMessage() : "直答失败");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** 重新生成:用上次的 prompt 和参数再调一次 */
|
||||
public void regenerate() {
|
||||
if (lastPrompt != null && !lastPrompt.isEmpty()) {
|
||||
|
||||
@@ -67,6 +67,15 @@
|
||||
android:clipToPadding="false"
|
||||
tools:listitem="@layout/item_generation_history" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler_direct_answer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone"
|
||||
android:padding="12dp"
|
||||
android:clipToPadding="false"
|
||||
tools:listitem="@layout/item_direct_answer_history" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/empty_optimize"
|
||||
android:layout_width="wrap_content"
|
||||
@@ -84,5 +93,14 @@
|
||||
android:text="@string/history_empty_generation"
|
||||
android:textColor="@color/colorTextSecondary"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/empty_direct_answer"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/history_empty_direct_answer"
|
||||
android:textColor="@color/colorTextSecondary"
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
android:textColor="@color/colorTextSecondary" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 操作按钮区:优化 + 生成 -->
|
||||
<!-- 操作按钮区:优化 + 生成 + 直答 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -220,16 +220,25 @@
|
||||
android:layout_height="56dp"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/btn_optimize"
|
||||
android:layout_marginEnd="8dp" />
|
||||
android:layout_marginEnd="4dp" />
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_generate"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="56dp"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/btn_generate"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginEnd="4dp" />
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_direct_answer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="56dp"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/btn_direct_answer"
|
||||
app:backgroundTint="@color/colorPrimary"
|
||||
android:textColor="@color/colorWhite"
|
||||
android:layout_marginStart="8dp" />
|
||||
android:layout_marginStart="4dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 加载指示 -->
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.card.MaterialCardView 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"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardBackgroundColor="@color/colorCard"
|
||||
app:cardElevation="2dp"
|
||||
app:cardCornerRadius="12dp"
|
||||
android:layout_marginBottom="12dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_question"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/colorTextDark"
|
||||
android:textSize="14sp"
|
||||
android:maxLines="2"
|
||||
android:ellipsize="end"
|
||||
tools:text="问:什么是机器学习?" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_answer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:textColor="@color/colorText"
|
||||
android:textSize="13sp"
|
||||
android:maxLines="4"
|
||||
android:ellipsize="end"
|
||||
tools:text="答:机器学习是..." />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:textColor="@color/colorTextSecondary"
|
||||
android:textSize="11sp"
|
||||
tools:text="2025-03-02 14:30" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginTop="8dp">
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_use"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/history_use" />
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_copy"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/btn_copy" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
@@ -16,6 +16,7 @@
|
||||
<string name="temp_balanced">平衡</string>
|
||||
<string name="temp_creative">创意</string>
|
||||
<string name="btn_generate">生成</string>
|
||||
<string name="btn_direct_answer">直答</string>
|
||||
<string name="btn_optimize">优化提示词</string>
|
||||
<string name="result_placeholder">生成结果将显示在这里…</string>
|
||||
<string name="btn_copy">复制</string>
|
||||
@@ -24,9 +25,11 @@
|
||||
<string name="btn_history">历史</string>
|
||||
<string name="history_title">生成历史</string>
|
||||
<string name="history_back">返回</string>
|
||||
<string name="history_tab_optimize">优化历史</string>
|
||||
<string name="history_tab_generation">生成历史</string>
|
||||
<string name="history_tab_optimize">优化</string>
|
||||
<string name="history_tab_generation">生成</string>
|
||||
<string name="history_tab_direct_answer">直答</string>
|
||||
<string name="history_empty_optimize">暂无优化记录</string>
|
||||
<string name="history_empty_generation">暂无生成记录</string>
|
||||
<string name="history_empty_direct_answer">暂无直答记录</string>
|
||||
<string name="history_use">使用</string>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user