87 lines
3.1 KiB
Python
87 lines
3.1 KiB
Python
|
|
"""CAD-Documenter CLI - Main entry point."""
|
||
|
|
|
||
|
|
import click
|
||
|
|
from pathlib import Path
|
||
|
|
from rich.console import Console
|
||
|
|
|
||
|
|
from .pipeline import DocumentationPipeline
|
||
|
|
|
||
|
|
console = Console()
|
||
|
|
|
||
|
|
|
||
|
|
@click.command()
|
||
|
|
@click.argument("video", type=click.Path(exists=True, path_type=Path))
|
||
|
|
@click.option("-o", "--output", type=click.Path(path_type=Path), help="Output directory")
|
||
|
|
@click.option("--frames-only", is_flag=True, help="Only extract frames, skip documentation")
|
||
|
|
@click.option("--atomizer-hints", is_flag=True, help="Generate Atomizer FEA hints")
|
||
|
|
@click.option("--bom", is_flag=True, help="Generate Bill of Materials")
|
||
|
|
@click.option("--pdf", is_flag=True, help="Generate PDF via Atomaste Report Standard")
|
||
|
|
@click.option("--frame-interval", default=2.0, help="Seconds between frame extractions")
|
||
|
|
@click.option("--whisper-model", default="base", help="Whisper model size (tiny/base/small/medium/large)")
|
||
|
|
@click.version_option()
|
||
|
|
def main(
|
||
|
|
video: Path,
|
||
|
|
output: Path | None,
|
||
|
|
frames_only: bool,
|
||
|
|
atomizer_hints: bool,
|
||
|
|
bom: bool,
|
||
|
|
pdf: bool,
|
||
|
|
frame_interval: float,
|
||
|
|
whisper_model: str,
|
||
|
|
):
|
||
|
|
"""
|
||
|
|
Generate engineering documentation from a CAD walkthrough video.
|
||
|
|
|
||
|
|
VIDEO: Path to the video file (.mp4, .mov, .avi, etc.)
|
||
|
|
"""
|
||
|
|
console.print(f"[bold blue]CAD-Documenter[/bold blue] v0.1.0")
|
||
|
|
console.print(f"Processing: [cyan]{video}[/cyan]")
|
||
|
|
|
||
|
|
# Default output directory
|
||
|
|
if output is None:
|
||
|
|
output = video.parent / f"{video.stem}_docs"
|
||
|
|
|
||
|
|
output.mkdir(parents=True, exist_ok=True)
|
||
|
|
|
||
|
|
# Run pipeline
|
||
|
|
pipeline = DocumentationPipeline(
|
||
|
|
video_path=video,
|
||
|
|
output_dir=output,
|
||
|
|
frame_interval=frame_interval,
|
||
|
|
whisper_model=whisper_model,
|
||
|
|
)
|
||
|
|
|
||
|
|
if frames_only:
|
||
|
|
console.print("[yellow]Extracting frames only...[/yellow]")
|
||
|
|
pipeline.extract_frames()
|
||
|
|
console.print(f"[green]✓[/green] Frames saved to {output / 'frames'}")
|
||
|
|
return
|
||
|
|
|
||
|
|
# Full pipeline
|
||
|
|
console.print("[yellow]Step 1/4:[/yellow] Extracting frames...")
|
||
|
|
frames = pipeline.extract_frames()
|
||
|
|
console.print(f" [green]✓[/green] Extracted {len(frames)} frames")
|
||
|
|
|
||
|
|
console.print("[yellow]Step 2/4:[/yellow] Transcribing audio...")
|
||
|
|
transcript = pipeline.transcribe_audio()
|
||
|
|
console.print(f" [green]✓[/green] Transcribed {len(transcript.segments)} segments")
|
||
|
|
|
||
|
|
console.print("[yellow]Step 3/4:[/yellow] Analyzing components...")
|
||
|
|
analysis = pipeline.analyze_components(frames, transcript)
|
||
|
|
console.print(f" [green]✓[/green] Identified {len(analysis.components)} components")
|
||
|
|
|
||
|
|
console.print("[yellow]Step 4/4:[/yellow] Generating documentation...")
|
||
|
|
doc_path = pipeline.generate_documentation(analysis, atomizer_hints=atomizer_hints, bom=bom)
|
||
|
|
console.print(f" [green]✓[/green] Documentation saved to {doc_path}")
|
||
|
|
|
||
|
|
if pdf:
|
||
|
|
console.print("[yellow]Generating PDF...[/yellow]")
|
||
|
|
pdf_path = pipeline.generate_pdf(doc_path)
|
||
|
|
console.print(f" [green]✓[/green] PDF saved to {pdf_path}")
|
||
|
|
|
||
|
|
console.print(f"\n[bold green]Done![/bold green] Output: {output}")
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
main()
|