Compare commits
1 Commits
feature/co
...
a16e1cc42a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a16e1cc42a |
1230
docs/floating-ai-integration-guide.md
Normal file
1230
docs/floating-ai-integration-guide.md
Normal file
File diff suppressed because it is too large
Load Diff
130
src/renderer/hooks/useAIChat.ts
Normal file
130
src/renderer/hooks/useAIChat.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
import { useState, useCallback, useRef } from 'react';
|
||||
import { trpc } from '@/lib/trpc';
|
||||
|
||||
export interface ChatMessage {
|
||||
id: string;
|
||||
role: 'user' | 'assistant';
|
||||
content: string;
|
||||
error?: boolean;
|
||||
}
|
||||
|
||||
export interface ChatContext {
|
||||
type: 'global' | 'project';
|
||||
projectId?: string;
|
||||
uiContext?: string;
|
||||
}
|
||||
|
||||
export interface UseAIChatReturn {
|
||||
messages: ChatMessage[];
|
||||
input: string;
|
||||
setInput: (v: string) => void;
|
||||
isStreaming: boolean;
|
||||
streamingContent: string;
|
||||
handleSend: (overrideMessage?: string, overrideContext?: ChatContext) => void;
|
||||
clearMessages: () => void;
|
||||
}
|
||||
|
||||
export function useAIChat(defaultContext: ChatContext): UseAIChatReturn {
|
||||
const [messages, setMessages] = useState<ChatMessage[]>([]);
|
||||
const [input, setInput] = useState('');
|
||||
const [isStreaming, setIsStreaming] = useState(false);
|
||||
const [streamingContent, setStreamingContent] = useState('');
|
||||
|
||||
const streamingContentRef = useRef('');
|
||||
const chatMutation = trpc.ai.chat.useMutation();
|
||||
|
||||
const clearMessages = useCallback(() => {
|
||||
setMessages([]);
|
||||
setStreamingContent('');
|
||||
streamingContentRef.current = '';
|
||||
}, []);
|
||||
|
||||
const handleSend = useCallback(
|
||||
(overrideMessage?: string, overrideContext?: ChatContext) => {
|
||||
const trimmed = (overrideMessage ?? input).trim();
|
||||
if (!trimmed || isStreaming) return;
|
||||
|
||||
const userMsg: ChatMessage = {
|
||||
id: crypto.randomUUID(),
|
||||
role: 'user',
|
||||
content: trimmed,
|
||||
};
|
||||
|
||||
setMessages((prev) => [...prev, userMsg]);
|
||||
if (!overrideMessage) setInput('');
|
||||
setIsStreaming(true);
|
||||
setStreamingContent('');
|
||||
streamingContentRef.current = '';
|
||||
|
||||
const unsubscribe = window.electronAI.onStreamChunk(({ token, done }) => {
|
||||
if (done) {
|
||||
const finalContent = streamingContentRef.current;
|
||||
setMessages((prev) => [
|
||||
...prev,
|
||||
{ id: crypto.randomUUID(), role: 'assistant', content: finalContent },
|
||||
]);
|
||||
setStreamingContent('');
|
||||
streamingContentRef.current = '';
|
||||
setIsStreaming(false);
|
||||
unsubscribe();
|
||||
return;
|
||||
}
|
||||
streamingContentRef.current += token;
|
||||
setStreamingContent(streamingContentRef.current);
|
||||
});
|
||||
|
||||
const ctx = overrideContext ?? defaultContext;
|
||||
|
||||
chatMutation.mutate(
|
||||
{
|
||||
message: trimmed,
|
||||
context: {
|
||||
type: ctx.type,
|
||||
...(ctx.type === 'project' && ctx.projectId ? { projectId: ctx.projectId } : {}),
|
||||
...(ctx.uiContext ? { uiContext: ctx.uiContext } : {}),
|
||||
},
|
||||
},
|
||||
{
|
||||
onSuccess: (data) => {
|
||||
if (data.error) {
|
||||
unsubscribe();
|
||||
setMessages((prev) => [
|
||||
...prev,
|
||||
{ id: crypto.randomUUID(), role: 'assistant', content: data.error!, error: true },
|
||||
]);
|
||||
setStreamingContent('');
|
||||
streamingContentRef.current = '';
|
||||
setIsStreaming(false);
|
||||
}
|
||||
},
|
||||
onError: (err) => {
|
||||
unsubscribe();
|
||||
setMessages((prev) => [
|
||||
...prev,
|
||||
{
|
||||
id: crypto.randomUUID(),
|
||||
role: 'assistant',
|
||||
content: err.message || 'An unexpected error occurred.',
|
||||
error: true,
|
||||
},
|
||||
]);
|
||||
setStreamingContent('');
|
||||
streamingContentRef.current = '';
|
||||
setIsStreaming(false);
|
||||
},
|
||||
},
|
||||
);
|
||||
},
|
||||
[input, isStreaming, defaultContext, chatMutation],
|
||||
);
|
||||
|
||||
return {
|
||||
messages,
|
||||
input,
|
||||
setInput,
|
||||
isStreaming,
|
||||
streamingContent,
|
||||
handleSend,
|
||||
clearMessages,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user