Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions web/frontend/src/components/chat/chat-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export function ChatPage() {
messages,
isTyping,
activeSessionId,
isLoadingSession,
sendMessage,
switchSession,
newChat,
Expand Down Expand Up @@ -122,13 +123,19 @@ export function ChatPage() {
className="min-h-0 flex-1 overflow-y-auto px-4 py-6 md:px-8 lg:px-24 xl:px-48"
>
<div className="mx-auto flex w-full max-w-250 flex-col gap-8 pb-8">
{messages.length === 0 && !isTyping && (
{isLoadingSession ? (
<div className="flex flex-1 items-center justify-center py-20">
<div className="text-muted-foreground animate-pulse">
{t("chat.loading")}
</div>
</div>
) : messages.length === 0 && !isTyping ? (
<ChatEmptyState
hasConfiguredModels={hasConfiguredModels}
defaultModelName={defaultModelName}
isConnected={isConnected}
/>
)}
) : null}

{messages.map((msg) => (
<div key={msg.id} className="flex w-full">
Expand Down
38 changes: 36 additions & 2 deletions web/frontend/src/hooks/use-pico-chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,8 @@ export function usePicoChat() {
const [connectionState, setConnectionState] =
useState<ConnectionState>("disconnected")
const [isTyping, setIsTyping] = useState(false)
const [activeSessionId, setActiveSessionId] =
useState<string>(generateSessionId)
const [activeSessionId, setActiveSessionId] = useState<string>("")
const [isLoadingSession, setIsLoadingSession] = useState(true)

const wsRef = useRef<WebSocket | null>(null)
const isConnectingRef = useRef(false)
Expand Down Expand Up @@ -290,6 +290,39 @@ export function usePicoChat() {
return () => disconnect()
}, [disconnect])

// Load most recent session on initial mount
useEffect(() => {
const loadRecentSession = async () => {
try {
const sessions = await getSessions(0, 1)
if (sessions.length > 0) {
const recentSession = sessions[0]
const detail = await getSessionHistory(recentSession.id)
const fallbackTime = detail.updated
const historyMessages = detail.messages.map((m, i) => ({
id: `hist-${i}-${Date.now()}`,
role: m.role as "user" | "assistant",
content: m.content,
timestamp: fallbackTime,
}))
setActiveSessionId(recentSession.id)
setMessages(historyMessages)
} else {
// No existing sessions, create a new one
setActiveSessionId(generateSessionId())
}
} catch (err) {
console.error("Failed to load recent session:", err)
// Fall back to new session on error
setActiveSessionId(generateSessionId())
} finally {
setIsLoadingSession(false)
}
}

void loadRecentSession()
}, [])

const sendMessage = useCallback((content: string) => {
if (!wsRef.current || wsRef.current.readyState !== WebSocket.OPEN) {
console.warn("WebSocket not connected")
Expand Down Expand Up @@ -379,6 +412,7 @@ export function usePicoChat() {
connectionState,
isTyping,
activeSessionId,
isLoadingSession,
sendMessage,
switchSession,
newChat,
Expand Down
1 change: 1 addition & 0 deletions web/frontend/src/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"historyLoadFailed": "Failed to load chat history",
"historyOpenFailed": "Failed to open this chat history",
"loadingMore": "Loading more...",
"loading": "Loading...",
"deleteSession": "Delete session",
"messagesCount": "{{count}} messages",
"noModel": "Select model",
Expand Down
1 change: 1 addition & 0 deletions web/frontend/src/i18n/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"historyLoadFailed": "加载历史记录失败",
"historyOpenFailed": "打开该历史会话失败",
"loadingMore": "加载更多...",
"loading": "加载中...",
"deleteSession": "删除会话",
"messagesCount": "{{count}} 条消息",
"noModel": "选择模型",
Expand Down
Loading