Spaces:
Sleeping
Sleeping
| """ | |
| Single-scene narration rewrite for the regenerate flow. | |
| When the user's instruction asks to change the spoken text, we rewrite the narration | |
| and then the voiceover is regenerated from the new text. | |
| """ | |
| import dspy | |
| from app.dspy_modules import ensure_dspy_configured | |
| class RewriteNarrationFromInstruction(dspy.Signature): | |
| """ | |
| You are an expert video script editor. The user is editing ONE scene and has given an instruction. | |
| βββ YOUR TASK βββ | |
| - If the user's instruction is about changing the SPOKEN NARRATION (tone, length, rephrase, | |
| add/remove content, make it shorter/longer, more formal/casual, fix a fact, emphasize something): | |
| β Rewrite the narration according to the instruction. Keep the same general meaning and | |
| scene purpose unless the user explicitly asks to change it. Output the new text in updated_narration. | |
| - If the user's instruction is ONLY about VISUAL/LAYOUT (e.g. "use glass image layout", | |
| "add an image", "remove image", "change to cinematic title", "make it more dramatic visually"): | |
| β Return the current_narration UNCHANGED in updated_narration (do not modify the spoken text). | |
| βββ RULES βββ | |
| - Preserve scene_title context: the narration should still fit the scene. | |
| - Output only the narration text in updated_narration β no labels, no quotes, no preamble. | |
| - If unclear whether the user wants narration or visual change, prefer keeping narration unchanged | |
| unless the instruction clearly mentions words like "narration", "script", "say", "text", "rephrase", | |
| "shorter", "longer", "tone", "simplify", "add detail", etc. | |
| """ | |
| scene_title: str = dspy.InputField(desc="Title of this scene (for context)") | |
| current_narration: str = dspy.InputField(desc="Current spoken narration for this scene") | |
| user_instruction: str = dspy.InputField( | |
| desc="The user's edit instruction (e.g. 'make it shorter', 'use glass image', 'rephrase more casually')" | |
| ) | |
| reasoning: str = dspy.OutputField( | |
| desc="One sentence: whether the instruction is about narration (rewrite) or only visual/layout (keep unchanged), and what you did." | |
| ) | |
| updated_narration: str = dspy.OutputField( | |
| desc="The narration text to use: either your rewritten version or the exact current_narration if no narration change was requested. Plain text only, no markdown or quotes." | |
| ) | |
| async def rewrite_narration_if_requested( | |
| current_narration: str, | |
| user_instruction: str, | |
| scene_title: str, | |
| ) -> str: | |
| """ | |
| If the user's instruction asks to change the narration, return a rewritten version. | |
| Otherwise return the current narration unchanged. | |
| On any failure, returns current_narration. | |
| """ | |
| if not (user_instruction and user_instruction.strip()): | |
| return current_narration or "" | |
| if not (current_narration and current_narration.strip()): | |
| return current_narration or "" | |
| ensure_dspy_configured() | |
| predictor = dspy.ChainOfThought(RewriteNarrationFromInstruction) | |
| predictor_async = dspy.asyncify(predictor) | |
| try: | |
| result = await predictor_async( | |
| scene_title=scene_title, | |
| current_narration=current_narration, | |
| user_instruction=user_instruction.strip(), | |
| ) | |
| out = (result.updated_narration or "").strip() | |
| if out: | |
| return out | |
| return current_narration | |
| except Exception: | |
| return current_narration | |