AI Generation API
Genkit flows for script analysis and SVG asset generation.
Overview
On Book Pro uses Google Genkit with Gemini Pro for:
- Script Analysis — Extract scenes, characters, and props from PDF scripts
- SVG Asset Generation — AI-generated stage furniture icons
Architecture
┌─────────────────┐
│ Client App │
└────────┬────────┘
│ httpsCallable
▼
┌─────────────────┐
│ Firebase │
│ Functions │
└────────┬────────┘
│
▼
┌─────────────────┐ ┌─────────────────┐
│ Genkit Flow │─────►│ Gemini Pro │
└─────────────────┘ └─────────────────┘Script Analysis
Client Request
typescript
import { httpsCallable } from 'firebase/functions';
export const analyzeScript = async (pdfBase64: string) => {
const analyze = httpsCallable(functions, 'analyzeScript');
const result = await analyze({ pdfContent: pdfBase64 });
return result.data as ScriptAnalysisResult;
};Genkit Flow Definition
typescript
// functions/src/ai/analyze-script.ts
import { defineFlow, run } from '@genkit-ai/flow';
import { gemini15Pro } from '@genkit-ai/googleai';
export const analyzeScriptFlow = defineFlow(
{
name: 'analyzeScript',
inputSchema: z.object({
pdfContent: z.string(),
}),
outputSchema: z.object({
scenes: z.array(SceneSchema),
characters: z.array(CharacterSchema),
props: z.array(PropSchema),
}),
},
async (input) => {
const { pdfContent } = input;
// Extract text from PDF
const text = await extractPdfText(pdfContent);
// Call Gemini for analysis
const result = await run('gemini-analysis', async () => {
return gemini15Pro.generate({
prompt: buildAnalysisPrompt(text),
config: {
temperature: 0.2,
maxOutputTokens: 8192,
},
});
});
return parseAnalysisResponse(result.text);
}
);Analysis Prompt Pattern
typescript
const buildAnalysisPrompt = (scriptText: string): string => `
You are a theatrical script analyst. Analyze the following script and extract:
1. **Scenes**: Act/Scene numbers, locations, and brief descriptions
2. **Characters**: Names, descriptions, and notable traits
3. **Props**: Physical objects mentioned in stage directions
Format your response as JSON matching this schema:
{
"scenes": [{"act": number, "scene": number, "location": string, "description": string}],
"characters": [{"name": string, "description": string}],
"props": [{"name": string, "firstAppearance": string}]
}
SCRIPT:
${scriptText}
`;SVG Asset Generation
Client Request
typescript
export const generateStageFurniture = async (description: string) => {
const generate = httpsCallable(functions, 'generateStageFurnitureIcon');
const result = await generate({ description });
return result.data as { svg: string };
};Genkit Flow
typescript
// functions/src/ai/generate-svg.ts
export const generateSvgFlow = defineFlow(
{
name: 'generateStageFurnitureIcon',
inputSchema: z.object({
description: z.string(),
}),
outputSchema: z.object({
svg: z.string(),
}),
},
async (input) => {
const result = await gemini15Pro.generate({
prompt: buildSvgPrompt(input.description),
config: {
temperature: 0.7,
},
});
// Extract SVG from response
const svg = extractSvgFromResponse(result.text);
// Validate SVG
if (!isValidSvg(svg)) {
throw new Error('Invalid SVG generated');
}
return { svg };
}
);SVG Prompt Pattern
typescript
const buildSvgPrompt = (description: string): string => `
Generate a simple, monochrome SVG icon for a piece of stage furniture.
REQUIREMENTS:
- Simple, flat design suitable for a technical drawing
- Single color (use currentColor for flexibility)
- ViewBox: 0 0 48 48
- No gradients or complex effects
- Stage manager-readable at small sizes
DESCRIPTION: ${description}
Return ONLY the SVG code, no explanation.
`;Error Handling
Retry Logic
typescript
const withRetry = async <T>(
fn: () => Promise<T>,
maxRetries: number = 3
): Promise<T> => {
let lastError: Error | undefined;
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
lastError = error as Error;
// Don't retry on validation errors
if (error.message.includes('Invalid')) {
throw error;
}
// Exponential backoff
await new Promise(r => setTimeout(r, Math.pow(2, attempt) * 1000));
}
}
throw lastError;
};Rate Limiting
typescript
import { RateLimiter } from '@/utils/rate-limiter';
const aiLimiter = new RateLimiter({
maxRequests: 10,
windowMs: 60000, // 10 requests per minute per user
});
export const analyzeScriptWithLimit = onCall(async (request) => {
const userId = request.auth?.uid;
if (!aiLimiter.check(userId)) {
throw new HttpsError('resource-exhausted', 'Rate limit exceeded');
}
return analyzeScriptFlow(request.data);
});Response Schemas
Script Analysis Result
typescript
interface ScriptAnalysisResult {
scenes: {
act: number;
scene: number;
location: string;
description: string;
}[];
characters: {
name: string;
description: string;
}[];
props: {
name: string;
firstAppearance: string;
}[];
}SVG Generation Result
typescript
interface SvgGenerationResult {
svg: string; // Raw SVG markup
}Environment Variables
bash
# Required in Firebase Functions environment
GOOGLE_GENAI_API_KEY=your-gemini-api-keySet secrets using Firebase CLI:
bash
firebase functions:secrets:set GOOGLE_GENAI_API_KEYBarry AI Chat
Overview
The barryChat Cloud Function provides an AI production assistant powered by Gemini with tool-calling. It runs a multi-round conversation loop, executing tools to query project data before synthesizing a natural-language response.
Endpoint
typescript
// Client
const barryChat = httpsCallable<BarryChatRequest, BarryChatResponse>(
functions, 'barryChat'
);Request
typescript
interface BarryChatRequest {
projectId: string;
message: string;
history?: Array<{ role: 'user' | 'model'; text: string }>;
}Response
typescript
interface BarryChatResponse {
response: string; // Gemini's synthesized answer (markdown)
toolsUsed: string[]; // Names of tools invoked (e.g., 'searchFiles', 'getProductionData')
}Configuration
| Setting | Value |
|---|---|
| Region | us-central1 |
| Timeout | 120s |
| Memory | 512 MiB |
| Max tool-call rounds | 5 |
| Auth | Required (Firebase Auth) |
Available Tools
| Tool | Description | Data Source |
|---|---|---|
searchFiles | RAG over uploaded project files (scripts, notes, riders) | Vertex AI Data Store |
getProductionData | Read live production data (structure, cast, props, scheduler, etc.) | Firestore shards |
Files
functions/src/barry-chat.ts— Orchestrator Cloud Functionfunctions/src/barry-tools.ts— Tool execution functionsfunctions/src/barry-datastore.ts— Vertex AI Search Data Store integrationfunctions/src/barry-config.ts— Model and shard configurationfunctions/src/barry-prompts.ts— System prompts and few-shot examples
Last updated: February 2026 (Barry Chat API added)