Spaces:
Configuration error
Configuration error
import { | |
ChangeEvent, | |
FormEventHandler, | |
useCallback, | |
useMemo, | |
useState, | |
} from "react"; | |
import "./settings-dialog.scss"; | |
import { useLiveAPIContext } from "../../contexts/LiveAPIContext"; | |
import { LiveConfig } from "../../multimodal-live-types"; | |
import { | |
FunctionDeclaration, | |
FunctionDeclarationsTool, | |
Tool, | |
} from "@google/generative-ai"; | |
import VoiceSelector from "./VoiceSelector"; | |
import ResponseModalitySelector from "./ResponseModalitySelector"; | |
export default function SettingsDialog() { | |
const [open, setOpen] = useState(false); | |
const { config, setConfig, connected } = useLiveAPIContext(); | |
const functionDeclarations: FunctionDeclaration[] = useMemo(() => { | |
if (!Array.isArray(config.tools)) { | |
return []; | |
} | |
return (config.tools as Tool[]) | |
.filter((t: Tool): t is FunctionDeclarationsTool => | |
Array.isArray((t as any).functionDeclarations) | |
) | |
.map((t) => t.functionDeclarations) | |
.filter((fc) => !!fc) | |
.flat(); | |
}, [config]); | |
const systemInstruction = useMemo(() => { | |
const s = config.systemInstruction?.parts.find((p) => p.text)?.text || ""; | |
return s; | |
}, [config]); | |
const updateConfig: FormEventHandler<HTMLTextAreaElement> = useCallback( | |
(event: ChangeEvent<HTMLTextAreaElement>) => { | |
const newConfig: LiveConfig = { | |
...config, | |
systemInstruction: { | |
parts: [{ text: event.target.value }], | |
}, | |
}; | |
setConfig(newConfig); | |
}, | |
[config, setConfig] | |
); | |
const updateFunctionDescription = useCallback( | |
(editedFdName: string, newDescription: string) => { | |
const newConfig: LiveConfig = { | |
...config, | |
tools: | |
config.tools?.map((tool) => { | |
const fdTool = tool as FunctionDeclarationsTool; | |
if (!Array.isArray(fdTool.functionDeclarations)) { | |
return tool; | |
} | |
return { | |
...tool, | |
functionDeclarations: fdTool.functionDeclarations.map((fd) => | |
fd.name === editedFdName | |
? { ...fd, description: newDescription } | |
: fd | |
), | |
}; | |
}) || [], | |
}; | |
setConfig(newConfig); | |
}, | |
[config, setConfig] | |
); | |
return ( | |
<div className="settings-dialog"> | |
<button | |
className="action-button material-symbols-outlined" | |
onClick={() => setOpen(!open)} | |
> | |
settings | |
</button> | |
<dialog className="dialog" style={{ display: open ? "block" : "none" }}> | |
<div className={`dialog-container ${connected ? "disabled" : ""}`}> | |
{connected && ( | |
<div className="connected-indicator"> | |
<p> | |
These settings can only be applied before connecting and will | |
override other settings. | |
</p> | |
</div> | |
)} | |
<div className="mode-selectors"> | |
<ResponseModalitySelector /> | |
<VoiceSelector /> | |
</div> | |
<h3>System Instructions</h3> | |
<textarea | |
className="system" | |
onChange={updateConfig} | |
value={systemInstruction} | |
/> | |
<h4>Function declarations</h4> | |
<div className="function-declarations"> | |
<div className="fd-rows"> | |
{functionDeclarations.map((fd, fdKey) => ( | |
<div className="fd-row" key={`function-${fdKey}`}> | |
<span className="fd-row-name">{fd.name}</span> | |
<span className="fd-row-args"> | |
{Object.keys(fd.parameters?.properties || {}).map( | |
(item, k) => ( | |
<span key={k}>{item}</span> | |
) | |
)} | |
</span> | |
<input | |
key={`fd-${fd.description}`} | |
className="fd-row-description" | |
type="text" | |
defaultValue={fd.description} | |
onBlur={(e) => | |
updateFunctionDescription(fd.name, e.target.value) | |
} | |
/> | |
</div> | |
))} | |
</div> | |
</div> | |
</div> | |
</dialog> | |
</div> | |
); | |
} | |