Commit 50510818 authored by AI-甘富林's avatar AI-甘富林

多轮对话记忆

parent 6d7edaac
......@@ -113,6 +113,7 @@ async function loadConversationHistory(
maxMessages = 20
): Promise<HistoryMessage[]> {
try {
console.log(`🔍 [ai-chat-stream] 查询历史: conv_id=${conversationId} user_id=${userId} limit=${maxMessages}`);
const { data, error } = await supabase
.from('messages')
.select('sender_type, content')
......@@ -122,11 +123,11 @@ async function loadConversationHistory(
.limit(maxMessages);
if (error) {
console.error('[ai-chat-stream] 加载历史消息失败:', error);
console.error('❌ [ai-chat-stream] 加载历史消息失败:', JSON.stringify(error));
return [];
}
console.log(`📜 [ai-chat-stream] Loaded ${data?.length || 0} history messages for conversation ${conversationId}`);
console.log(`📜 [ai-chat-stream] 历史查询结果: conversation_id=${conversationId} user_id=${userId} rows=${data?.length || 0}`);
return (data || []).map((m: any) => ({
role: m.sender_type === 'user' ? 'user' : 'assistant',
content: m.content,
......@@ -262,8 +263,11 @@ Deno.serve(async (req) => {
trace_id: traceId,
message: message?.substring(0, 80),
catalogCount: inputs?.catalog?.length || 0,
conversationId: conversationId || '(new)',
localConversationId: localConversationId || '(not provided)',
conversationId: conversationId || '(empty)',
localConversationId: localConversationId || '(empty)',
localConversationId_type: typeof localConversationId,
inputs_user_id: inputs?.user_id || '(empty)',
inputs_user_id_type: typeof inputs?.user_id,
});
const supabaseUrl = Deno.env.get('SUPABASE_URL')!;
......@@ -307,8 +311,20 @@ Deno.serve(async (req) => {
// ─── 加载对话历史 ───
let historyMessages: HistoryMessage[] = [];
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
const userId = (inputs.user_id && uuidRegex.test(inputs.user_id)) ? inputs.user_id : crypto.randomUUID();
const localConvId = localConversationId || crypto.randomUUID(); // 前端没传则后端生成,保障多轮记忆自给自足
const rawUserId = inputs.user_id;
const userIdPassed = !!(rawUserId && uuidRegex.test(rawUserId));
const userId = userIdPassed ? rawUserId : crypto.randomUUID();
const localConvIdPassed = !!(localConversationId && uuidRegex.test(localConversationId));
const localConvId = localConvIdPassed ? localConversationId! : crypto.randomUUID();
console.log('🔑 [ai-chat-stream] ID resolution:', {
rawUserId,
userIdPassed,
userId_used: userId,
rawLocalConvId: localConversationId,
localConvIdPassed,
localConvId_used: localConvId,
});
if (localConvId && userId) {
historyMessages = await loadConversationHistory(supabase, localConvId, userId, 20);
......@@ -478,18 +494,29 @@ Deno.serve(async (req) => {
.map(c => ({ id: c.id, name: c.name }));
console.log('🔎 [ai-chat-stream] Product IDs mentioned in text:', JSON.stringify(mentionedIds));
// ─── 保存消息到数据库1(服务端写入,保障多轮记忆)───
// ─── 保存消息到数据库(服务端写入,保障多轮记忆)───
if (localConvId && userId) {
const baseTime = new Date();
const userTs = baseTime.toISOString();
const aiTs = new Date(baseTime.getTime() + 1).toISOString(); // +1ms 保证顺序
console.log('💾 [ai-chat-stream] 准备写入 DB:', {
conversation_id: localConvId,
user_id: userId,
user_msg_len: message.length,
ai_msg_len: fullAnswer.length,
});
// 确保 conversations 表有对应行(访客场景下前端只写 localStorage,FK 约束会拒绝 messages 写入)
const { error: upsertConvError } = await supabase.from('conversations').upsert({
id: localConvId,
user_id: userId,
}, { onConflict: 'id' });
if (upsertConvError) console.error('[ai-chat-stream] upsert conversations 失败:', upsertConvError);
if (upsertConvError) {
console.error('❌ [ai-chat-stream] upsert conversations 失败:', JSON.stringify(upsertConvError));
} else {
console.log('✅ [ai-chat-stream] conversations 已 upsert');
}
// 保存用户消息
const { error: saveUserError } = await supabase.from('messages').insert({
......@@ -500,7 +527,11 @@ Deno.serve(async (req) => {
message_type: 'text',
created_at: userTs,
});
if (saveUserError) console.error('[ai-chat-stream] 保存用户消息失败:', saveUserError, { code: saveUserError?.code });
if (saveUserError) {
console.error('❌ [ai-chat-stream] 保存用户消息失败:', JSON.stringify(saveUserError));
} else {
console.log('✅ [ai-chat-stream] 用户消息已保存');
}
// 保存 AI 回复
const { error: saveAiError } = await supabase.from('messages').insert({
......@@ -512,8 +543,13 @@ Deno.serve(async (req) => {
metadata: { picks, intent, highlights, title },
created_at: aiTs,
});
if (saveAiError) console.error('[ai-chat-stream] 保存 AI 回复失败:', saveAiError, { code: saveAiError?.code });
else console.log('💾 [ai-chat-stream] 消息已保存到 DB');
if (saveAiError) {
console.error('❌ [ai-chat-stream] 保存 AI 回复失败:', JSON.stringify(saveAiError));
} else {
console.log('✅ [ai-chat-stream] AI 回复已保存');
}
} else {
console.error('❌ [ai-chat-stream] 跳过 DB 写入 — localConvId 或 userId 为空:', { localConvId, userId });
}
// ─── 发送最终元数据 ───
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment