chat / agent_system /script_schema.py
rejig-ai's picture
JSON version of video script creation and parsing
2fd7af0
"""
Defines structured JSON schema for video scripts.
"""
from typing import List, Dict, Any, Optional
from pydantic import BaseModel, Field
class VideoScriptSection(BaseModel):
"""
Represents a section of a video script.
"""
section_type: str = Field(..., description="Type of section: hook, key_points, explanation, conclusion, call_to_action")
content: str = Field(..., description="Content text of this section")
display_title: Optional[str] = Field(None, description="Display title for this section (for UI)")
class VideoScript(BaseModel):
"""
Structured schema for video scripts.
"""
title: str = Field(..., description="Title of the video")
target_audience: Optional[str] = Field(None, description="Target audience for this video")
tone: Optional[str] = Field(None, description="Tone of the video: professional, casual, etc.")
sections: List[VideoScriptSection] = Field(..., description="Ordered sections of the script")
call_to_action: Optional[str] = Field(None, description="Call to action for the video")
key_summary_points: Optional[List[str]] = Field(default_factory=list, description="Key summary points")
sources: Optional[List[str]] = Field(default_factory=list, description="Sources used for the script")
fact_check_confirmation: Optional[str] = Field(None, description="Confirmation that facts have been checked")
def get_full_script_text(self) -> str:
"""
Generate the full script text suitable for narration.
Returns:
Combined script text from all sections
"""
return "\n\n".join(section.content for section in self.sections)
def get_formatted_display(self) -> str:
"""
Generate formatted script for display in chat UI.
Returns:
Markdown formatted script for display
"""
result = [f"## 🎬 {self.title}"]
if self.target_audience:
result.append(f"**Target Audience:** {self.target_audience}")
if self.tone:
result.append(f"**Tone:** {self.tone}")
result.append("") # Empty line
# Add each section with its display title
for section in self.sections:
if section.display_title:
emoji = self._get_emoji_for_section(section.section_type)
result.append(f"### {emoji} {section.display_title.upper()}")
# Add content, maintaining paragraph breaks
result.append(section.content)
result.append("") # Empty line
# Add summary points if available
if self.key_summary_points and len(self.key_summary_points) > 0:
result.append("### πŸ“‹ KEY SUMMARY POINTS")
for point in self.key_summary_points:
result.append(f"- {point}")
result.append("")
# Add sources if available
if self.sources and len(self.sources) > 0:
result.append("### πŸ“š SOURCES")
for source in self.sources:
result.append(f"- {source}")
return "\n".join(result)
def _get_emoji_for_section(self, section_type: str) -> str:
"""
Get appropriate emoji for section type.
Args:
section_type: Type of section
Returns:
Emoji character
"""
emoji_map = {
"hook": "🎯",
"key_points": "πŸ“Š",
"explanation": "πŸ’‘",
"detail": "πŸ“‹",
"context": "πŸ”",
"conclusion": "🏁",
"call_to_action": "⚑"
}
return emoji_map.get(section_type, "✨")
def get_legacy_format(self) -> Dict[str, Any]:
"""
Get script in the legacy format for backward compatibility.
Returns:
Dictionary in the original format used by the system
"""
# Extract full script text
script_text = self.get_full_script_text()
# Find call_to_action text
cta_text = self.call_to_action or ""
for section in self.sections:
if section.section_type == "call_to_action":
cta_text = section.content
break
# Build legacy format
return {
"title": self.title,
"script": script_text,
"callToAction": cta_text,
"factCheckConfirmation": self.fact_check_confirmation or "",
"keySummaryPoints": self.key_summary_points or [],
"sources": self.sources or []
}
def convert_legacy_to_script(legacy_data: Dict[str, Any]) -> VideoScript:
"""
Convert legacy script data to VideoScript format.
Args:
legacy_data: Legacy script data dictionary
Returns:
VideoScript object
"""
sections = []
# Extract script content and try to split into logical sections
script_content = legacy_data.get("script", "")
# Try to find a hook (first sentence or paragraph)
hook = ""
remaining_script = script_content
if "." in script_content:
hook_parts = script_content.split(".", 1)
if len(hook_parts) > 0:
hook = hook_parts[0].strip() + "."
remaining_script = hook_parts[1].strip()
# Add hook if found
if hook:
sections.append(
VideoScriptSection(
section_type="hook",
content=hook,
display_title="Hook"
)
)
# Add main content
if remaining_script:
sections.append(
VideoScriptSection(
section_type="explanation",
content=remaining_script,
display_title="Main Content"
)
)
# Add call to action if present
call_to_action = legacy_data.get("callToAction", "")
if call_to_action:
sections.append(
VideoScriptSection(
section_type="call_to_action",
content=call_to_action,
display_title="Call To Action"
)
)
# Create VideoScript object
return VideoScript(
title=legacy_data.get("title", "Video Script"),
sections=sections,
key_summary_points=legacy_data.get("keySummaryPoints", []),
sources=legacy_data.get("sources", []),
call_to_action=call_to_action,
fact_check_confirmation=legacy_data.get("factCheckConfirmation", "")
)