more
This commit is contained in:
parent
3cbd591bc6
commit
c58566c82e
|
|
@ -7,11 +7,11 @@ import type { Conversation, LLMMessage } from './llm';
|
|||
export function AIConversation({ history, conversation }: { history: LLMMessage[], conversation: Conversation }) {
|
||||
const [input, setInput] = useState('');
|
||||
|
||||
const onSubmit = useCallback(async (event: React.FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
setInput('');
|
||||
const content = new FormData(event.target as any).get('content') as string;
|
||||
await conversation.send(content);
|
||||
const onSubmit = useCallback(() => {
|
||||
setInput(content => {
|
||||
conversation.send(content);
|
||||
return '';
|
||||
});
|
||||
}, [conversation]);
|
||||
|
||||
return (
|
||||
|
|
@ -34,29 +34,33 @@ export function AIConversation({ history, conversation }: { history: LLMMessage[
|
|||
))}
|
||||
</div>
|
||||
|
||||
<form onSubmit={onSubmit} className="input-form">
|
||||
<input
|
||||
type="text"
|
||||
<div className="input-form">
|
||||
<textarea
|
||||
name='content'
|
||||
value={input}
|
||||
onChange={(e) => setInput(e.target.value)}
|
||||
onKeyDown={e => {
|
||||
if (e.key === 'Enter' && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
onSubmit();
|
||||
}
|
||||
}}
|
||||
placeholder="Ask a question..."
|
||||
className="message-input"
|
||||
/>
|
||||
{conversation.isSending() ? (
|
||||
<button type="button" className="send-button" onClick={(evt) => {
|
||||
evt.preventDefault()
|
||||
console.log("aborting")
|
||||
conversation.abortSending();
|
||||
}}>
|
||||
Cancel
|
||||
</button>
|
||||
) : (
|
||||
<button type="submit" className="send-button" disabled={!input.trim()}>
|
||||
<button className="send-button" disabled={!input.trim()} onClick={onSubmit}>
|
||||
Send
|
||||
</button>
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ class LLMChat {
|
|||
getConversation(id: string, systemPrompt: string) {
|
||||
if (!this.conversations.has(id)) {
|
||||
const conversation = new Conversation(this, systemPrompt);
|
||||
this.conversations.set(id, conversation);
|
||||
this.conversations.set(id, conversation); // TODO: cleanup
|
||||
}
|
||||
return this.conversations.get(id)!;
|
||||
}
|
||||
|
|
@ -178,36 +178,37 @@ class LLMChat {
|
|||
export class Conversation {
|
||||
history: LLMMessage[];
|
||||
onChange = new EventEmitter<void>();
|
||||
private _abortController: AbortController | undefined;
|
||||
private _abortControllers = new Set<AbortController>();
|
||||
|
||||
constructor(private chat: LLMChat, systemPrompt: string) {
|
||||
this.history = [{ role: 'developer', content: systemPrompt }];
|
||||
}
|
||||
|
||||
async send(content: string, displayContent?: string) {
|
||||
if (this.isSending())
|
||||
throw new Error('Already sending');
|
||||
|
||||
const response: LLMMessage = { role: 'assistant', content: '' };
|
||||
this.history.push({ role: 'user', content, displayContent }, response);
|
||||
const abortController = new AbortController();
|
||||
this._abortControllers.add(abortController);
|
||||
this.onChange.fire();
|
||||
this._abortController = new AbortController();
|
||||
try {
|
||||
for await (const chunk of this.chat.api.chatCompletion(this.history, this._abortController.signal)) {
|
||||
for await (const chunk of this.chat.api.chatCompletion(this.history, abortController.signal)) {
|
||||
response.content += chunk;
|
||||
this.onChange.fire();
|
||||
}
|
||||
} finally {
|
||||
this._abortController = undefined;
|
||||
this._abortControllers.delete(abortController);
|
||||
this.onChange.fire();
|
||||
}
|
||||
}
|
||||
|
||||
isSending(): boolean {
|
||||
return this._abortController !== undefined;
|
||||
return this._abortControllers.size > 0;
|
||||
}
|
||||
|
||||
abortSending() {
|
||||
this._abortController!.abort();
|
||||
for (const controller of this._abortControllers)
|
||||
controller.abort();
|
||||
this._abortControllers.clear();
|
||||
this.onChange.fire();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue