davidjurgens's picture
Deploy: Potato — Codebook Annotation
aceb1b2 verified
Raw
History Blame Contribute Delete
7.14 kB
"""
Video Layout
Generates a form interface for displaying video content. Features include:
- Custom video player controls
- Autoplay options
- Loop control
- Muting options
- Custom CSS styling
- Multiple video source support
- Fallback content support
"""
import logging
import os.path
from potato.ai.ai_help_wrapper import get_ai_wrapper, get_dynamic_ai_help
from .identifier_utils import (
safe_generate_layout,
escape_html_content,
generate_layout_attributes
)
logger = logging.getLogger(__name__)
def generate_video_layout(annotation_scheme):
"""
Generate HTML for a video player interface.
Args:
annotation_scheme (dict): Configuration including:
- name: Schema identifier
- description: Display description
- video_path: Path to video file
- custom_css (dict): Optional CSS styling
- width: Video width (default: "320")
- height: Video height (default: "240")
- autoplay (bool): Whether to start playing automatically
- loop (bool): Whether to loop video playback
- muted (bool): Whether to mute audio by default
- controls (bool): Whether to show player controls
- fallback_text (str): Optional text to show if video fails
- additional_sources (list): Optional additional video formats
Returns:
tuple: (html_string, key_bindings)
html_string: Complete HTML for the video interface
key_bindings: Empty list (no keyboard shortcuts)
Raises:
ValueError: If video_path is missing or invalid
"""
return safe_generate_layout(annotation_scheme, _generate_video_layout_internal)
def _is_url(path: str) -> bool:
"""
Check if a path is a URL.
Args:
path: The path to check
Returns:
bool: True if path is a URL, False otherwise
"""
return path.startswith(('http://', 'https://', '//', 'data:'))
def _generate_video_layout_internal(annotation_scheme):
"""
Internal function to generate video layout after validation.
"""
logger.debug(f"Generating video layout for schema: {annotation_scheme['name']}")
# Validate video path
if "video_path" not in annotation_scheme:
error_msg = f"Missing video_path in schema: {annotation_scheme['name']}"
logger.error(error_msg)
raise ValueError(error_msg)
video_path = annotation_scheme["video_path"]
# Only check file existence for local paths, not URLs
if not _is_url(video_path) and not os.path.exists(video_path):
# Log a warning but don't fail - the file might be served from a different location
logger.warning(f"Video file not found locally: {video_path}. "
f"Assuming it will be served from a web-accessible location.")
# Get layout attributes for grid positioning
layout_attrs = generate_layout_attributes(annotation_scheme)
# Initialize form wrapper
schematic = f"""
<form id="{escape_html_content(annotation_scheme['name'])}" class="annotation-form video" action="javascript:void(0)" data-annotation-id="{escape_html_content(str(annotation_scheme.get("annotation_id", "")))}" {layout_attrs}>
{get_ai_wrapper()}
<fieldset schema="{escape_html_content(annotation_scheme['name'])}">
<legend>{escape_html_content(annotation_scheme['description'])}</legend>
"""
# Generate video element with attributes
video_attrs = _generate_video_attributes(annotation_scheme)
css = _generate_css_style(annotation_scheme)
schematic += f"""
<video {video_attrs} style="{css}">
{_generate_video_sources(annotation_scheme)}
{_generate_fallback_content(annotation_scheme)}
</video>
"""
schematic += "</fieldset></form>"
logger.info(f"Successfully generated video layout for {annotation_scheme['name']}")
return schematic, []
def _generate_video_attributes(annotation_scheme):
"""
Generate HTML attributes for video element.
Args:
annotation_scheme (dict): Video configuration settings
Returns:
str: Space-separated video attributes
"""
attrs = []
# Handle playback controls
if annotation_scheme.get("controls", True):
attrs.append("controls")
logger.debug("Enabled video controls")
if annotation_scheme.get("autoplay"):
attrs.append("autoplay")
logger.debug("Enabled autoplay")
if annotation_scheme.get("loop"):
attrs.append("loop")
logger.debug("Enabled video loop")
if annotation_scheme.get("muted"):
attrs.append("muted")
logger.debug("Enabled muted playback")
return " ".join(attrs)
def _generate_css_style(annotation_scheme):
"""
Generate CSS style string from configuration.
Args:
annotation_scheme (dict): Configuration containing custom_css settings
Returns:
str: Formatted CSS style string
"""
css = annotation_scheme.get("custom_css", {})
styles = []
# Default dimensions if not specified
width = css.get("width", "320")
height = css.get("height", "240")
styles.append(f"width: {width}px")
styles.append(f"height: {height}px")
return "; ".join(styles)
def _generate_video_sources(annotation_scheme):
"""
Generate source elements for video formats.
Args:
annotation_scheme (dict): Configuration containing video sources
Returns:
str: HTML for video source elements
"""
sources = []
# Add main video source
mime_type = _get_mime_type(annotation_scheme["video_path"])
sources.append(
f'<source src="{escape_html_content(annotation_scheme["video_path"])}" type="{mime_type}">'
)
logger.debug(f"Added primary video source: {annotation_scheme['video_path']}")
# Add additional sources if specified
for source in annotation_scheme.get("additional_sources", []):
mime_type = _get_mime_type(source)
sources.append(f'<source src="{escape_html_content(source)}" type="{mime_type}">')
logger.debug(f"Added additional video source: {source}")
return "\n".join(sources)
def _generate_fallback_content(annotation_scheme):
"""
Generate fallback content for browsers that don't support video.
Args:
annotation_scheme (dict): Configuration containing fallback settings
Returns:
str: HTML for fallback content
"""
fallback = annotation_scheme.get("fallback_text", "Your browser does not support the video tag.")
logger.debug("Added fallback content for video element")
return escape_html_content(fallback)
def _get_mime_type(file_path):
"""
Determine MIME type from video file extension.
Args:
file_path (str): Path to video file
Returns:
str: MIME type string
"""
ext = os.path.splitext(file_path)[1].lower()
mime_types = {
'.mp4': 'video/mp4',
'.webm': 'video/webm',
'.ogg': 'video/ogg'
}
return mime_types.get(ext, 'video/mp4')