Spaces:
Configuration error
Configuration error
File size: 4,278 Bytes
610dd27 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
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>
);
}
|