2024-07-03 23:32:55 +02:00
// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import { atom , useAtom } from "jotai" ;
import { v4 as uuidv4 } from "uuid" ;
interface ChatMessageType {
id : string ;
user : string ;
text : string ;
isAssistant : boolean ;
2024-07-04 18:07:29 +02:00
isUpdating? : boolean ;
isError? : string ;
2024-07-03 23:32:55 +02:00
}
const defaultMessage : ChatMessageType = {
id : uuidv4 ( ) ,
user : "assistant" ,
text : ` <p>Hello, how may I help you with this command?<br>
( Cmd - Shift - Space : open / close , Ctrl + L : clear chat buffer , Up / Down : select code blocks , Enter : to copy a selected code block to the command input ) < / p > ` ,
isAssistant : true ,
} ;
const messagesAtom = atom < ChatMessageType [ ] > ( [ defaultMessage ] ) ;
const addMessageAtom = atom ( null , ( get , set , message : ChatMessageType ) = > {
const messages = get ( messagesAtom ) ;
set ( messagesAtom , [ . . . messages , message ] ) ;
} ) ;
2024-07-04 18:07:29 +02:00
const updateLastMessageAtom = atom ( null , ( get , set , text : string , isUpdating : boolean ) = > {
2024-07-03 23:32:55 +02:00
const messages = get ( messagesAtom ) ;
const lastMessage = messages [ messages . length - 1 ] ;
2024-07-04 18:07:29 +02:00
if ( lastMessage . isAssistant && ! lastMessage . isError ) {
const updatedMessage = { . . . lastMessage , text : lastMessage.text + text , isUpdating } ;
2024-07-03 23:32:55 +02:00
set ( messagesAtom , [ . . . messages . slice ( 0 , - 1 ) , updatedMessage ] ) ;
}
} ) ;
const simulateAssistantResponseAtom = atom ( null , ( get , set , userMessage : ChatMessageType ) = > {
const responseText = ` Here is an example of a simple bash script:
\ ` \` \` bash
# ! / b i n / b a s h
# This is a comment
echo "Hello, World!"
\ ` \` \`
You can run this script by saving it to a file , for example , \ ` hello.sh \` , and then running \` chmod +x hello.sh \` to make it executable. Finally, run it with \` ./hello.sh \` . ` ;
const typingMessage : ChatMessageType = {
id : uuidv4 ( ) ,
user : "assistant" ,
text : "" ,
isAssistant : true ,
} ;
// Add a typing indicator
set ( addMessageAtom , typingMessage ) ;
setTimeout ( ( ) = > {
const parts = responseText . split ( " " ) ;
let currentPart = 0 ;
const intervalId = setInterval ( ( ) = > {
if ( currentPart < parts . length ) {
const part = parts [ currentPart ] + " " ;
2024-07-04 18:07:29 +02:00
set ( updateLastMessageAtom , part , true ) ;
2024-07-03 23:32:55 +02:00
currentPart ++ ;
} else {
clearInterval ( intervalId ) ;
2024-07-04 18:07:29 +02:00
set ( updateLastMessageAtom , "" , false ) ;
2024-07-03 23:32:55 +02:00
}
} , 100 ) ;
} , 1500 ) ;
} ) ;
const useWaveAi = ( ) = > {
const [ messages ] = useAtom ( messagesAtom ) ;
const [ , addMessage ] = useAtom ( addMessageAtom ) ;
const [ , simulateResponse ] = useAtom ( simulateAssistantResponseAtom ) ;
const sendMessage = ( text : string , user : string = "user" ) = > {
const newMessage : ChatMessageType = {
id : uuidv4 ( ) ,
user ,
text ,
isAssistant : false ,
} ;
addMessage ( newMessage ) ;
simulateResponse ( newMessage ) ;
} ;
return {
messages ,
sendMessage ,
} ;
} ;
export { useWaveAi } ;
export type { ChatMessageType } ;