Trudy's picture
adding proxy running local
854a551
/**
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { FunctionDeclaration, SchemaType } from "@google/generative-ai";
import { useEffect, useRef, useState, memo } from "react";
import vegaEmbed from "vega-embed";
import { useLiveAPIContext } from "../../contexts/LiveAPIContext";
import { ToolCall } from "../../multimodal-live-types";
function P5SketchComponent() {
const containerRef = useRef<HTMLDivElement>(null);
const [jsonString, setJSONString] = useState<string>("");
const { client, setConfig } = useLiveAPIContext();
useEffect(() => {
const w = window as any;
if (containerRef.current && w.initSketch) {
w.initSketch(containerRef.current);
}
}, [containerRef]);
useEffect(() => {
setConfig({
model: "models/gemini-2.0-flash-exp",
generationConfig: {
responseModalities: "text",
//responseModalities: "audio",
/*
speechConfig: {
voiceConfig: { prebuiltVoiceConfig: { voiceName: "Kobe" } },
},
*/
},
systemInstruction: {
parts: [
{
text: `We have circles on a canvas that we can move and resize. Every time that I ask you something, I want you to use the "get_circles" function to understand where the circles are. Once you receive the response for "get_circles" I want you to use "change_circle" to modify one or multiple circle properties to accomplish our mutual goal. Every time I ask you ask you to do something you should call "get_circles" then "change_circle" after evaluating the response.
The circles blend additively using screen mode, so if I ask you mix colors, you can make the color by moving circles to the same position to blend their colors.
`
},
],
},
tools: [
// there is a free-tier quota for search
{ googleSearch: {} },
{
functionDeclarations: [
{
name: "get_circles",
description: "Get a list of circles in my application",
},
{
name: "change_circle",
description: "Change one of the circles",
parameters: {
type: SchemaType.OBJECT,
properties: {
color: {
type: SchemaType.STRING,
},
x: {
type: SchemaType.NUMBER,
},
y: {
type: SchemaType.NUMBER,
},
radius: {
type: SchemaType.NUMBER,
},
},
required: ["color", "x", "y", "radius"],
},
},
],
},
],
});
}, [setConfig]);
useEffect(() => {
const onToolCall = (toolCall: ToolCall) => {
console.log(`got toolcall`, toolCall);
toolCall.functionCalls.forEach((fc) => {
const w = window as any;
const func: Function = w[fc.name];
if (fc.name === "get_circles") {
setTimeout(
() =>
client.sendToolResponse({
functionResponses: [
{
response: w.get_circles(),
id: fc.id,
},
],
}),
500,
);
} else if (func && typeof func === "function") {
func(fc.args);
client.sendToolResponse({
functionResponses: [
{
response: {
content: { ...w.get_circles() },
},
id: fc.id,
},
],
});
} else {
console.error(`Unhandled function call for ${fc.name}`);
}
});
};
client.on("toolcall", onToolCall);
return () => {
client.off("toolcall", onToolCall);
};
}, [client]);
const embedRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (embedRef.current && jsonString) {
vegaEmbed(embedRef.current, JSON.parse(jsonString));
}
}, [embedRef, jsonString]);
return (
<div
ref={containerRef}
style={{
width: "100vw",
height: "100vh",
alignItems: "center",
justifyContent: "center",
display: "flex",
}}
/>
);
}
export const P5Sketch = memo(P5SketchComponent);