@tw2gem/gemini-live-client
Version:
TypeScript client for real-time communication with Gemini Live, designed to send audio input and receive AI responses using Google's LLM.
82 lines (65 loc) • 2.78 kB
text/typescript
import { BidiGenerateContentRealtimeInput, BidiGenerateContentServerContent, BidiGenerateContentServerMessage, BidiRequest, GeminiLiveClientOptions } from './gemini-live.dto';
import { CloseEvent, ErrorEvent, MessageEvent, WebSocket } from 'ws';
export class GeminiLiveClient {
private static readonly DEFAULT_GEMINI_BIDI_SERVER = 'wss://generativelanguage.googleapis.com/ws/google.ai.generativelanguage.v1beta.GenerativeService.BidiGenerateContent';
private socket: WebSocket;
public isReady: boolean;
public onReady?: () => void;
public onError?: (event: ErrorEvent) => void;
public onClose?: (event: CloseEvent) => void;
public onServerContent?: (serverContent: BidiGenerateContentServerContent) => void;
constructor(
private options: GeminiLiveClientOptions
) {
const server = options.server;
const baseUrl = server?.url || GeminiLiveClient.DEFAULT_GEMINI_BIDI_SERVER;
const queryParams = server?.apiKey ? `key=${server.apiKey}` : '';
const url = `${baseUrl}?${queryParams}`;
this.socket = new WebSocket(url);
this.socket.onopen = this.sendSetup.bind(this);
this.socket.onmessage = this.handlerMessage.bind(this);
this.socket.onerror = (event) => {
this.isReady = false;
this.onError?.(event);
};
this.socket.onclose = (event) => {
this.isReady = false;
this.onClose?.(event);
};
}
protected sendSetup() {
const jsonPayload = JSON.stringify({ setup: this.options.setup });
this.socket.send(jsonPayload);
}
protected async handlerMessage(event: MessageEvent) {
const isBuffer = event.data instanceof Buffer;
if (!isBuffer)
return;
const blob = event.data;
const text = blob.toString();
const obj: BidiGenerateContentServerMessage = JSON.parse(text);
if (obj.setupComplete) {
this.isReady = true;
return this.onReady?.();
}
if (obj.serverContent) {
return this.onServerContent?.(obj.serverContent);
}
};
public sendText(text: string) {
const realtimeInput: BidiGenerateContentRealtimeInput = { text };
this.send({ realtimeInput });
}
public sendRealTime(realTimeData: BidiGenerateContentRealtimeInput) {
this.send({ realtimeInput: realTimeData });
}
protected send(request: BidiRequest) {
if (!this.isReady)
return;
const jsonPayload = JSON.stringify(request);
this.socket.send(jsonPayload);
}
public close() {
this.socket.close();
}
}