analyze_script
Analyze theatrical scripts to extract lighting cues and generate scene suggestions, enhancing lighting design for LacyLights MCP Server.
Instructions
Analyze a theatrical script to extract lighting-relevant information
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| extractLightingCues | No | Extract specific lighting cues from the script | |
| scriptText | Yes | The theatrical script text to analyze | |
| suggestScenes | No | Generate scene suggestions based on analysis |
Input Schema (JSON Schema)
{
"properties": {
"extractLightingCues": {
"default": true,
"description": "Extract specific lighting cues from the script",
"type": "boolean"
},
"scriptText": {
"description": "The theatrical script text to analyze",
"type": "string"
},
"suggestScenes": {
"default": true,
"description": "Generate scene suggestions based on analysis",
"type": "boolean"
}
},
"required": [
"scriptText"
],
"type": "object"
}
Implementation Reference
- src/tools/scene-tools.ts:300-363 (handler)Main execution logic for the 'analyze_script' tool: parses input using Zod schema, calls RAG service for script analysis, extracts lighting cues if requested, generates scene suggestions if requested, and returns structured analysis.async analyzeScript(args: z.infer<typeof AnalyzeScriptSchema>) { const { scriptText, extractLightingCues, suggestScenes } = AnalyzeScriptSchema.parse(args); try { // Analyze script using RAG service const scriptAnalysis = await this.ragService.analyzeScript(scriptText); const result: GenerateSceneResult = { analysis: scriptAnalysis, totalCues: scriptAnalysis.scenes.length, characters: scriptAnalysis.characters, overallMood: scriptAnalysis.overallMood, themes: scriptAnalysis.themes }; if (extractLightingCues) { // Extract specific lighting cues from the analysis const lightingCues = scriptAnalysis.scenes.flatMap((scene, _index) => scene.lightingCues.map(cue => ({ sceneNumber: scene.sceneNumber, cue, context: scene.content.substring(0, 200) + '...', suggestedTiming: this.suggestCueTiming(cue, scene.mood) })) ); result.lightingCues = lightingCues; result.totalCues = lightingCues.length; } if (suggestScenes) { // Generate scene suggestions based on script analysis const sceneTemplates = await Promise.all( scriptAnalysis.scenes.slice(0, 5).map(async (scene, _index) => { const recommendations = await this.ragService.generateLightingRecommendations( scene.content, scene.mood, ['LED_PAR', 'MOVING_HEAD'] // Default fixture types ); return { sceneNumber: scene.sceneNumber, title: scene.title || `Scene ${scene.sceneNumber}`, mood: scene.mood, timeOfDay: scene.timeOfDay, location: scene.location, suggestedLighting: { colorPalette: recommendations.colorSuggestions, intensity: this.mapIntensityLevel(recommendations.intensityLevels), focusAreas: recommendations.focusAreas, reasoning: recommendations.reasoning }, estimatedFixtureCount: this.estimateFixtureNeeds(recommendations) }; }) ); result.sceneTemplates = sceneTemplates; } return result; } catch (error) { throw new Error(`Failed to analyze script: ${error}`); }
- src/tools/scene-tools.ts:79-83 (schema)Zod schema defining input parameters for the analyze_script tool: scriptText (required), extractLightingCues and suggestScenes (optional booleans with defaults). Used for validation in handler.const AnalyzeScriptSchema = z.object({ scriptText: z.string(), extractLightingCues: z.boolean().default(true), suggestScenes: z.boolean().default(true) });
- src/index.ts:861-884 (registration)Tool registration in ListToolsRequestSchema handler: defines name 'analyze_script', description, and inputSchema matching AnalyzeScriptSchema.name: "analyze_script", description: "Analyze a theatrical script to extract lighting-relevant information", inputSchema: { type: "object", properties: { scriptText: { type: "string", description: "The theatrical script text to analyze", }, extractLightingCues: { type: "boolean", default: true, description: "Extract specific lighting cues from the script", }, suggestScenes: { type: "boolean", default: true, description: "Generate scene suggestions based on analysis", }, }, required: ["scriptText"], }, },
- src/index.ts:2098-2110 (registration)Dispatch handler in CallToolRequestSchema: routes 'analyze_script' calls to sceneTools.analyzeScript method.case "analyze_script": return { content: [ { type: "text", text: JSON.stringify( await this.sceneTools.analyzeScript(args as any), null, 2, ), }, ], };
- Core RAG service method analyzeScript that performs GPT-4 analysis on script text to extract scenes, moods, characters, lighting cues, etc., returning ScriptAnalysis object. Called by the tool handler.async analyzeScript(scriptText: string): Promise<ScriptAnalysis> { const prompt = ` Analyze this theatrical script and extract lighting-relevant information. Return a JSON object with the following structure: { "scenes": [ { "sceneNumber": "string", "title": "string (optional)", "content": "string (excerpt)", "mood": "string (e.g., tense, romantic, mysterious)", "characters": ["string"], "stageDirections": ["string"], "lightingCues": ["string"], "timeOfDay": "string (optional)", "location": "string (optional)" } ], "characters": ["string"], "settings": ["string"], "overallMood": "string", "themes": ["string"] } Script text: ${scriptText} Focus on: - Mood and atmosphere descriptions - Time of day and location changes - Stage directions that imply lighting - Character entrances and emotional beats - Explicit lighting cues in the text `; const response = await this.openai.chat.completions.create({ model: 'gpt-4', messages: [{ role: 'user', content: prompt }], temperature: 0.3 }); const content = response.choices[0].message.content || '{}'; try { return JSON.parse(content); } catch (_error) { // If JSON parsing fails, try to extract JSON from the response const jsonMatch = content.match(/\{[\s\S]*\}/); if (jsonMatch) { try { return JSON.parse(jsonMatch[0]); } catch (_e) { // If still fails, return a fallback structure return { scenes: [], characters: [], settings: [], overallMood: 'unknown', themes: [] }; } } return { scenes: [], characters: [], settings: [], overallMood: 'unknown', themes: [] }; } }