import * as React from 'react' import {__, _x, sprintf} from '@wordpress/i18n' import { useState, useMemo, useRef, useEffect, } from '@wordpress/element' import { __experimentalVStack as VStack, __experimentalView as View, TextareaControl, ToggleControl, BaseControl, } from '@wordpress/components' import { Button, ButtonGroup, UserJsonView, } from '@ska/components' import { useSkaBlocksOptions, } from '@ska/shared' import { getRandomSuggestions, getSuggestions, } from '../../suggestions' import { ModelPicker, } from '../model-picker' import type { Message, AISession, } from '../../types' import './style.scss' export interface ChatProps { /** AI session context. */ session: AISession /** Current prompt. */ prompt: string /** Update prompt. */ setPrompt: (nextPrompt: string) => void /** Whether user needs to enter a prompt. */ promptRequired?: boolean /** Custom model. */ model: string /** Update custom model. */ setModel: (nextModel: string) => void /** Content to display above the chat. */ description?: React.ReactNode /** Additional suggestion options. */ suggestions?: string[] /** Loading AI response. */ isLoading?: boolean /** Current state. */ messages: Message[] /** Prompt that was sent to AI. */ onSend: (prompt: string) => void /** Abort query. */ onAbort: () => void /** End chat session. */ onEndSession?: () => void } const noop = (...args: any) => {} const NO_SUGGESTIONS: string[] = [] const Chat: React.FC = ({ session, prompt, setPrompt, promptRequired = true, model, setModel, description = null, suggestions: additionalSuggestions = NO_SUGGESTIONS, isLoading, messages, onSend, onAbort, onEndSession = noop, }) => { const { openRouterModel, } = useSkaBlocksOptions() const { mode = 'html', value, } = session const hasValue = !!value const promptRef = useRef(null) const [includeValue, setIncludeValue] = useState(true) const [overrideModel, setOverrideModel] = useState(!!model) const getPrompt = (prompt: string = '') => { let msg = prompt || (promptRequired ? '{Prompt or suggestion}' : 'Please do as instructed by the system prompt.') if(hasValue) { switch(mode) { case 'html': if(includeValue) { msg += `\n\nThis is the current HTML, please make the modifications to this:\n${value}` } break case 'text': msg += `\n\nThis is the current text, please make the modifications to this:\n${value}` break } } else { switch(mode) { case 'text': msg += `\n\nThere is currently no text, please generate something related to the request above.` break } } return msg } const sendPrompt = (prompt: string) => { onSend(getPrompt(prompt)) } const { suggestions = NO_SUGGESTIONS, placeholder = '', } = useMemo(() => { const suggestionsFor = (hasValue ? `edit-${mode}` : `initial-${mode}`) as 'edit-text' return { suggestions: NO_SUGGESTIONS, ...(mode === 'html' && { placeholder: getRandomSuggestions(suggestionsFor, 1)[0], suggestions: [...getRandomSuggestions(suggestionsFor, 10), ...additionalSuggestions], }), ...(mode === 'text' && { placeholder: getRandomSuggestions(suggestionsFor, 1)[0], suggestions: [...getSuggestions(suggestionsFor), ...additionalSuggestions], }), ...(mode === 'seo' && { placeholder: hasValue ? _x('Improvement suggestions', 'SEO prompt placeholder', 'ska-blocks') : _x('Optional additional details', 'SEO prompt placeholder', 'ska-blocks'), }), } }, [hasValue, mode, additionalSuggestions]) useEffect(() => { promptRef?.current?.focus() }, []) return ( {isLoading && <>

{__('Awaiting response from AI…', 'ska-blocks')}

} {!isLoading && <> {description} {suggestions.length > 0 && <> ({label: v, value: v}))} onChange={suggestion => { suggestion && sendPrompt(suggestion) }} /> } 0 ? __('…or write a prompt', 'ska-blocks') : __('Write a prompt', 'ska-blocks')} placeholder={placeholder ? `${placeholder}…` : ''} value={prompt} onChange={setPrompt} __nextHasNoMarginBottom /> {hasValue && mode === 'html' && <> } { const nextOverrideModel = !overrideModel if(!nextOverrideModel && model) { setModel('') } setOverrideModel(nextOverrideModel) }} __nextHasNoMarginBottom /> {overrideModel && ( )}
}
) } export default Chat