feat: 全栈 Logger 依赖注入 — DB/Route/AI 层传参 + 前端 Logger + 测试更新 + 归档 add-frontend-logger
This commit is contained in:
@@ -11,6 +11,7 @@ import {
|
||||
fetchMessages,
|
||||
updateConversation,
|
||||
} from "../../../../hooks/use-conversations";
|
||||
import { useLogger } from "../../../../hooks/use-logger";
|
||||
import { useModelList } from "../../../../hooks/use-models";
|
||||
import { ChatInputArea } from "./ChatInputArea";
|
||||
import { ReasoningPart } from "./parts/ReasoningPart";
|
||||
@@ -25,6 +26,7 @@ interface ChatPanelProps {
|
||||
|
||||
export function ChatPanel({ conversationId, onConversationCreated, projectId }: ChatPanelProps) {
|
||||
const { message } = App.useApp();
|
||||
const logger = useLogger().child({ component: "ChatPanel", page: "workbench" });
|
||||
const queryClient = useQueryClient();
|
||||
const [input, setInput] = useState("");
|
||||
const [editingMessageId, setEditingMessageId] = useState<null | string>(null);
|
||||
@@ -45,6 +47,7 @@ export function ChatPanel({ conversationId, onConversationCreated, projectId }:
|
||||
|
||||
const { messages, regenerate, sendMessage, setMessages, status, stop } = useChat({
|
||||
onError: (err) => {
|
||||
logger.error("聊天发送失败", { error: err.message });
|
||||
void message.error(`发送失败:${err.message}`);
|
||||
},
|
||||
transport: new DefaultChatTransport({ api: `/api/projects/${projectId}/chat` }),
|
||||
@@ -87,6 +90,7 @@ export function ChatPanel({ conversationId, onConversationCreated, projectId }:
|
||||
} catch (err: unknown) {
|
||||
if (!cancelled) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
logger.error("加载历史失败", { conversationId, error: msg, projectId });
|
||||
void message.error(`加载历史失败:${msg}`);
|
||||
}
|
||||
} finally {
|
||||
@@ -99,22 +103,27 @@ export function ChatPanel({ conversationId, onConversationCreated, projectId }:
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [conversationId, projectId, setMessages, message]);
|
||||
}, [conversationId, projectId, setMessages, message, logger]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!conversationId) return;
|
||||
const firstTextId = textModels[0]?.id;
|
||||
if (!firstTextId) return;
|
||||
|
||||
void fetchConversation(projectId, conversationId).then((conv) => {
|
||||
if (textModels.every((m) => m.id !== conv.modelId)) {
|
||||
setSelectedModelId(firstTextId);
|
||||
void updateConversation(projectId, conversationId, { modelId: firstTextId });
|
||||
} else {
|
||||
setSelectedModelId(conv.modelId);
|
||||
}
|
||||
});
|
||||
}, [conversationId, textModels, projectId]);
|
||||
void fetchConversation(projectId, conversationId)
|
||||
.then((conv) => {
|
||||
if (textModels.every((m) => m.id !== conv.modelId)) {
|
||||
setSelectedModelId(firstTextId);
|
||||
void updateConversation(projectId, conversationId, { modelId: firstTextId });
|
||||
} else {
|
||||
setSelectedModelId(conv.modelId);
|
||||
}
|
||||
})
|
||||
.catch((err: unknown) => {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
logger.warn("获取会话模型信息失败", { conversationId, error: msg, projectId });
|
||||
});
|
||||
}, [conversationId, textModels, projectId, logger]);
|
||||
|
||||
useEffect(() => {
|
||||
scrollRef.current?.scrollTo({ behavior: "smooth", top: scrollRef.current.scrollHeight });
|
||||
@@ -132,10 +141,13 @@ export function ChatPanel({ conversationId, onConversationCreated, projectId }:
|
||||
(value: string) => {
|
||||
setSelectedModelId(value);
|
||||
if (conversationId) {
|
||||
void updateConversation(projectId, conversationId, { modelId: value });
|
||||
void updateConversation(projectId, conversationId, { modelId: value }).catch((err: unknown) => {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
logger.warn("更新会话模型失败", { conversationId, error: msg, projectId });
|
||||
});
|
||||
}
|
||||
},
|
||||
[projectId, conversationId],
|
||||
[projectId, conversationId, logger],
|
||||
);
|
||||
|
||||
const handleSend = useCallback(async () => {
|
||||
@@ -153,13 +165,27 @@ export function ChatPanel({ conversationId, onConversationCreated, projectId }:
|
||||
} catch (err: unknown) {
|
||||
setInput(text);
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
logger.error("创建会话失败", { error: msg, projectId });
|
||||
void message.error(`创建会话失败:${msg}`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void sendMessage({ text }, { body: { conversationId } });
|
||||
}, [input, sendMessage, conversationId, projectId, onConversationCreated, message, queryClient, displayModelId]);
|
||||
void sendMessage({ text }, { body: { conversationId } }).catch((err: unknown) => {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
logger.error("发送消息失败", { conversationId, error: msg, projectId });
|
||||
});
|
||||
}, [
|
||||
input,
|
||||
sendMessage,
|
||||
conversationId,
|
||||
projectId,
|
||||
onConversationCreated,
|
||||
message,
|
||||
queryClient,
|
||||
displayModelId,
|
||||
logger,
|
||||
]);
|
||||
|
||||
const extractText = useCallback((msg: UIMessage) => {
|
||||
return msg.parts
|
||||
@@ -171,11 +197,17 @@ export function ChatPanel({ conversationId, onConversationCreated, projectId }:
|
||||
const handleCopy = useCallback(
|
||||
(msg: UIMessage) => {
|
||||
const text = extractText(msg);
|
||||
void navigator.clipboard.writeText(text).then(() => {
|
||||
void message.success("已复制");
|
||||
});
|
||||
void navigator.clipboard
|
||||
.writeText(text)
|
||||
.then(() => {
|
||||
void message.success("已复制");
|
||||
})
|
||||
.catch((err: unknown) => {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
logger.warn("复制失败", { error: msg });
|
||||
});
|
||||
},
|
||||
[extractText, message],
|
||||
[extractText, message, logger],
|
||||
);
|
||||
|
||||
const handleEditStart = useCallback(
|
||||
@@ -192,8 +224,11 @@ export function ChatPanel({ conversationId, onConversationCreated, projectId }:
|
||||
const idx = messages.findIndex((m) => m.id === editingMessageId);
|
||||
if (idx === -1) return;
|
||||
setMessages(messages.slice(0, idx));
|
||||
void sendMessage({ text: editText }, { body: { conversationId } });
|
||||
}, [editText, conversationId, messages, editingMessageId, setMessages, sendMessage]);
|
||||
void sendMessage({ text: editText }, { body: { conversationId } }).catch((err: unknown) => {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
logger.error("重新发送消息失败", { conversationId, error: msg, projectId });
|
||||
});
|
||||
}, [editText, conversationId, messages, editingMessageId, setMessages, sendMessage, logger, projectId]);
|
||||
|
||||
const handleEditCancel = useCallback(() => {
|
||||
setEditingMessageId(null);
|
||||
@@ -202,8 +237,11 @@ export function ChatPanel({ conversationId, onConversationCreated, projectId }:
|
||||
|
||||
const handleRegenerate = useCallback(() => {
|
||||
if (!conversationId) return;
|
||||
void regenerate({ body: { conversationId } });
|
||||
}, [regenerate, conversationId]);
|
||||
void regenerate({ body: { conversationId } }).catch((err: unknown) => {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
logger.error("重新生成失败", { conversationId, error: msg, projectId });
|
||||
});
|
||||
}, [regenerate, conversationId, logger, projectId]);
|
||||
|
||||
const getCardExtra = useCallback(
|
||||
(msg: UIMessage, idx: number) => {
|
||||
@@ -282,7 +320,10 @@ export function ChatPanel({ conversationId, onConversationCreated, projectId }:
|
||||
void handleSend();
|
||||
}}
|
||||
onStop={() => {
|
||||
void stop();
|
||||
void stop().catch((err: unknown) => {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
logger.warn("停止聊天失败", { error: msg });
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
@@ -350,7 +391,10 @@ export function ChatPanel({ conversationId, onConversationCreated, projectId }:
|
||||
void handleSend();
|
||||
}}
|
||||
onStop={() => {
|
||||
void stop();
|
||||
void stop().catch((err: unknown) => {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
logger.warn("停止聊天失败", { error: msg });
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user