feat: 将系统提示词加入会话上下文中,系统提示词不会显示在前端。
This commit is contained in:
parent
38faeeb46d
commit
3471e8552f
|
|
@ -223,15 +223,25 @@ async function handleSend(
|
||||||
await chatStore.createConversation();
|
await chatStore.createConversation();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从当前会话中提取历史消息(用于上下文记忆),在添加新消息之前提取
|
// 获取系统提示词(优先使用传入的,否则使用会话设置)
|
||||||
|
const systemPrompt = options?.systemPrompt || currentConversation.value?.settings?.systemPrompt;
|
||||||
|
|
||||||
|
// 检查是否需要添加系统消息
|
||||||
const existingMessages = currentConversation.value?.messages || [];
|
const existingMessages = currentConversation.value?.messages || [];
|
||||||
|
const hasSystemMessage = existingMessages.some((m: any) => m.role === MessageRole.SYSTEM);
|
||||||
|
|
||||||
|
// 如果有系统提示词且对话中没有系统消息,添加系统消息
|
||||||
|
if (systemPrompt && !hasSystemMessage) {
|
||||||
|
await chatStore.addMessage(MessageRole.SYSTEM, {
|
||||||
|
type: MessageType.TEXT,
|
||||||
|
text: systemPrompt,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从当前会话中提取历史消息(用于上下文记忆),在添加新消息之前提取
|
||||||
|
const updatedMessages = currentConversation.value?.messages || [];
|
||||||
const MAX_HISTORY_ROUNDS = 20; // 最多保留最近 20 轮(40 条消息)
|
const MAX_HISTORY_ROUNDS = 20; // 最多保留最近 20 轮(40 条消息)
|
||||||
const historyMessages = existingMessages
|
const historyMessages = updatedMessages.filter((m: any) => m.content?.text) // 过滤掉空消息
|
||||||
.filter(
|
|
||||||
(m: any) =>
|
|
||||||
m.role === MessageRole.USER || m.role === MessageRole.ASSISTANT,
|
|
||||||
)
|
|
||||||
.filter((m: any) => m.content?.text) // 过滤掉空消息
|
|
||||||
.slice(-(MAX_HISTORY_ROUNDS * 2))
|
.slice(-(MAX_HISTORY_ROUNDS * 2))
|
||||||
.map((m: any) => ({ role: m.role, content: m.content.text }));
|
.map((m: any) => ({ role: m.role, content: m.content.text }));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
<div ref="containerRef" class="message-list" @scroll="handleScroll">
|
<div ref="containerRef" class="message-list" @scroll="handleScroll">
|
||||||
<!-- 欢迎界面 -->
|
<!-- 欢迎界面 -->
|
||||||
<WelcomeScreen
|
<WelcomeScreen
|
||||||
v-if="messages.length === 0"
|
v-if="visibleMessages.length === 0"
|
||||||
@select="$emit('select-suggestion', $event)"
|
@select="$emit('select-suggestion', $event)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
@ -12,12 +12,12 @@
|
||||||
<div class="messages-wrapper">
|
<div class="messages-wrapper">
|
||||||
<TransitionGroup name="message">
|
<TransitionGroup name="message">
|
||||||
<MessageBubble
|
<MessageBubble
|
||||||
v-for="(message, index) in messages"
|
v-for="(message, index) in visibleMessages"
|
||||||
:key="message.id"
|
:key="message.id"
|
||||||
:message="message"
|
:message="message"
|
||||||
:show-timestamp="showTimestamp"
|
:show-timestamp="showTimestamp"
|
||||||
:compact="compact"
|
:compact="compact"
|
||||||
:is-New="index === messages.length - 1"
|
:is-New="index === visibleMessages.length - 1"
|
||||||
@retry="$emit('retry', message.id)"
|
@retry="$emit('retry', message.id)"
|
||||||
@regenerate="$emit('regenerate', message.id)"
|
@regenerate="$emit('regenerate', message.id)"
|
||||||
@copy="handleCopy(message)"
|
@copy="handleCopy(message)"
|
||||||
|
|
@ -62,12 +62,13 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, watch, nextTick, onMounted } from "vue";
|
import { ref, watch, nextTick, onMounted, computed } from "vue";
|
||||||
import { useChatStore } from "@/stores/chat";
|
import { useChatStore } from "@/stores/chat";
|
||||||
import MessageBubble from "@/components/message/MessageBubble.vue";
|
import MessageBubble from "@/components/message/MessageBubble.vue";
|
||||||
import WelcomeScreen from "./WelcomeScreen.vue";
|
import WelcomeScreen from "./WelcomeScreen.vue";
|
||||||
import { Bot, ChevronDown } from "@/components/icons";
|
import { Bot, ChevronDown } from "@/components/icons";
|
||||||
import type { Message, Attachment, VideoInfo, Suggestion } from "@/types/chat";
|
import type { Message, Attachment, VideoInfo, Suggestion } from "@/types/chat";
|
||||||
|
import { MessageRole } from "@/types/chat";
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
|
|
@ -83,6 +84,13 @@ const props = withDefaults(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 过滤掉系统消息,不显示在前端
|
||||||
|
const visibleMessages = computed(() => {
|
||||||
|
return props.messages.filter(
|
||||||
|
(message) => message.role !== MessageRole.SYSTEM
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
retry: [messageId: string];
|
retry: [messageId: string];
|
||||||
regenerate: [messageId: string];
|
regenerate: [messageId: string];
|
||||||
|
|
@ -175,7 +183,7 @@ function handleDownloadFile(file: Attachment) {
|
||||||
|
|
||||||
// 监听消息变化
|
// 监听消息变化
|
||||||
watch(
|
watch(
|
||||||
() => props.messages.length,
|
() => visibleMessages.value.length,
|
||||||
(newLen, oldLen) => {
|
(newLen, oldLen) => {
|
||||||
if (newLen > oldLen) {
|
if (newLen > oldLen) {
|
||||||
if (isAutoScrolling.value) {
|
if (isAutoScrolling.value) {
|
||||||
|
|
@ -191,7 +199,7 @@ watch(
|
||||||
|
|
||||||
// 监听最后一条消息的内容变化
|
// 监听最后一条消息的内容变化
|
||||||
watch(
|
watch(
|
||||||
() => props.messages[props.messages.length - 1]?.content.text,
|
() => visibleMessages.value[visibleMessages.value.length - 1]?.content.text,
|
||||||
() => {
|
() => {
|
||||||
if (isAutoScrolling.value) {
|
if (isAutoScrolling.value) {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,7 @@ async function textCopy(data: any) {
|
||||||
/* 可折叠内容 */
|
/* 可折叠内容 */
|
||||||
.thinking-content {
|
.thinking-content {
|
||||||
max-height: 2000px;
|
max-height: 2000px;
|
||||||
overflow: hidden;
|
overflow: auto;
|
||||||
transition:
|
transition:
|
||||||
max-height 0.35s ease,
|
max-height 0.35s ease,
|
||||||
opacity 0.25s ease;
|
opacity 0.25s ease;
|
||||||
|
|
|
||||||
|
|
@ -202,6 +202,7 @@ import FormSelect from "@/components/ui/FormSelect.vue";
|
||||||
import { MessageSquare, X, Check, Trash2 } from "@/components/icons";
|
import { MessageSquare, X, Check, Trash2 } from "@/components/icons";
|
||||||
import { chatApi } from "@/services/api.ts";
|
import { chatApi } from "@/services/api.ts";
|
||||||
import type { ConversationSettings } from "@/types/chat";
|
import type { ConversationSettings } from "@/types/chat";
|
||||||
|
import { MessageRole, MessageType } from "@/types/chat";
|
||||||
|
|
||||||
const chatStore = useChatStore();
|
const chatStore = useChatStore();
|
||||||
const settingsStore = useSettingsStore();
|
const settingsStore = useSettingsStore();
|
||||||
|
|
@ -359,6 +360,25 @@ function handleSave() {
|
||||||
// 调用更新对话设置的方法
|
// 调用更新对话设置的方法
|
||||||
chatStore.updateConversationSettings(conversation.value.id, convSettings);
|
chatStore.updateConversationSettings(conversation.value.id, convSettings);
|
||||||
|
|
||||||
|
// 如果系统提示词有变化,更新消息列表中的系统消息
|
||||||
|
if (localSettings.value.systemPrompt) {
|
||||||
|
const messages = conversation.value.messages || [];
|
||||||
|
const systemMsgIndex = messages.findIndex((m: any) => m.role === MessageRole.SYSTEM);
|
||||||
|
|
||||||
|
if (systemMsgIndex >= 0) {
|
||||||
|
// 更新已有的系统消息
|
||||||
|
chatStore.updateMessage(messages[systemMsgIndex].id, {
|
||||||
|
content: {
|
||||||
|
type: MessageType.TEXT,
|
||||||
|
text: localSettings.value.systemPrompt,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// 添加新的系统消息(放在消息列表开头)
|
||||||
|
chatStore.addSystemMessage(conversation.value.id, localSettings.value.systemPrompt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
close();
|
close();
|
||||||
|
|
||||||
// 显示成功提示
|
// 显示成功提示
|
||||||
|
|
|
||||||
|
|
@ -121,21 +121,36 @@ class ChatApi {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将前端简化的请求翻译为 OpenAI 兼容的规范请求体
|
// 将前端简化的请求翻译为 OpenAI 兼容的规范请求体
|
||||||
// 构建 messages 数组:system + 历史消息 + 当前用户消息
|
// 检查历史消息中是否已有系统消息
|
||||||
|
const historyHasSystem = request.history?.some((m) => m.role === "system");
|
||||||
|
|
||||||
|
// 构建 messages 数组
|
||||||
|
let allMessages: Array<{ role: string; content: any }>;
|
||||||
|
|
||||||
|
if (request.history && request.history.length > 0) {
|
||||||
|
// 如果历史中有系统消息,直接使用历史消息
|
||||||
|
if (historyHasSystem) {
|
||||||
|
allMessages = [...request.history, { role: "user", content: userContent }];
|
||||||
|
} else {
|
||||||
|
// 否则添加系统消息
|
||||||
const systemMessage = {
|
const systemMessage = {
|
||||||
role: "system",
|
role: "system",
|
||||||
content:
|
content:
|
||||||
request.systemPrompt ||
|
request.systemPrompt ||
|
||||||
"你是一个智能助手,可以分析用户发送的文字,文件或图片内容,并进行回答。",
|
"你是一个智能助手,可以分析用户发送的文字,文件或图片内容,并进行回答。",
|
||||||
};
|
};
|
||||||
const currentUserMessage = {
|
allMessages = [systemMessage, ...request.history, { role: "user", content: userContent }];
|
||||||
role: "user",
|
}
|
||||||
content: userContent,
|
} else {
|
||||||
|
// 没有历史消息,添加系统消息
|
||||||
|
const systemMessage = {
|
||||||
|
role: "system",
|
||||||
|
content:
|
||||||
|
request.systemPrompt ||
|
||||||
|
"你是一个智能助手,可以分析用户发送的文字,文件或图片内容,并进行回答。",
|
||||||
};
|
};
|
||||||
const allMessages =
|
allMessages = [systemMessage, { role: "user", content: userContent }];
|
||||||
request.history && request.history.length > 0
|
}
|
||||||
? [systemMessage, ...request.history, currentUserMessage]
|
|
||||||
: [systemMessage, currentUserMessage];
|
|
||||||
|
|
||||||
const openAiRequest = {
|
const openAiRequest = {
|
||||||
model: request.model || "glm-4-flash",
|
model: request.model || "glm-4-flash",
|
||||||
|
|
|
||||||
|
|
@ -290,6 +290,38 @@ export const useChatStore = defineStore("chat", () => {
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 添加系统消息(放在消息列表开头)
|
||||||
|
async function addSystemMessage(
|
||||||
|
conversationId: string,
|
||||||
|
systemPrompt: string
|
||||||
|
): Promise<Message> {
|
||||||
|
const conversation = conversations.value.find((c) => c.id === conversationId);
|
||||||
|
if (!conversation) {
|
||||||
|
throw new Error("Conversation not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
const message: Message = {
|
||||||
|
id: generateId(),
|
||||||
|
role: MessageRole.SYSTEM,
|
||||||
|
content: { type: "text" as const, text: systemPrompt },
|
||||||
|
timestamp: Date.now(),
|
||||||
|
isStreaming: false,
|
||||||
|
} as Message;
|
||||||
|
|
||||||
|
// 将系统消息插入到消息列表开头
|
||||||
|
conversation.messages.unshift(message);
|
||||||
|
conversation.updatedAt = Date.now();
|
||||||
|
|
||||||
|
// 异步保存
|
||||||
|
try {
|
||||||
|
await conversationApi.addMessage(conversationId, message);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to save system message:", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
// 更新消息
|
// 更新消息
|
||||||
async function updateMessage(messageId: string, updates: Partial<Message>) {
|
async function updateMessage(messageId: string, updates: Partial<Message>) {
|
||||||
const conversation = currentConversation.value;
|
const conversation = currentConversation.value;
|
||||||
|
|
@ -479,6 +511,7 @@ export const useChatStore = defineStore("chat", () => {
|
||||||
renameConversation,
|
renameConversation,
|
||||||
updateConversationSettings,
|
updateConversationSettings,
|
||||||
addMessage,
|
addMessage,
|
||||||
|
addSystemMessage,
|
||||||
updateMessage,
|
updateMessage,
|
||||||
updateMessageContent,
|
updateMessageContent,
|
||||||
saveConversation,
|
saveConversation,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue