init: 昔涟项目骨架

This commit is contained in:
2026-05-15 20:10:35 +08:00
commit 6bde87f807
84 changed files with 3635 additions and 0 deletions
@@ -0,0 +1,80 @@
import { useEffect, useCallback } from 'react';
import { useWebSocket } from '@/hooks/useWebSocket';
import { useChatStore } from '@/store/chatStore';
import { MessageList } from './MessageList';
import { ChatInput } from './ChatInput';
import { CyreneAvatar } from '@/components/persona/CyreneAvatar';
import { MoodIndicator } from '@/components/persona/MoodIndicator';
export function ChatContainer({ sessionId }: { sessionId: string }) {
const { messages, isTyping, addMessage, setTyping } = useChatStore();
const { connect, sendMessage, onMessage } = useWebSocket(sessionId);
useEffect(() => {
// 连接WebSocket (使用JWT token)
const token = localStorage.getItem('token');
if (token) connect(token);
// 监听回复
onMessage('onResponse', (msg) => {
addMessage({
id: msg.message_id,
role: 'assistant',
content: msg.text || '',
audioUrl: msg.full_audio_url,
segments: msg.segments?.map(s => ({
index: s.index,
text: s.text,
audioUrl: s.audio_url,
})),
timestamp: msg.timestamp,
isStreaming: false,
});
setTyping(false);
});
onMessage('onError', (msg) => {
addMessage({
id: msg.message_id,
role: 'assistant',
content: '啊……不好意思,人家刚才走神了。能再说一遍吗?♪',
timestamp: Date.now(),
});
setTyping(false);
});
}, [sessionId]);
const handleSend = useCallback((content: string, mode: string) => {
// 添加用户消息
addMessage({
id: `user-${Date.now()}`,
role: 'user',
content,
timestamp: Date.now(),
});
setTyping(true);
sendMessage(content, mode);
}, [sendMessage, addMessage, setTyping]);
return (
<div className="flex flex-col h-screen bg-[#FFFAF5] dark:bg-[#1a1a2e]">
{/* 顶部栏 */}
<header className="flex items-center justify-between px-6 py-3 border-b border-pink-100 dark:border-pink-900">
<div className="flex items-center gap-3">
<CyreneAvatar size="sm" />
<div>
<h1 className="text-lg font-semibold text-pink-600"></h1>
<MoodIndicator />
</div>
</div>
<span className="text-sm text-gray-400">🌸 </span>
</header>
{/* 消息列表 */}
<MessageList messages={messages} isTyping={isTyping} />
{/* 输入区域 */}
<ChatInput onSend={handleSend} disabled={isTyping} />
</div>
);
}