From 99dc2807be92a4c62cf3b758bfdfdb1f7f0950ad Mon Sep 17 00:00:00 2001 From: wangdl Date: Sat, 6 Jun 2026 18:19:30 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20AIChat=20=E5=85=A8=E9=93=BE=E8=B7=AF?= =?UTF-8?q?=E8=B0=83=E8=AF=95=E6=97=A5=E5=BF=97=20+=20=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E8=AF=A6=E6=83=85=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit load/createSession/loadSession/send 都加了 print 日志: - scope 参数 - 请求成功/失败状态 - 具体错误信息 sessionError 现在显示具体错误原因而非通用"创建对话失败" Co-Authored-By: Claude Opus 4.7 --- .../AIStudyApp/Core/Services/APIService.swift | 10 ++++++- .../Features/AI/AIChatViewModel.swift | 28 +++++++++++++++---- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/AIStudyApp/AIStudyApp/Core/Services/APIService.swift b/AIStudyApp/AIStudyApp/Core/Services/APIService.swift index a7f3faa..8c90d3e 100644 --- a/AIStudyApp/AIStudyApp/Core/Services/APIService.swift +++ b/AIStudyApp/AIStudyApp/Core/Services/APIService.swift @@ -353,7 +353,15 @@ class RagChatService { title: nil, forceCreate: forceCreate ? true : nil ) - return try await client.request("/rag-chat/sessions", method: "POST", body: body) + print("[RagChat] POST /rag-chat/sessions — scopeType=\(body.scopeType), scopeId=\(body.scopeId ?? "nil"), parentKB=\(body.parentKnowledgeBaseId ?? "nil"), forceCreate=\(forceCreate)") + do { + let session = try await client.request("/rag-chat/sessions", method: "POST", body: body) as ChatSession + print("[RagChat] createSession OK — id=\(session.id), scopeType=\(session.scopeType ?? "nil")") + return session + } catch { + print("[RagChat] createSession FAILED: \(error)") + throw error + } } func listSessions(scopeType: String? = nil, scopeId: String? = nil, parentKnowledgeBaseId: String? = nil) async throws -> [ChatSession] { diff --git a/AIStudyApp/AIStudyApp/Features/AI/AIChatViewModel.swift b/AIStudyApp/AIStudyApp/Features/AI/AIChatViewModel.swift index 9b8fb17..7759fbc 100644 --- a/AIStudyApp/AIStudyApp/Features/AI/AIChatViewModel.swift +++ b/AIStudyApp/AIStudyApp/Features/AI/AIChatViewModel.swift @@ -74,12 +74,18 @@ final class AIChatViewModel: ObservableObject { createdFrom: "global_ai_entry" ) + print("[AIChat] load() entry — scopeType=\(ctx.scopeType.rawValue), scopeId=\(ctx.scopeId ?? "nil"), parentKB=\(ctx.parentKnowledgeBaseId ?? "nil")") + do { - // open-or-create: backend handles find-or-create logic let session = try await RagChatService.shared.createSession(ctx: ctx) + print("[AIChat] open-or-create OK — sessionId=\(session.id), isNew=\(session.createdAt == session.updatedAt)") await loadSession(session.id) } catch { - sessionError = "创建对话失败" + print("[AIChat] open-or-create FAILED: \(error)") + if let apiErr = error as? APIError { + print("[AIChat] APIError detail: \(apiErr)") + } + sessionError = "创建对话失败: \(error.localizedDescription)" isCreatingSession = false } } @@ -89,7 +95,6 @@ final class AIChatViewModel: ObservableObject { messages = [] isCreatingSession = true - // Use entry context if available, otherwise default to global let ctx = entryContext ?? ChatEntryContext( scopeType: .global, scopeId: nil, @@ -98,14 +103,18 @@ final class AIChatViewModel: ObservableObject { createdFrom: "global_ai_entry" ) + print("[AIChat] createNewSession() — scopeType=\(ctx.scopeType.rawValue), scopeId=\(ctx.scopeId ?? "nil")") + do { let session = try await RagChatService.shared.createSession(ctx: ctx, forceCreate: true) + print("[AIChat] forceCreate OK — sessionId=\(session.id)") sessionId = session.id let scopeLabel = ctx.scopeType != .global ? "「\(ctx.scopeName)」的" : "" messages = [AIMessage(role: .ai, content: "你好!我是你的 AI 学习助手,基于\(scopeLabel)内容回答问题。")] isCreatingSession = false } catch { - sessionError = "创建对话失败" + print("[AIChat] forceCreate FAILED: \(error)") + sessionError = "创建对话失败: \(error.localizedDescription)" isCreatingSession = false } } @@ -113,6 +122,7 @@ final class AIChatViewModel: ObservableObject { func send() { guard canSend, let sid = sessionId else { return } let text = inputText.trimmingCharacters(in: .whitespacesAndNewlines) + print("[AIChat] send — sessionId=\(sid), text=\(text.prefix(50))") messages.append(AIMessage(role: .user, content: text)) inputText = "" isSending = true @@ -139,10 +149,12 @@ final class AIChatViewModel: ObservableObject { messages[idx] = AIMessage(role: .ai, content: reply, thinkingContent: thinking, isStreaming: true, id: placeholderId) } case "error": + print("[AIChat] stream error: \(chunk.content ?? "unknown")") if let idx = messages.firstIndex(where: { $0.id == placeholderId }) { messages[idx] = AIMessage(role: .ai, content: "请求失败: \(chunk.content ?? "未知错误")") } case "done": + print("[AIChat] stream done — reply=\(reply.count)chars, thinking=\(thinking.count)chars") if let idx = messages.firstIndex(where: { $0.id == placeholderId }) { messages[idx] = AIMessage(role: .ai, content: reply, thinkingContent: thinking.isEmpty ? nil : thinking) } @@ -150,6 +162,7 @@ final class AIChatViewModel: ObservableObject { } } } catch { + print("[AIChat] stream FAILED: \(error)") if let idx = messages.firstIndex(where: { $0.id == placeholderId }) { messages[idx] = AIMessage(role: .ai, content: "发送失败: \(error.localizedDescription)") } @@ -164,7 +177,9 @@ final class AIChatViewModel: ObservableObject { sessionId = id isCreatingSession = true do { + print("[AIChat] loadSession — id=\(id)") let msgs: [ChatMessage] = try await RagChatService.shared.getMessages(sessionId: id) + print("[AIChat] loadSession OK — \(msgs.count) messages") // Update entryContext from the first message's scope snapshot (if available) if let snapshot = msgs.first?.scopeSnapshot, @@ -191,7 +206,10 @@ final class AIChatViewModel: ObservableObject { AIMessage(role: m.role == "user" ? .user : .ai, content: m.content, citations: m.citations) } } - } catch { sessionError = "加载对话失败" } + } catch { + print("[AIChat] loadSession FAILED: \(error)") + sessionError = "加载对话失败: \(error.localizedDescription)" + } isCreatingSession = false } }