Files
Your Name 33cca5f552 Initial CutScript release - Open-source AI-powered text-based video editor
CutScript is a local-first, Descript-like video editor where you edit video by editing text.
Delete a word from the transcript and it's cut from the video.

Features:
- Word-level transcription with WhisperX
- Text-based video editing with undo/redo
- AI filler word removal (Ollama/OpenAI/Claude)
- AI clip creation for shorts
- Waveform timeline with virtualized transcript
- FFmpeg stream-copy (fast) and re-encode (4K) export
- Caption burn-in and sidecar SRT generation
- Studio Sound audio enhancement (DeepFilterNet)
- Keyboard shortcuts (J/K/L, Space, Delete, Ctrl+Z/S/E)
- Encrypted API key storage
- Project save/load (.aive files)

Architecture:
- Electron + React + Tailwind (frontend)
- FastAPI + Python (backend)
- WhisperX for transcription
- FFmpeg for video processing
- Multi-provider AI support

Performance optimizations:
- RAF-throttled time updates
- Zustand selectors for granular subscriptions
- Dual-canvas waveform rendering
- Virtualized transcript with react-virtuoso

Built on top of DataAnts-AI/VideoTranscriber, completely rewritten as a desktop application.

License: MIT
2026-03-03 06:31:04 -05:00

84 lines
2.4 KiB
Python

"""AI feature endpoints: filler word detection, clip creation, Ollama model listing."""
import logging
from typing import List, Optional
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel
from services.ai_provider import AIProvider, detect_filler_words, create_clip_suggestion
logger = logging.getLogger(__name__)
router = APIRouter()
class WordInfo(BaseModel):
index: int
word: str
start: Optional[float] = None
end: Optional[float] = None
class FillerRequest(BaseModel):
transcript: str
words: List[WordInfo]
provider: str = "ollama"
model: Optional[str] = None
api_key: Optional[str] = None
base_url: Optional[str] = None
custom_filler_words: Optional[str] = None
class ClipRequest(BaseModel):
transcript: str
words: List[WordInfo]
provider: str = "ollama"
model: Optional[str] = None
api_key: Optional[str] = None
base_url: Optional[str] = None
target_duration: int = 60
@router.post("/ai/filler-removal")
async def filler_removal(req: FillerRequest):
try:
words_dicts = [w.model_dump() for w in req.words]
result = detect_filler_words(
transcript=req.transcript,
words=words_dicts,
provider=req.provider,
model=req.model,
api_key=req.api_key,
base_url=req.base_url,
custom_filler_words=req.custom_filler_words,
)
return result
except Exception as e:
logger.error(f"Filler detection failed: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=str(e))
@router.post("/ai/create-clip")
async def create_clip(req: ClipRequest):
try:
words_dicts = [w.model_dump() for w in req.words]
result = create_clip_suggestion(
transcript=req.transcript,
words=words_dicts,
target_duration=req.target_duration,
provider=req.provider,
model=req.model,
api_key=req.api_key,
base_url=req.base_url,
)
return result
except Exception as e:
logger.error(f"Clip creation failed: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=str(e))
@router.get("/ai/ollama-models")
async def ollama_models(base_url: str = "http://localhost:11434"):
models = AIProvider.list_ollama_models(base_url)
return {"models": models}