feat: 新增全局学习模式
This commit is contained in:
parent
8261415b40
commit
9abe247503
|
|
@ -80,12 +80,21 @@
|
|||
</button>
|
||||
</div>
|
||||
</Transition>
|
||||
|
||||
<div class="learning-mode-toggle">
|
||||
<span class="learning-mode-label">学习模式</span>
|
||||
<FormSwitch
|
||||
:model-value="settings.learningModeEnabled"
|
||||
@update:model-value="settingsStore.setLearningModeEnabled($event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { storeToRefs } from "pinia";
|
||||
import {
|
||||
Menu,
|
||||
Trash2,
|
||||
|
|
@ -97,6 +106,7 @@ import {
|
|||
import SidebarExpandIcon from "@/components/icons/custom/SidebarExpandIcon.vue";
|
||||
import SidebarCollapseIcon from "@/components/icons/custom/SidebarCollapseIcon.vue";
|
||||
import { useSettingsStore } from "@/stores/settings.ts";
|
||||
import FormSwitch from "@/components/ui/FormSwitch.vue";
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
|
|
@ -129,6 +139,7 @@ const emit = defineEmits<{
|
|||
|
||||
const showMoreMenu = ref(false);
|
||||
const settingsStore = useSettingsStore();
|
||||
const { settings } = storeToRefs(settingsStore);
|
||||
|
||||
function handleClear() {
|
||||
if (confirm("确定要清空当前对话吗?此操作不可恢复。")) {
|
||||
|
|
@ -244,6 +255,24 @@ if (typeof window !== "undefined") {
|
|||
position: relative;
|
||||
}
|
||||
|
||||
.learning-mode-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.learning-mode-label {
|
||||
font-size: 13px;
|
||||
color: #6b7280;
|
||||
user-select: none;
|
||||
white-space: nowrap;
|
||||
|
||||
.dark & {
|
||||
color: #9ca3af;
|
||||
}
|
||||
}
|
||||
|
||||
.header-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
|||
|
|
@ -216,7 +216,10 @@ async function handleSend(
|
|||
}
|
||||
|
||||
// 获取系统提示词(优先使用传入的,否则使用会话设置)
|
||||
const systemPrompt = options?.systemPrompt || currentConversation.value?.settings?.systemPrompt;
|
||||
const systemPrompt =
|
||||
options?.systemPrompt ||
|
||||
currentConversation.value?.settings?.systemPrompt ||
|
||||
settings.value.defaultSystemPrompt;
|
||||
|
||||
// 检查是否需要添加系统消息
|
||||
const existingMessages = currentConversation.value?.messages || [];
|
||||
|
|
@ -283,7 +286,7 @@ async function handleSend(
|
|||
deepSearch: options?.deepSearch,
|
||||
webSearch: options?.webSearch,
|
||||
deepThinking: options?.deepThinking,
|
||||
systemPrompt: options?.systemPrompt,
|
||||
systemPrompt,
|
||||
},
|
||||
abortController.value.signal,
|
||||
);
|
||||
|
|
@ -404,6 +407,9 @@ async function handleRetry(messageId: string) {
|
|||
currentStreamingMessageId.value = messageId;
|
||||
chatStore.startStreaming();
|
||||
abortController.value = new AbortController();
|
||||
const systemPrompt =
|
||||
currentConversation.value?.settings?.systemPrompt ||
|
||||
settings.value.defaultSystemPrompt;
|
||||
|
||||
try {
|
||||
const stream = chatApi.streamChat(
|
||||
|
|
@ -413,6 +419,7 @@ async function handleRetry(messageId: string) {
|
|||
model: settings.value.defaultModel,
|
||||
stream: true,
|
||||
history: priorMessages,
|
||||
systemPrompt,
|
||||
},
|
||||
abortController.value.signal,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -203,6 +203,8 @@
|
|||
</div>
|
||||
<textarea
|
||||
class="prompt-textarea"
|
||||
:class="{ disabled: settings.learningModeEnabled }"
|
||||
:disabled="settings.learningModeEnabled"
|
||||
:value="settings.defaultSystemPrompt"
|
||||
rows="4"
|
||||
placeholder="输入系统提示词..."
|
||||
|
|
@ -214,6 +216,9 @@
|
|||
})
|
||||
"
|
||||
/>
|
||||
<p v-if="settings.learningModeEnabled" class="setting-desc">
|
||||
当前提示词已由学习模式接管,关闭学习模式后可恢复编辑。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -849,6 +854,16 @@ function handleClearData() {
|
|||
&::placeholder {
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
opacity: 0.7;
|
||||
cursor: not-allowed;
|
||||
background: #f3f4f6;
|
||||
|
||||
.dark & {
|
||||
background: #252533;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.data-actions {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
* 所有端点都是固定的,后端需要实现这些端点
|
||||
*/
|
||||
import { getAuthHeaders } from './request';
|
||||
import { useSettingsStore } from "@/stores/settings";
|
||||
|
||||
// API 端点定义(固定)
|
||||
const API_ENDPOINTS = {
|
||||
|
|
@ -24,6 +25,9 @@ const API_ENDPOINTS = {
|
|||
STOP: "/api/chat-ui/stop",
|
||||
};
|
||||
|
||||
const DEFAULT_SYSTEM_PROMPT =
|
||||
"你是一个智能助手,可以分析用户发送的文字,文件或图片内容,并进行回答。";
|
||||
|
||||
// 请求类型定义
|
||||
export interface ChatMessage {
|
||||
role: "user" | "assistant" | "system";
|
||||
|
|
@ -96,6 +100,24 @@ class ChatApi {
|
|||
this.baseUrl = baseUrl;
|
||||
}
|
||||
|
||||
private resolveSystemPrompt(explicit?: string): string {
|
||||
if (explicit?.trim()) {
|
||||
return explicit.trim();
|
||||
}
|
||||
|
||||
try {
|
||||
const settingsStore = useSettingsStore();
|
||||
const fallbackPrompt = settingsStore.settings.defaultSystemPrompt;
|
||||
if (fallbackPrompt?.trim()) {
|
||||
return fallbackPrompt.trim();
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn("读取全局默认系统提示词失败,使用内置兜底提示词", error);
|
||||
}
|
||||
|
||||
return DEFAULT_SYSTEM_PROMPT;
|
||||
}
|
||||
|
||||
/**
|
||||
* 流式对话
|
||||
*/
|
||||
|
|
@ -135,9 +157,7 @@ class ChatApi {
|
|||
// 否则添加系统消息
|
||||
const systemMessage = {
|
||||
role: "system",
|
||||
content:
|
||||
request.systemPrompt ||
|
||||
"你是一个智能助手,可以分析用户发送的文字,文件或图片内容,并进行回答。",
|
||||
content: this.resolveSystemPrompt(request.systemPrompt),
|
||||
};
|
||||
allMessages = [systemMessage, ...request.history, { role: "user", content: userContent }];
|
||||
}
|
||||
|
|
@ -145,9 +165,7 @@ class ChatApi {
|
|||
// 没有历史消息,添加系统消息
|
||||
const systemMessage = {
|
||||
role: "system",
|
||||
content:
|
||||
request.systemPrompt ||
|
||||
"你是一个智能助手,可以分析用户发送的文字,文件或图片内容,并进行回答。",
|
||||
content: this.resolveSystemPrompt(request.systemPrompt),
|
||||
};
|
||||
allMessages = [systemMessage, { role: "user", content: userContent }];
|
||||
}
|
||||
|
|
@ -257,6 +275,7 @@ class ChatApi {
|
|||
const requestBody = {
|
||||
...request,
|
||||
message: userContent,
|
||||
systemPrompt: this.resolveSystemPrompt(request.systemPrompt),
|
||||
};
|
||||
|
||||
const response = await fetch(`${this.baseUrl}${API_ENDPOINTS.CHAT}`, {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { defineStore } from "pinia";
|
||||
import { ref } from "vue";
|
||||
import type { AppSettings, AIModel } from "@/types/chat";
|
||||
import promptData from "@/assets/prompt.json";
|
||||
|
||||
// 分享结果类型
|
||||
export interface ShareResult {
|
||||
|
|
@ -13,6 +14,10 @@ export interface ShareResult {
|
|||
export const useSettingsStore = defineStore("settings", () => {
|
||||
const MIN_SIDEBAR_WIDTH = 310;
|
||||
const MAX_SIDEBAR_WIDTH = 400;
|
||||
const LEARNING_MODE_PROMPT_TITLE = "让可学 AI 成为我的全科学习导师?";
|
||||
const LEARNING_MODE_SYSTEM_PROMPT =
|
||||
promptData["分析与实践"]?.[LEARNING_MODE_PROMPT_TITLE] ||
|
||||
"你是一位“学习模式”引导员,通过严格的苏格拉底式提问法,引导用户自己思考并逐步得出答案。";
|
||||
|
||||
// 默认设置
|
||||
const defaultSettings: AppSettings = {
|
||||
|
|
@ -31,6 +36,8 @@ export const useSettingsStore = defineStore("settings", () => {
|
|||
defaultTemperature: 0.7,
|
||||
defaultMaxTokens: 4096,
|
||||
defaultSystemPrompt: "你是一个有帮助的 AI 助手。",
|
||||
learningModeEnabled: false,
|
||||
learningModePrevDefaultSystemPrompt: "",
|
||||
|
||||
// 功能设置
|
||||
enableSound: true,
|
||||
|
|
@ -223,9 +230,42 @@ export const useSettingsStore = defineStore("settings", () => {
|
|||
shareResult.value = null;
|
||||
}
|
||||
|
||||
function normalizeLearningModeState() {
|
||||
if (!settings.value.learningModeEnabled) return;
|
||||
|
||||
const currentPrompt = settings.value.defaultSystemPrompt || "";
|
||||
const isUsingLearningPrompt = currentPrompt === LEARNING_MODE_SYSTEM_PROMPT;
|
||||
|
||||
if (!isUsingLearningPrompt && !settings.value.learningModePrevDefaultSystemPrompt) {
|
||||
settings.value.learningModePrevDefaultSystemPrompt = currentPrompt;
|
||||
}
|
||||
|
||||
settings.value.defaultSystemPrompt = LEARNING_MODE_SYSTEM_PROMPT;
|
||||
}
|
||||
|
||||
function setLearningModeEnabled(enabled: boolean) {
|
||||
if (enabled) {
|
||||
if (!settings.value.learningModePrevDefaultSystemPrompt) {
|
||||
settings.value.learningModePrevDefaultSystemPrompt =
|
||||
settings.value.defaultSystemPrompt || defaultSettings.defaultSystemPrompt;
|
||||
}
|
||||
settings.value.learningModeEnabled = true;
|
||||
settings.value.defaultSystemPrompt = LEARNING_MODE_SYSTEM_PROMPT;
|
||||
} else {
|
||||
settings.value.learningModeEnabled = false;
|
||||
if (settings.value.learningModePrevDefaultSystemPrompt) {
|
||||
settings.value.defaultSystemPrompt =
|
||||
settings.value.learningModePrevDefaultSystemPrompt;
|
||||
}
|
||||
settings.value.learningModePrevDefaultSystemPrompt = "";
|
||||
}
|
||||
saveToStorage();
|
||||
}
|
||||
|
||||
// 更新设置
|
||||
function updateSettings(updates: Partial<AppSettings>) {
|
||||
Object.assign(settings.value, updates);
|
||||
normalizeLearningModeState();
|
||||
|
||||
if (updates.theme) {
|
||||
applyTheme(updates.theme);
|
||||
|
|
@ -256,6 +296,7 @@ export const useSettingsStore = defineStore("settings", () => {
|
|||
try {
|
||||
const imported = JSON.parse(json);
|
||||
settings.value = { ...defaultSettings, ...imported };
|
||||
normalizeLearningModeState();
|
||||
applyTheme(settings.value.theme);
|
||||
applyFontSize(settings.value.fontSize);
|
||||
saveToStorage();
|
||||
|
|
@ -304,6 +345,7 @@ export const useSettingsStore = defineStore("settings", () => {
|
|||
if (stored) {
|
||||
settings.value = { ...defaultSettings, ...JSON.parse(stored) };
|
||||
}
|
||||
normalizeLearningModeState();
|
||||
|
||||
const collapsedStored = localStorage.getItem("chat-sidebar-collapsed");
|
||||
if (collapsedStored) {
|
||||
|
|
@ -381,5 +423,6 @@ export const useSettingsStore = defineStore("settings", () => {
|
|||
loadFromStorage,
|
||||
getSelectedModelId,
|
||||
setSelectedModelId,
|
||||
setLearningModeEnabled,
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -126,6 +126,8 @@ export interface AppSettings {
|
|||
defaultTemperature: number;
|
||||
defaultMaxTokens: number;
|
||||
defaultSystemPrompt: string;
|
||||
learningModeEnabled: boolean;
|
||||
learningModePrevDefaultSystemPrompt: string;
|
||||
|
||||
// 功能设置
|
||||
enableSound: boolean;
|
||||
|
|
|
|||
Loading…
Reference in New Issue