diff --git a/.gitignore b/.gitignore index 4876138b7..7b8b2b697 100644 --- a/.gitignore +++ b/.gitignore @@ -138,6 +138,7 @@ htmlcov/ instance/ logs/ node_modules/ +sdks/*/dist/ pnpm-lock.yaml quantomcode_private.pem research/labs/archive/ diff --git a/README.md b/README.md index 52955e5bd..c39e7a680 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,12 @@ PYTHONPATH=src python3 -m uvicorn youtube_extension.main:app --port 8000 cd apps/web && BACKEND_URL=http://localhost:8000 npx next dev --port 3000 ``` +### OpenAPI + SDKs + +- Export the backend schema: `python scripts/export_openapi.py` (writes `openapi/eventrelay.openapi.json`). +- Generate typed SDKs with Stainless: `npm run sdk:generate` (requires `npx stainless`). +- SDK packages live in `sdks/python` and `sdks/typescript` (see `sdks/README.md` for publish steps). + Open http://localhost:3000/dashboard — paste a YouTube URL and watch it process. ## How It Works diff --git a/openapi/eventrelay.openapi.json b/openapi/eventrelay.openapi.json new file mode 100644 index 000000000..69ea8d08b --- /dev/null +++ b/openapi/eventrelay.openapi.json @@ -0,0 +1,4428 @@ +{ + "components": { + "schemas": { + "AgentDispatchRequest": { + "description": "Request to dispatch agents for a set of events.", + "properties": { + "agent_types": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "Specific agent types to dispatch", + "title": "Agent Types" + }, + "events": { + "items": { + "additionalProperties": true, + "type": "object" + }, + "title": "Events", + "type": "array" + }, + "job_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Job Id" + }, + "transcript": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Transcript text \u2014 events will be auto-extracted if events list is empty", + "title": "Transcript" + } + }, + "title": "AgentDispatchRequest", + "type": "object" + }, + "ApiResponse": { + "description": "Standardized API response wrapper used by all endpoints.", + "properties": { + "data": { + "anyOf": [ + {}, + { + "type": "null" + } + ], + "description": "Response payload", + "title": "Data" + }, + "detail": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Additional error detail", + "title": "Detail" + }, + "error": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Error message (when status='error')", + "title": "Error" + }, + "request_id": { + "title": "Request Id", + "type": "string" + }, + "status": { + "description": "'success' or 'error'", + "title": "Status", + "type": "string" + }, + "timestamp": { + "format": "date-time", + "title": "Timestamp", + "type": "string" + } + }, + "required": [ + "status" + ], + "title": "ApiResponse", + "type": "object" + }, + "CacheStats": { + "description": "Response model for cache statistics", + "example": { + "categories": { + "education": { + "count": 15, + "size_mb": 25.3 + }, + "technology": { + "count": 27, + "size_mb": 41.7 + } + }, + "newest_cache": "2024-01-01T14:30:00Z", + "oldest_cache": "2024-01-01T10:00:00Z", + "total_cached_videos": 42, + "total_size_mb": 67.0 + }, + "properties": { + "categories": { + "additionalProperties": true, + "description": "Cache by category", + "title": "Categories", + "type": "object" + }, + "newest_cache": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Newest cache entry timestamp", + "title": "Newest Cache" + }, + "oldest_cache": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Oldest cache entry timestamp", + "title": "Oldest Cache" + }, + "total_cached_videos": { + "description": "Total cached videos", + "title": "Total Cached Videos", + "type": "integer" + }, + "total_size_mb": { + "description": "Total cache size in MB", + "title": "Total Size Mb", + "type": "number" + } + }, + "required": [ + "total_cached_videos", + "categories", + "total_size_mb" + ], + "title": "CacheStats", + "type": "object" + }, + "ChatRequest": { + "description": "Request model for chat endpoint", + "example": { + "context": "tooltip-assistant", + "query": "How can I process a YouTube video?", + "session_id": "user123", + "video_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ" + }, + "properties": { + "context": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "tooltip-assistant", + "description": "Chat context", + "title": "Context" + }, + "history": { + "anyOf": [ + { + "items": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "Chat history", + "title": "History" + }, + "query": { + "description": "User message", + "maxLength": 2000, + "minLength": 1, + "title": "Query", + "type": "string" + }, + "session_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "default", + "description": "Session identifier", + "title": "Session Id" + }, + "video_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Video identifier", + "title": "Video Id" + }, + "video_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Video URL", + "title": "Video Url" + } + }, + "required": [ + "query" + ], + "title": "ChatRequest", + "type": "object" + }, + "ChatResponse": { + "description": "Response model for chat endpoint", + "example": { + "response": "I can help you process YouTube videos for analysis...", + "session_id": "user123", + "status": "success", + "timestamp": "2024-01-01T12:00:00Z" + }, + "properties": { + "response": { + "description": "AI assistant response", + "title": "Response", + "type": "string" + }, + "session_id": { + "description": "Session identifier", + "title": "Session Id", + "type": "string" + }, + "status": { + "description": "Response status", + "title": "Status", + "type": "string" + }, + "timestamp": { + "description": "Response timestamp", + "format": "date-time", + "title": "Timestamp", + "type": "string" + } + }, + "required": [ + "response", + "status", + "session_id", + "timestamp" + ], + "title": "ChatResponse", + "type": "object" + }, + "ErrorResponse": { + "description": "Standard error response model", + "example": { + "detail": "Invalid YouTube URL format", + "error": "Validation error", + "error_type": "validation_error", + "path": "/api/v1/process-video", + "timestamp": "2024-01-01T12:00:00Z" + }, + "properties": { + "detail": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Error details", + "title": "Detail" + }, + "error": { + "description": "Error message", + "title": "Error", + "type": "string" + }, + "error_type": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Error type/category", + "title": "Error Type" + }, + "path": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Request path", + "title": "Path" + }, + "timestamp": { + "description": "Error timestamp", + "format": "date-time", + "title": "Timestamp", + "type": "string" + } + }, + "required": [ + "error", + "timestamp" + ], + "title": "ErrorResponse", + "type": "object" + }, + "EventExtractRequest": { + "description": "Request to extract events from a transcript.", + "properties": { + "job_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Job ID from video processing", + "title": "Job Id" + }, + "transcript": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Raw transcript text", + "title": "Transcript" + }, + "video_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Video Url" + } + }, + "title": "EventExtractRequest", + "type": "object" + }, + "FeedbackRequest": { + "description": "Request model for feedback submission", + "example": { + "comment": "Excellent video analysis results!", + "feedback_type": "quality", + "metadata": { + "source": "web_interface" + }, + "rating": 5, + "user_id": "user123", + "video_id": "jNQXAC9IVRw" + }, + "properties": { + "comment": { + "anyOf": [ + { + "maxLength": 1000, + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Feedback comment", + "title": "Comment" + }, + "feedback_type": { + "description": "Type of feedback", + "title": "Feedback Type", + "type": "string" + }, + "metadata": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "default": {}, + "description": "Additional metadata", + "title": "Metadata" + }, + "rating": { + "anyOf": [ + { + "maximum": 5.0, + "minimum": 1.0, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Rating (1-5)", + "title": "Rating" + }, + "user_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "User identifier", + "title": "User Id" + }, + "video_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Related video ID", + "title": "Video Id" + } + }, + "required": [ + "feedback_type" + ], + "title": "FeedbackRequest", + "type": "object" + }, + "FeedbackResponse": { + "description": "Response model for feedback submission", + "example": { + "feedback_id": "fb123456", + "message": "Thank you for your feedback!", + "status": "ok", + "timestamp": "2024-01-01T12:00:00Z" + }, + "properties": { + "feedback_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Feedback identifier", + "title": "Feedback Id" + }, + "message": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Response message", + "title": "Message" + }, + "status": { + "description": "Submission status", + "title": "Status", + "type": "string" + }, + "timestamp": { + "description": "Submission timestamp", + "format": "date-time", + "title": "Timestamp", + "type": "string" + } + }, + "required": [ + "status", + "timestamp" + ], + "title": "FeedbackResponse", + "type": "object" + }, + "GeminiBatchRequest": { + "description": "Request payload for Gemini batch submission", + "properties": { + "batch_params": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Additional Gemini batch parameters", + "title": "Batch Params" + }, + "model_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Optional model override", + "title": "Model Name" + }, + "poll_interval": { + "anyOf": [ + { + "minimum": 0.1, + "type": "number" + }, + { + "type": "null" + } + ], + "default": 5.0, + "description": "Polling interval when waiting", + "title": "Poll Interval" + }, + "requests": { + "description": "List of generateContent requests", + "items": { + "additionalProperties": true, + "type": "object" + }, + "minItems": 1, + "title": "Requests", + "type": "array" + }, + "timeout": { + "anyOf": [ + { + "minimum": 1.0, + "type": "number" + }, + { + "type": "null" + } + ], + "default": 600.0, + "description": "Maximum wait time in seconds", + "title": "Timeout" + }, + "wait": { + "default": false, + "description": "Wait for completion before returning", + "title": "Wait", + "type": "boolean" + } + }, + "required": [ + "requests" + ], + "title": "GeminiBatchRequest", + "type": "object" + }, + "GeminiBatchResponse": { + "description": "Response payload for Gemini batch submission", + "properties": { + "completed": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Completed" + }, + "error": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Error" + }, + "latency": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Latency" + }, + "operation": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Operation" + }, + "result": { + "anyOf": [ + {}, + { + "type": "null" + } + ], + "title": "Result" + }, + "success": { + "title": "Success", + "type": "boolean" + } + }, + "required": [ + "success" + ], + "title": "GeminiBatchResponse", + "type": "object" + }, + "GeminiCacheRequest": { + "description": "Request payload for Gemini cache creation", + "properties": { + "contents": { + "anyOf": [ + { + "type": "string" + }, + { + "additionalProperties": true, + "type": "object" + }, + { + "items": {}, + "type": "array" + } + ], + "description": "Prompt or content payload to cache", + "title": "Contents" + }, + "display_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Friendly name for the cache entry", + "title": "Display Name" + }, + "generation_params": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Additional Gemini parameters", + "title": "Generation Params" + }, + "model_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Specific model to use for caching", + "title": "Model Name" + }, + "ttl_seconds": { + "default": 3600, + "description": "Cache time-to-live in seconds", + "minimum": 60.0, + "title": "Ttl Seconds", + "type": "integer" + } + }, + "required": [ + "contents" + ], + "title": "GeminiCacheRequest", + "type": "object" + }, + "GeminiCacheResponse": { + "description": "Response payload for Gemini cache creation", + "properties": { + "cache": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Cache" + }, + "error": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Error" + }, + "latency": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Latency" + }, + "success": { + "title": "Success", + "type": "boolean" + } + }, + "required": [ + "success" + ], + "title": "GeminiCacheResponse", + "type": "object" + }, + "GeminiTokenRequest": { + "description": "Request payload for Gemini ephemeral token creation", + "properties": { + "audience": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Audience claim for the token", + "title": "Audience" + }, + "model_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Model alias to scope the token", + "title": "Model Name" + }, + "token_params": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Additional token parameters", + "title": "Token Params" + }, + "ttl_seconds": { + "anyOf": [ + { + "minimum": 60.0, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Token time-to-live in seconds", + "title": "Ttl Seconds" + } + }, + "title": "GeminiTokenRequest", + "type": "object" + }, + "GeminiTokenResponse": { + "description": "Response payload for Gemini ephemeral token creation", + "properties": { + "error": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Error" + }, + "latency": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Latency" + }, + "success": { + "title": "Success", + "type": "boolean" + }, + "token": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Token" + } + }, + "required": [ + "success" + ], + "title": "GeminiTokenResponse", + "type": "object" + }, + "HTTPValidationError": { + "properties": { + "detail": { + "items": { + "$ref": "#/components/schemas/ValidationError" + }, + "title": "Detail", + "type": "array" + } + }, + "title": "HTTPValidationError", + "type": "object" + }, + "HealthResponse": { + "description": "Response model for health checks", + "example": { + "components": { + "cache": "healthy", + "video_processor": "available" + }, + "status": "healthy", + "timestamp": "2024-01-01T12:00:00Z", + "version": "2.0.0" + }, + "properties": { + "components": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "default": {}, + "description": "Component health details", + "title": "Components" + }, + "status": { + "description": "Overall health status", + "title": "Status", + "type": "string" + }, + "timestamp": { + "description": "Health check timestamp", + "format": "date-time", + "title": "Timestamp", + "type": "string" + }, + "version": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "API version", + "title": "Version" + } + }, + "required": [ + "status", + "timestamp" + ], + "title": "HealthResponse", + "type": "object" + }, + "MCPRequest": { + "properties": { + "method": { + "title": "Method", + "type": "string" + }, + "params": { + "additionalProperties": true, + "title": "Params", + "type": "object" + } + }, + "required": [ + "method", + "params" + ], + "title": "MCPRequest", + "type": "object" + }, + "MarkdownRequest": { + "description": "Request model for markdown processing", + "example": { + "force_regenerate": false, + "video_url": "https://www.youtube.com/watch?v=jNQXAC9IVRw" + }, + "properties": { + "force_regenerate": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": false, + "description": "Force cache regeneration", + "title": "Force Regenerate" + }, + "video_url": { + "description": "YouTube video URL", + "title": "Video Url", + "type": "string" + } + }, + "required": [ + "video_url" + ], + "title": "MarkdownRequest", + "type": "object" + }, + "MarkdownResponse": { + "description": "Response model for markdown processing", + "example": { + "cached": false, + "markdown_content": "# Sample Video Analysis\n\n...", + "metadata": { + "duration": "3:32", + "title": "Sample Video" + }, + "processing_time": "15.3s", + "save_path": "/path/to/analysis.md", + "status": "success", + "video_id": "jNQXAC9IVRw", + "video_url": "https://www.youtube.com/watch?v=jNQXAC9IVRw" + }, + "properties": { + "cached": { + "description": "Whether result was cached", + "title": "Cached", + "type": "boolean" + }, + "markdown_content": { + "description": "Generated markdown content", + "title": "Markdown Content", + "type": "string" + }, + "metadata": { + "additionalProperties": true, + "description": "Video metadata", + "title": "Metadata", + "type": "object" + }, + "processing_time": { + "description": "Processing duration", + "title": "Processing Time", + "type": "string" + }, + "save_path": { + "description": "File save path", + "title": "Save Path", + "type": "string" + }, + "status": { + "description": "Processing status", + "title": "Status", + "type": "string" + }, + "video_id": { + "description": "YouTube video ID", + "title": "Video Id", + "type": "string" + }, + "video_url": { + "description": "Original video URL", + "title": "Video Url", + "type": "string" + } + }, + "required": [ + "video_id", + "video_url", + "metadata", + "markdown_content", + "cached", + "save_path", + "processing_time", + "status" + ], + "title": "MarkdownResponse", + "type": "object" + }, + "TranscriptActionRequest": { + "description": "Request model for transcript-to-action workflow", + "properties": { + "language": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "en", + "description": "Preferred transcript language", + "title": "Language" + }, + "transcript_text": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Optional pre-fetched transcript text", + "title": "Transcript Text" + }, + "video_options": { + "anyOf": [ + { + "$ref": "#/components/schemas/VideoClipOptions" + }, + { + "type": "null" + } + ], + "description": "Optional Gemini video metadata controls (clip window, fps, resolution)" + }, + "video_url": { + "description": "YouTube video URL", + "title": "Video Url", + "type": "string" + } + }, + "required": [ + "video_url" + ], + "title": "TranscriptActionRequest", + "type": "object" + }, + "TranscriptActionResponse": { + "description": "Response model for transcript-to-action workflow", + "properties": { + "errors": { + "items": { + "type": "string" + }, + "title": "Errors", + "type": "array" + }, + "metadata": { + "additionalProperties": true, + "title": "Metadata", + "type": "object" + }, + "orchestration_meta": { + "additionalProperties": true, + "title": "Orchestration Meta", + "type": "object" + }, + "outputs": { + "additionalProperties": true, + "title": "Outputs", + "type": "object" + }, + "success": { + "title": "Success", + "type": "boolean" + }, + "transcript": { + "additionalProperties": true, + "title": "Transcript", + "type": "object" + }, + "video_url": { + "title": "Video Url", + "type": "string" + } + }, + "required": [ + "success", + "video_url", + "metadata", + "transcript", + "outputs", + "orchestration_meta" + ], + "title": "TranscriptActionResponse", + "type": "object" + }, + "ValidationError": { + "properties": { + "ctx": { + "title": "Context", + "type": "object" + }, + "input": { + "title": "Input" + }, + "loc": { + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "integer" + } + ] + }, + "title": "Location", + "type": "array" + }, + "msg": { + "title": "Message", + "type": "string" + }, + "type": { + "title": "Error Type", + "type": "string" + } + }, + "required": [ + "loc", + "msg", + "type" + ], + "title": "ValidationError", + "type": "object" + }, + "VideoClipOptions": { + "description": "Optional video clipping and sampling controls for Gemini processing.", + "properties": { + "end_seconds": { + "anyOf": [ + { + "exclusiveMinimum": 0.0, + "type": "number" + }, + { + "type": "null" + } + ], + "description": "End offset (seconds); must be greater than start_seconds when provided", + "title": "End Seconds" + }, + "fps": { + "anyOf": [ + { + "exclusiveMinimum": 0.0, + "maximum": 30.0, + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Sampling rate for Gemini video frames; defaults to API standard when omitted", + "title": "Fps" + }, + "start_seconds": { + "anyOf": [ + { + "minimum": 0.0, + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Start offset (seconds) when requesting Gemini video processing", + "title": "Start Seconds" + } + }, + "title": "VideoClipOptions", + "type": "object" + }, + "VideoProcessJobRequest": { + "description": "Request to start async video processing.", + "properties": { + "language": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "en", + "description": "Transcript language", + "title": "Language" + }, + "options": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Options" + }, + "video_url": { + "description": "YouTube video URL", + "title": "Video Url", + "type": "string" + } + }, + "required": [ + "video_url" + ], + "title": "VideoProcessJobRequest", + "type": "object" + }, + "VideoProcessingRequest": { + "description": "Request model for video processing", + "example": { + "options": { + "include_transcript": true, + "quality": "high" + }, + "video_url": "https://www.youtube.com/watch?v=jNQXAC9IVRw" + }, + "properties": { + "options": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "default": {}, + "description": "Processing options", + "title": "Options" + }, + "video_url": { + "description": "YouTube video URL", + "title": "Video Url", + "type": "string" + } + }, + "required": [ + "video_url" + ], + "title": "VideoProcessingRequest", + "type": "object" + }, + "VideoToSoftwareRequest": { + "description": "Request model for video-to-software conversion", + "example": { + "deployment_target": "vercel", + "features": [ + "responsive_design", + "dark_mode" + ], + "project_type": "web", + "video_url": "https://www.youtube.com/watch?v=bMknfKXIFA8" + }, + "properties": { + "deployment_target": { + "default": "vercel", + "description": "Deployment platform", + "title": "Deployment Target", + "type": "string" + }, + "features": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": [], + "description": "Additional features to implement", + "title": "Features" + }, + "project_type": { + "default": "web", + "description": "Project type (web, api, ml, mobile)", + "title": "Project Type", + "type": "string" + }, + "url": { + "description": "YouTube video URL", + "title": "Url", + "type": "string" + } + }, + "required": [ + "url" + ], + "title": "VideoToSoftwareRequest", + "type": "object" + }, + "VideoToSoftwareResponse": { + "description": "Response model for video-to-software conversion", + "example": { + "build_status": "completed", + "code_generation": { + "framework": "React" + }, + "deployment": { + "status": "success" + }, + "deployment_target": "vercel", + "features_implemented": [ + "responsive_design", + "dark_mode" + ], + "github_repo": "https://github.com/user/sample-video-app", + "live_url": "https://sample-video-app.vercel.app", + "processing_time": "45.2s", + "project_name": "sample-video-app", + "project_type": "web", + "status": "success", + "timestamp": "2024-01-01T12:00:00Z", + "video_analysis": { + "status": "success" + }, + "video_url": "https://www.youtube.com/watch?v=bMknfKXIFA8" + }, + "properties": { + "build_status": { + "description": "Build status", + "title": "Build Status", + "type": "string" + }, + "code_generation": { + "additionalProperties": true, + "description": "Code generation details", + "title": "Code Generation", + "type": "object" + }, + "deployment": { + "additionalProperties": true, + "description": "Deployment information", + "title": "Deployment", + "type": "object" + }, + "deployment_target": { + "description": "Deployment target", + "title": "Deployment Target", + "type": "string" + }, + "features_implemented": { + "description": "Implemented features", + "items": { + "type": "string" + }, + "title": "Features Implemented", + "type": "array" + }, + "github_repo": { + "description": "GitHub repository URL", + "title": "Github Repo", + "type": "string" + }, + "live_url": { + "description": "Live deployment URL", + "title": "Live Url", + "type": "string" + }, + "processing_time": { + "description": "Total processing time", + "title": "Processing Time", + "type": "string" + }, + "project_name": { + "description": "Generated project name", + "title": "Project Name", + "type": "string" + }, + "project_type": { + "description": "Project type", + "title": "Project Type", + "type": "string" + }, + "status": { + "description": "Overall status", + "title": "Status", + "type": "string" + }, + "timestamp": { + "description": "Completion timestamp", + "format": "date-time", + "title": "Timestamp", + "type": "string" + }, + "video_analysis": { + "additionalProperties": true, + "description": "Video analysis results", + "title": "Video Analysis", + "type": "object" + }, + "video_url": { + "description": "Original video URL", + "title": "Video Url", + "type": "string" + } + }, + "required": [ + "video_url", + "project_name", + "project_type", + "deployment_target", + "live_url", + "github_repo", + "build_status", + "processing_time", + "features_implemented", + "video_analysis", + "code_generation", + "deployment", + "status", + "timestamp" + ], + "title": "VideoToSoftwareResponse", + "type": "object" + } + }, + "securitySchemes": { + "ApiKeyAuth": { + "in": "header", + "name": "X-API-Key", + "type": "apiKey" + } + } + }, + "info": { + "description": "\n ## UVAI Platform API\n\n **Architecture Features:**\n - \ud83c\udfd7\ufe0f **Service-Oriented Architecture** with dependency injection\n - \ud83d\udccb **API Versioning** for backward compatibility\n - \ud83d\udd04 **Real-time WebSocket** communication\n - \ud83d\udcca **Comprehensive Monitoring** and health checks\n - \ud83d\ude80 **Production-ready** with proper error handling\n\n **Core Capabilities:**\n - **Video Processing**: AI-powered analysis of YouTube videos\n - **Markdown Generation**: Automated learning guides and summaries\n - **Video-to-Software**: Convert videos into deployable applications\n - **Caching System**: Intelligent caching for improved performance\n - **Real-time Communication**: WebSocket support for live updates\n\n **API Versions:**\n - **v1**: Current stable API with all core features\n - **Legacy**: Backward compatibility with original endpoints\n\n **MCP Integration:**\n - Multi-modal Content Processing with agent orchestration\n - Support for multiple LLM providers (Gemini, Claude, GPT-4)\n - Real-time video analysis and action generation\n ", + "title": "YouTube Extension API", + "version": "2.0.0", + "x-logo": { + "url": "https://uvai.io/logo.png" + } + }, + "openapi": "3.1.0", + "paths": { + "/api/cache/stats": { + "get": { + "description": "Legacy cache stats endpoint", + "operationId": "legacy_cache_stats_api_cache_stats_get", + "responses": { + "200": { + "content": { + "application/json": { + "schema": {} + } + }, + "description": "Successful Response" + } + }, + "summary": "Legacy Cache Stats" + } + }, + "/api/cache/{video_id}": { + "delete": { + "description": "Legacy cache clearing endpoint", + "operationId": "legacy_clear_video_cache_api_cache__video_id__delete", + "parameters": [ + { + "in": "path", + "name": "video_id", + "required": true, + "schema": { + "title": "Video Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": {} + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Legacy Clear Video Cache" + } + }, + "/api/chat": { + "post": { + "description": "Legacy chat endpoint - redirects to v1 with data preservation", + "operationId": "legacy_chat_api_chat_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "additionalProperties": true, + "title": "Request", + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": {} + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Legacy Chat" + } + }, + "/api/process-video": { + "post": { + "description": "Legacy video processing endpoint", + "operationId": "legacy_process_video_api_process_video_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "additionalProperties": true, + "title": "Request", + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": {} + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Legacy Process Video" + } + }, + "/api/process-video-markdown": { + "post": { + "description": "Legacy markdown processing endpoint", + "operationId": "legacy_process_video_markdown_api_process_video_markdown_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "additionalProperties": true, + "title": "Request", + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": {} + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Legacy Process Video Markdown" + } + }, + "/api/v1/actions/{action_id}": { + "put": { + "description": "Update action completion status or metadata", + "operationId": "update_action_v1_api_v1_actions__action_id__put", + "parameters": [ + { + "in": "path", + "name": "action_id", + "required": true, + "schema": { + "title": "Action Id", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "additionalProperties": true, + "title": "Payload", + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": {} + } + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Update action status", + "tags": [ + "API v1" + ] + } + }, + "/api/v1/actions/{video_id}": { + "get": { + "description": "Retrieve actions generated for a specific processed video", + "operationId": "get_actions_by_video_v1_api_v1_actions__video_id__get", + "parameters": [ + { + "in": "path", + "name": "video_id", + "required": true, + "schema": { + "title": "Video Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": {} + } + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "List actions for a video", + "tags": [ + "API v1" + ] + } + }, + "/api/v1/agents/a2a/log": { + "get": { + "description": "Return recent A2A inter-agent messages.", + "operationId": "get_a2a_log_api_v1_agents_a2a_log_get", + "parameters": [ + { + "in": "query", + "name": "conversation_id", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Conversation Id" + } + }, + { + "in": "query", + "name": "limit", + "required": false, + "schema": { + "default": 50, + "title": "Limit", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Get A2A message log", + "tags": [ + "API v1", + "Agents" + ] + } + }, + "/api/v1/agents/a2a/send": { + "post": { + "description": "Send a context-share or tool-request message between agents.", + "operationId": "send_a2a_message_api_v1_agents_a2a_send_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "additionalProperties": true, + "default": {}, + "title": "Body", + "type": "object" + } + } + } + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Send an A2A message between agents", + "tags": [ + "API v1", + "Agents" + ] + } + }, + "/api/v1/agents/dispatch": { + "post": { + "description": "Dispatch specialist agents to act on extracted events.", + "operationId": "dispatch_agents_api_v1_agents_dispatch_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentDispatchRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Dispatch agents for extracted events", + "tags": [ + "API v1", + "Agents" + ] + } + }, + "/api/v1/agents/{agent_id}/status": { + "get": { + "description": "Return the current status of an agent execution.", + "operationId": "get_agent_status_api_v1_agents__agent_id__status_get", + "parameters": [ + { + "in": "path", + "name": "agent_id", + "required": true, + "schema": { + "title": "Agent Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Get agent execution status", + "tags": [ + "API v1", + "Agents" + ] + } + }, + "/api/v1/cache": { + "delete": { + "description": "Clear all cached video processing results", + "operationId": "clear_all_cache_v1_api_v1_cache_delete", + "responses": { + "200": { + "content": { + "application/json": { + "schema": {} + } + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Clear All Cache", + "tags": [ + "API v1" + ] + } + }, + "/api/v1/cache/stats": { + "get": { + "description": "Get comprehensive statistics about cached video processing results", + "operationId": "get_cache_stats_v1_api_v1_cache_stats_get", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CacheStats" + } + } + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Get Cache Statistics", + "tags": [ + "API v1" + ] + } + }, + "/api/v1/cache/{video_id}": { + "delete": { + "description": "Clear cached results for a specific video", + "operationId": "clear_video_cache_v1_api_v1_cache__video_id__delete", + "parameters": [ + { + "in": "path", + "name": "video_id", + "required": true, + "schema": { + "title": "Video Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": {} + } + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Clear Video Cache", + "tags": [ + "API v1" + ] + }, + "get": { + "description": "Retrieve cached analysis for a specific video by ID", + "operationId": "get_cached_video_v1_api_v1_cache__video_id__get", + "parameters": [ + { + "in": "path", + "name": "video_id", + "required": true, + "schema": { + "title": "Video Id", + "type": "string" + } + }, + { + "in": "query", + "name": "format", + "required": false, + "schema": { + "default": "markdown", + "title": "Format", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": {} + } + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Get Cached Video Analysis", + "tags": [ + "API v1" + ] + } + }, + "/api/v1/capabilities": { + "get": { + "description": "Report availability info for video processing models", + "operationId": "get_capabilities_v1_api_v1_capabilities_get", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "additionalProperties": true, + "title": "Response Get Capabilities V1 Api V1 Capabilities Get", + "type": "object" + } + } + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Model capabilities status", + "tags": [ + "API v1" + ] + } + }, + "/api/v1/chat": { + "post": { + "description": "Send a message to the AI assistant for help with video processing", + "operationId": "chat_v1_api_v1_chat_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChatRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChatResponse" + } + } + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Chat with AI Assistant", + "tags": [ + "API v1" + ] + } + }, + "/api/v1/events/extract": { + "post": { + "description": "Extract actionable events from a transcript or completed job.", + "operationId": "extract_events_api_v1_events_extract_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventExtractRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Extract events from transcript", + "tags": [ + "API v1", + "Events" + ] + } + }, + "/api/v1/feedback": { + "post": { + "description": "Submit feedback about video processing results or the service", + "operationId": "submit_feedback_v1_api_v1_feedback_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FeedbackRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FeedbackResponse" + } + } + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Submit Feedback", + "tags": [ + "API v1" + ] + } + }, + "/api/v1/health": { + "get": { + "description": "Get basic health status of the API and its components", + "operationId": "health_check_v1_api_v1_health_get", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HealthResponse" + } + } + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Health Check", + "tags": [ + "API v1" + ] + } + }, + "/api/v1/health/detailed": { + "get": { + "description": "Get comprehensive health status including external connectors", + "operationId": "detailed_health_check_v1_api_v1_health_detailed_get", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "additionalProperties": true, + "title": "Response Detailed Health Check V1 Api V1 Health Detailed Get", + "type": "object" + } + } + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Detailed Health Check", + "tags": [ + "API v1" + ] + } + }, + "/api/v1/hybrid/batch": { + "post": { + "description": "Submit a batch generateContent request and optionally wait for completion.", + "operationId": "submit_gemini_batch_api_v1_hybrid_batch_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GeminiBatchRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GeminiBatchResponse" + } + } + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Submit Gemini batch job", + "tags": [ + "API v1" + ] + } + }, + "/api/v1/hybrid/cache": { + "post": { + "description": "Create a reusable Gemini cache entry via the hybrid processor.", + "operationId": "create_gemini_cache_api_v1_hybrid_cache_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GeminiCacheRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GeminiCacheResponse" + } + } + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Create Gemini cache session", + "tags": [ + "API v1" + ] + } + }, + "/api/v1/hybrid/ephemeral-token": { + "post": { + "description": "Generate a short-lived token suitable for client-side uploads.", + "operationId": "create_ephemeral_token_api_v1_hybrid_ephemeral_token_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GeminiTokenRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GeminiTokenResponse" + } + } + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Create Gemini ephemeral token", + "tags": [ + "API v1" + ] + } + }, + "/api/v1/learning-log": { + "get": { + "description": "Get learning log entries from processed videos", + "operationId": "get_learning_log_v1_api_v1_learning_log_get", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "additionalProperties": true, + "type": "object" + }, + "title": "Response Get Learning Log V1 Api V1 Learning Log Get", + "type": "array" + } + } + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Get Learning Log", + "tags": [ + "API v1" + ] + } + }, + "/api/v1/metrics": { + "get": { + "description": "Get system metrics in Prometheus format", + "operationId": "get_metrics_v1_api_v1_metrics_get", + "responses": { + "200": { + "content": { + "application/json": { + "schema": {} + }, + "text/plain": {} + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Get Metrics", + "tags": [ + "API v1" + ] + } + }, + "/api/v1/performance/alert": { + "post": { + "operationId": "ingest_performance_alert_v1_api_v1_performance_alert_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "additionalProperties": true, + "title": "Payload", + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": {} + } + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Ingest frontend performance alert", + "tags": [ + "API v1" + ] + } + }, + "/api/v1/performance/report": { + "post": { + "operationId": "ingest_performance_report_v1_api_v1_performance_report_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "additionalProperties": true, + "title": "Report", + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": {} + } + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Ingest frontend performance report", + "tags": [ + "API v1" + ] + } + }, + "/api/v1/process-video": { + "post": { + "description": "Process a YouTube video and extract information", + "operationId": "process_video_v1_api_v1_process_video_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VideoProcessingRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": {} + } + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Process Video", + "tags": [ + "API v1" + ] + } + }, + "/api/v1/process-video-markdown": { + "post": { + "description": "Process a YouTube video and generate markdown analysis with caching", + "operationId": "process_video_markdown_v1_api_v1_process_video_markdown_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MarkdownRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MarkdownResponse" + } + } + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Process Video to Markdown", + "tags": [ + "API v1" + ] + } + }, + "/api/v1/transcript-action": { + "post": { + "description": "Runs the transcript-to-action workflow, producing summaries, project scaffolds, and task boards.", + "operationId": "run_transcript_action_api_v1_transcript_action_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TranscriptActionRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TranscriptActionResponse" + } + } + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Extract transcript and produce deployable action plan", + "tags": [ + "API v1" + ] + } + }, + "/api/v1/video-to-software": { + "post": { + "description": "Process a YouTube video and generate deployable software application", + "operationId": "video_to_software_v1_api_v1_video_to_software_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VideoToSoftwareRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VideoToSoftwareResponse" + } + } + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Convert Video to Software", + "tags": [ + "API v1" + ] + } + }, + "/api/v1/videos": { + "get": { + "description": "Get summary list of all processed videos", + "operationId": "list_videos_v1_api_v1_videos_get", + "parameters": [ + { + "in": "query", + "name": "limit", + "required": false, + "schema": { + "default": 50, + "title": "Limit", + "type": "integer" + } + }, + { + "in": "query", + "name": "offset", + "required": false, + "schema": { + "default": 0, + "title": "Offset", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "additionalProperties": true, + "title": "Response List Videos V1 Api V1 Videos Get", + "type": "object" + } + } + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "List Processed Videos", + "tags": [ + "API v1" + ] + } + }, + "/api/v1/videos/process": { + "post": { + "description": "Create a background video-processing job and return immediately.", + "operationId": "start_video_processing_api_v1_videos_process_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VideoProcessJobRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Start async video processing", + "tags": [ + "API v1", + "Videos" + ] + } + }, + "/api/v1/videos/{job_id}/status": { + "get": { + "description": "Return the current status of a video-processing job.", + "operationId": "get_video_job_status_api_v1_videos__job_id__status_get", + "parameters": [ + { + "in": "path", + "name": "job_id", + "required": true, + "schema": { + "title": "Job Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Poll video processing status", + "tags": [ + "API v1", + "Videos" + ] + } + }, + "/api/v1/videos/{video_id}": { + "get": { + "description": "Get detailed information for a specific processed video", + "operationId": "get_video_detail_v1_api_v1_videos__video_id__get", + "parameters": [ + { + "in": "path", + "name": "video_id", + "required": true, + "schema": { + "title": "Video Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": {} + } + }, + "description": "Successful Response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad Request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Not Found" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Validation Error" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Rate Limited" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Get Video Details", + "tags": [ + "API v1" + ] + } + }, + "/connectors/health": { + "get": { + "description": "Legacy connector health endpoint", + "operationId": "legacy_connectors_health_connectors_health_get", + "responses": { + "200": { + "content": { + "application/json": { + "schema": {} + } + }, + "description": "Successful Response" + } + }, + "summary": "Legacy Connectors Health" + } + }, + "/health": { + "get": { + "description": "Legacy health endpoint - redirects to v1", + "operationId": "legacy_health_health_get", + "responses": { + "200": { + "content": { + "application/json": { + "schema": {} + } + }, + "description": "Successful Response" + } + }, + "summary": "Legacy Health" + } + }, + "/mcp": { + "post": { + "description": "Bridge endpoint to translate Frontend MCP JSON-RPC calls.\nMOCK IMPLEMENTATION to verify integration contract without heavy ML dependencies.", + "operationId": "handle_mcp_request_mcp_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MCPRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": {} + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Handle Mcp Request" + } + }, + "/metrics": { + "get": { + "description": "Legacy metrics endpoint", + "operationId": "legacy_metrics_metrics_get", + "responses": { + "200": { + "content": { + "application/json": { + "schema": {} + } + }, + "description": "Successful Response" + } + }, + "summary": "Legacy Metrics" + } + }, + "/system/info": { + "get": { + "description": "Get comprehensive system information", + "operationId": "system_info_system_info_get", + "responses": { + "200": { + "content": { + "application/json": { + "schema": {} + } + }, + "description": "Successful Response" + } + }, + "summary": "System Info" + } + } + }, + "servers": [ + { + "description": "Development server", + "url": "http://localhost:8000" + }, + { + "description": "Production server", + "url": "https://api.uvai.io" + } + ], + "tags": [ + { + "description": "Version 1 of the API - current stable release", + "name": "API v1" + }, + { + "description": "Health check and monitoring endpoints", + "name": "Health" + }, + { + "description": "Core video processing and analysis endpoints", + "name": "Video Processing" + }, + { + "description": "Cache control and statistics endpoints", + "name": "Cache Management" + }, + { + "description": "Data retrieval and analytics endpoints", + "name": "Data & Analytics" + } + ] +} \ No newline at end of file diff --git a/package.json b/package.json index fd68f1866..0f67a447d 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,9 @@ "test": "turbo run test", "build:web": "cd apps/web && npm run build", "dev:web": "cd apps/web && npm run dev", - "install:all": "npm install" + "install:all": "npm install", + "sdk:openapi": "python scripts/export_openapi.py", + "sdk:generate": "npm run sdk:openapi && npx stainless generate --config stainless.config.ts" }, "workspaces": [ "apps/*", diff --git a/scripts/export_openapi.py b/scripts/export_openapi.py new file mode 100644 index 000000000..9f4f533fa --- /dev/null +++ b/scripts/export_openapi.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 +"""Export the FastAPI OpenAPI schema to a file for SDK generation.""" + +from __future__ import annotations + +import argparse +import json +import sys +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parents[1] +SRC_PATH = REPO_ROOT / "src" +for path in (REPO_ROOT, SRC_PATH): + if str(path) not in sys.path: + sys.path.insert(0, str(path)) + +from youtube_extension.backend.main import app + + +def export_openapi(output: Path) -> dict: + """Generate the OpenAPI schema and write it to *output*.""" + schema = app.openapi() + output.parent.mkdir(parents=True, exist_ok=True) + with output.open("w", encoding="utf-8") as fp: + json.dump(schema, fp, indent=2, sort_keys=True) + return schema + + +def main() -> None: + parser = argparse.ArgumentParser( + description="Export the EventRelay FastAPI OpenAPI schema." + ) + parser.add_argument( + "--output", + type=Path, + default=Path("openapi/eventrelay.openapi.json"), + help="Path to write the schema JSON (default: %(default)s)", + ) + args = parser.parse_args() + schema = export_openapi(args.output) + print(f"Wrote OpenAPI schema with {len(schema.get('paths', {}))} paths to {args.output}") + + +if __name__ == "__main__": + main() diff --git a/sdks/README.md b/sdks/README.md new file mode 100644 index 000000000..908bcff36 --- /dev/null +++ b/sdks/README.md @@ -0,0 +1,20 @@ +# EventRelay SDKs + +This folder contains multi-language SDKs generated from the EventRelay FastAPI OpenAPI schema. + +- `openapi/eventrelay.openapi.json` is produced via `python scripts/export_openapi.py`. +- `stainless.config.ts` wires the OpenAPI spec into Stainless for SDK generation. +- `sdks/typescript` provides a TypeScript client package. +- `sdks/python` provides a Python client package. + +## Generate with Stainless + +```bash +python scripts/export_openapi.py +npx stainless generate --config stainless.config.ts +``` + +## Publish + +- **Python**: `cd sdks/python && python -m build && twine upload dist/*` +- **TypeScript**: `cd sdks/typescript && npm run build && npm publish` diff --git a/sdks/python/README.md b/sdks/python/README.md new file mode 100644 index 000000000..c300ade85 --- /dev/null +++ b/sdks/python/README.md @@ -0,0 +1,29 @@ +# EventRelay Python SDK + +Typed Python client for the EventRelay API. Generated from the FastAPI OpenAPI schema and aligned with Stainless configuration. + +## Installation + +```bash +pip install . +``` + +## Usage + +```python +from eventrelay_sdk.client import EventRelayClient, TranscriptActionRequest + +client = EventRelayClient(base_url="https://api.eventrelay.io", api_key="your-key") + +health = client.health() +result = client.transcript_action( + TranscriptActionRequest(video_url="https://youtu.be/auJzb1D-fag") +) +``` + +## Regenerate with Stainless + +```bash +python ../../scripts/export_openapi.py +npx stainless generate --config ../../stainless.config.ts +``` diff --git a/sdks/python/eventrelay_sdk/__init__.py b/sdks/python/eventrelay_sdk/__init__.py new file mode 100644 index 000000000..acd57baf2 --- /dev/null +++ b/sdks/python/eventrelay_sdk/__init__.py @@ -0,0 +1,21 @@ +from .client import EventRelayClient +from .models import ( + HealthResponse, + TranscriptActionRequest, + TranscriptActionResponse, + VideoProcessingRequest, + VideoProcessingResponse, + VideoToSoftwareRequest, + VideoToSoftwareResponse, +) + +__all__ = [ + "EventRelayClient", + "HealthResponse", + "TranscriptActionRequest", + "TranscriptActionResponse", + "VideoProcessingRequest", + "VideoProcessingResponse", + "VideoToSoftwareRequest", + "VideoToSoftwareResponse", +] diff --git a/sdks/python/eventrelay_sdk/client.py b/sdks/python/eventrelay_sdk/client.py new file mode 100644 index 000000000..f7202a572 --- /dev/null +++ b/sdks/python/eventrelay_sdk/client.py @@ -0,0 +1,74 @@ +from __future__ import annotations + +from typing import Any, Dict, Optional + +import httpx +from pydantic import BaseModel + +from .models import ( + HealthResponse, + TranscriptActionRequest, + TranscriptActionResponse, + VideoProcessingRequest, + VideoProcessingResponse, + VideoToSoftwareRequest, + VideoToSoftwareResponse, +) + + +class EventRelayClient: + """Small typed client for the EventRelay API.""" + + def __init__( + self, + base_url: str = "http://localhost:8000", + api_key: Optional[str] = None, + timeout: float = 30.0, + ) -> None: + headers: Dict[str, str] = {"Content-Type": "application/json"} + if api_key: + headers["X-API-Key"] = api_key + self._client = httpx.Client(base_url=base_url, headers=headers, timeout=timeout) + + def close(self) -> None: + self._client.close() + + def __enter__(self) -> "EventRelayClient": + return self + + def __exit__(self, *_: Any) -> None: + self.close() + + def _request(self, method: str, path: str, json: Optional[dict] = None) -> dict: + response = self._client.request(method, path, json=json) + response.raise_for_status() + return response.json() + + @staticmethod + def _parse(model: type[BaseModel], payload: dict) -> BaseModel: + return model.model_validate(payload) + + def health(self) -> HealthResponse: + data = self._request("GET", "/api/v1/health") + return self._parse(HealthResponse, data) + + def transcript_action( + self, request: TranscriptActionRequest + ) -> TranscriptActionResponse: + payload = request.model_dump(by_alias=True, exclude_none=True) + data = self._request("POST", "/api/v1/transcript-action", json=payload) + return self._parse(TranscriptActionResponse, data) + + def video_to_software( + self, request: VideoToSoftwareRequest + ) -> VideoToSoftwareResponse: + payload = request.model_dump(by_alias=True, exclude_none=True) + data = self._request("POST", "/api/v1/video-to-software", json=payload) + return self._parse(VideoToSoftwareResponse, data) + + def process_video( + self, request: VideoProcessingRequest + ) -> VideoProcessingResponse: + payload = request.model_dump(by_alias=True, exclude_none=True) + data = self._request("POST", "/api/v1/process-video", json=payload) + return self._parse(VideoProcessingResponse, data) diff --git a/sdks/python/eventrelay_sdk/models.py b/sdks/python/eventrelay_sdk/models.py new file mode 100644 index 000000000..1f3d0363f --- /dev/null +++ b/sdks/python/eventrelay_sdk/models.py @@ -0,0 +1,67 @@ +from __future__ import annotations + +from typing import Any, Optional + +from pydantic import BaseModel, ConfigDict, Field + + +class TranscriptActionRequest(BaseModel): + video_url: str + language: Optional[str] = "en" + transcript_text: Optional[str] = None + video_options: Optional[dict[str, Any]] = None + + +class TranscriptActionResponse(BaseModel): + success: bool + video_url: str + metadata: dict[str, Any] + transcript: dict[str, Any] + outputs: dict[str, Any] + errors: list[str] = Field(default_factory=list) + orchestration_meta: dict[str, Any] + + +class VideoProcessingRequest(BaseModel): + video_url: str + options: Optional[dict[str, Any]] = None + + +class VideoProcessingResponse(BaseModel): + result: dict[str, Any] + status: str + progress: Optional[float] = 0.0 + timestamp: str + + +class VideoToSoftwareRequest(BaseModel): + model_config = ConfigDict(populate_by_name=True) + + video_url: str = Field(..., alias="url") + project_type: Optional[str] = "web" + deployment_target: Optional[str] = "vercel" + features: Optional[list[str]] = None + + +class VideoToSoftwareResponse(BaseModel): + video_url: str + project_name: str + project_type: str + deployment_target: str + live_url: str + github_repo: str + build_status: str + processing_time: str + features_implemented: list[str] + video_analysis: dict[str, Any] + code_generation: dict[str, Any] + deployment: dict[str, Any] + status: str + timestamp: str + + +class HealthResponse(BaseModel): + status: str + timestamp: str + version: Optional[str] = None + components: Optional[dict[str, Any]] = None diff --git a/sdks/python/pyproject.toml b/sdks/python/pyproject.toml new file mode 100644 index 000000000..4470153b5 --- /dev/null +++ b/sdks/python/pyproject.toml @@ -0,0 +1,28 @@ +[build-system] +requires = ["setuptools>=61.0"] +build-backend = "setuptools.build_meta" + +[project] +name = "eventrelay-sdk" +version = "0.0.1" +description = "Python client SDK for the EventRelay API (generated from OpenAPI via Stainless)." +readme = "README.md" +requires-python = ">=3.9" +dependencies = [ + "httpx>=0.28.0", + "pydantic>=2.6.0", +] +authors = [{ name = "EventRelay" }] +license = { text = "MIT" } +keywords = ["eventrelay", "sdk", "openapi", "stainless"] + +[project.urls] +Homepage = "https://github.com/groupthinking/EventRelay" +Repository = "https://github.com/groupthinking/EventRelay" + +[tool.setuptools] +package-dir = {"" = "."} + +[tool.setuptools.packages.find] +where = ["."] +include = ["eventrelay_sdk*"] diff --git a/sdks/typescript/README.md b/sdks/typescript/README.md new file mode 100644 index 000000000..bc9dfe2c5 --- /dev/null +++ b/sdks/typescript/README.md @@ -0,0 +1,36 @@ +# EventRelay TypeScript SDK + +Type-safe client for the EventRelay API. This package can be generated automatically with Stainless from `openapi/eventrelay.openapi.json` and includes a lightweight hand-authored client for the core video-to-software workflow. + +## Usage + +```bash +npm install eventrelay-sdk +``` + +```ts +import { EventRelayClient } from "eventrelay-sdk"; + +const client = new EventRelayClient({ + baseUrl: "https://api.eventrelay.io", + apiKey: process.env.EVENTRELAY_API_KEY, +}); + +const health = await client.health(); +const result = await client.transcriptAction({ video_url: "https://youtu.be/auJzb1D-fag" }); +``` + +## Regenerating with Stainless + +1. Export the OpenAPI schema: + ```bash + python ../../scripts/export_openapi.py + ``` +2. Generate SDKs (requires `npx stainless`): + ```bash + npx stainless generate --config ../../stainless.config.ts + ``` +3. Build: + ```bash + npm run build + ``` diff --git a/sdks/typescript/package-lock.json b/sdks/typescript/package-lock.json new file mode 100644 index 000000000..55aac02dc --- /dev/null +++ b/sdks/typescript/package-lock.json @@ -0,0 +1,30 @@ +{ + "name": "eventrelay-sdk", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "eventrelay-sdk", + "version": "0.0.1", + "license": "MIT", + "devDependencies": { + "typescript": "^5.9.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + } + } +} diff --git a/sdks/typescript/package.json b/sdks/typescript/package.json new file mode 100644 index 000000000..b89be666d --- /dev/null +++ b/sdks/typescript/package.json @@ -0,0 +1,29 @@ +{ + "name": "eventrelay-sdk", + "version": "0.0.1", + "description": "TypeScript client SDK for the EventRelay API (generated from OpenAPI via Stainless).", + "type": "module", + "main": "dist/index.js", + "module": "dist/index.js", + "types": "dist/index.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "tsc -p tsconfig.json", + "clean": "rm -rf dist", + "prepublishOnly": "npm run build" + }, + "keywords": [ + "eventrelay", + "video-to-software", + "sdk", + "stainless", + "openapi" + ], + "author": "EventRelay", + "license": "MIT", + "devDependencies": { + "typescript": "^5.9.3" + } +} diff --git a/sdks/typescript/src/client.ts b/sdks/typescript/src/client.ts new file mode 100644 index 000000000..a38349ae1 --- /dev/null +++ b/sdks/typescript/src/client.ts @@ -0,0 +1,90 @@ +import { + ClientOptions, + HealthResponse, + TranscriptActionRequest, + TranscriptActionResponse, + VideoProcessingRequest, + VideoProcessingResponse, + VideoToSoftwareRequest, + VideoToSoftwareResponse, +} from "./types.js"; + +export class EventRelayClient { + private readonly baseUrl: string; + private readonly apiKey?: string; + private readonly timeoutMs: number; + + constructor(options: ClientOptions = {}) { + this.baseUrl = options.baseUrl ?? "http://localhost:8000"; + this.apiKey = options.apiKey; + this.timeoutMs = options.timeoutMs ?? 30000; + } + + private buildHeaders(): HeadersInit { + const headers: HeadersInit = { + "Content-Type": "application/json", + }; + if (this.apiKey) { + headers["X-API-Key"] = this.apiKey; + } + return headers; + } + + private async request(path: string, init: RequestInit): Promise { + const controller = new AbortController(); + const timeout = setTimeout(() => controller.abort(), this.timeoutMs); + try { + const response = await fetch(`${this.baseUrl}${path}`, { + ...init, + headers: { ...this.buildHeaders(), ...(init.headers ?? {}) }, + signal: controller.signal, + }); + if (!response.ok) { + const detail = await response.text(); + throw new Error( + `Request to ${path} failed with ${response.status}: ${detail}`, + ); + } + return (await response.json()) as T; + } finally { + clearTimeout(timeout); + } + } + + async health(): Promise { + return this.request("/api/v1/health", { method: "GET" }); + } + + async transcriptAction( + payload: TranscriptActionRequest, + ): Promise { + return this.request( + "/api/v1/transcript-action", + { + method: "POST", + body: JSON.stringify(payload), + }, + ); + } + + async videoToSoftware( + payload: VideoToSoftwareRequest, + ): Promise { + return this.request( + "/api/v1/video-to-software", + { + method: "POST", + body: JSON.stringify(payload), + }, + ); + } + + async processVideo( + payload: VideoProcessingRequest, + ): Promise { + return this.request("/api/v1/process-video", { + method: "POST", + body: JSON.stringify(payload), + }); + } +} diff --git a/sdks/typescript/src/index.ts b/sdks/typescript/src/index.ts new file mode 100644 index 000000000..0fdca2ff2 --- /dev/null +++ b/sdks/typescript/src/index.ts @@ -0,0 +1,2 @@ +export * from "./types.js"; +export * from "./client.js"; diff --git a/sdks/typescript/src/types.ts b/sdks/typescript/src/types.ts new file mode 100644 index 000000000..c50440834 --- /dev/null +++ b/sdks/typescript/src/types.ts @@ -0,0 +1,71 @@ +export interface ClientOptions { + baseUrl?: string; + apiKey?: string; + timeoutMs?: number; +} + +export interface VideoClipOptions { + start_seconds?: number; + end_seconds?: number; + fps?: number; +} + +export interface TranscriptActionRequest { + video_url: string; + language?: string; + transcript_text?: string; + video_options?: VideoClipOptions; +} + +export interface TranscriptActionResponse { + success: boolean; + video_url: string; + metadata: Record; + transcript: Record; + outputs: Record; + errors: string[]; + orchestration_meta: Record; +} + +export interface VideoProcessingRequest { + video_url: string; + options?: Record; +} + +export interface VideoProcessingResponse { + result: Record; + status: string; + progress?: number; + timestamp: string; +} + +export interface VideoToSoftwareRequest { + video_url: string; + project_type?: string; + deployment_target?: string; + features?: string[]; +} + +export interface VideoToSoftwareResponse { + video_url: string; + project_name: string; + project_type: string; + deployment_target: string; + live_url: string; + github_repo: string; + build_status: string; + processing_time: string; + features_implemented: string[]; + video_analysis: Record; + code_generation: Record; + deployment: Record; + status: string; + timestamp: string; +} + +export interface HealthResponse { + status: string; + timestamp: string; + version?: string; + components?: Record; +} diff --git a/sdks/typescript/tsconfig.json b/sdks/typescript/tsconfig.json new file mode 100644 index 000000000..a59a5fe5a --- /dev/null +++ b/sdks/typescript/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ES2020", + "moduleResolution": "Node", + "rootDir": "src", + "outDir": "dist", + "declaration": true, + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true + }, + "include": ["src"] +} diff --git a/src/youtube_extension.egg-info/PKG-INFO b/src/youtube_extension.egg-info/PKG-INFO deleted file mode 100644 index b842a5c16..000000000 --- a/src/youtube_extension.egg-info/PKG-INFO +++ /dev/null @@ -1,307 +0,0 @@ -Metadata-Version: 2.4 -Name: youtube_extension -Version: 1.0.0 -Summary: UVAI Platform - Revolutionary AI-Powered Video Learning System -Author-email: UVAI Team -Maintainer-email: UVAI Team -License: MIT -Project-URL: Homepage, https://github.com/uvai/youtube-extension -Project-URL: Documentation, https://uvai.github.io/youtube-extension/ -Project-URL: Repository, https://github.com/uvai/youtube-extension.git -Project-URL: Issues, https://github.com/uvai/youtube-extension/issues -Project-URL: Changelog, https://github.com/uvai/youtube-extension/blob/main/docs/changelog/v1.0.0.md -Keywords: youtube,ai,video-processing,machine-learning,education -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Topic :: Internet :: WWW/HTTP -Classifier: Topic :: Multimedia :: Video -Classifier: Topic :: Education -Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence -Requires-Python: >=3.9 -Description-Content-Type: text/markdown -License-File: LICENSE -Requires-Dist: fastapi>=0.110.0 -Requires-Dist: slowapi>=0.1.8 -Requires-Dist: sentry-sdk>=1.39.0 -Requires-Dist: ddtrace>=2.1.0 -Requires-Dist: google-cloud-aiplatform>=1.38.0 -Requires-Dist: uvicorn[standard]>=0.24.0 -Requires-Dist: pydantic>=2.5.0 -Requires-Dist: pydantic-settings>=2.1.0 -Requires-Dist: httpx>=0.25.0 -Requires-Dist: aiofiles>=23.2.1 -Requires-Dist: python-multipart>=0.0.6 -Requires-Dist: jinja2>=3.1.2 -Requires-Dist: alembic>=1.12.0 -Requires-Dist: sqlalchemy>=2.0.0 -Requires-Dist: aiosqlite>=0.19.0 -Requires-Dist: python-jose[cryptography]>=3.3.0 -Requires-Dist: passlib[bcrypt]>=1.7.4 -Requires-Dist: python-decouple>=3.8 -Requires-Dist: structlog>=23.2.0 -Requires-Dist: rich>=13.7.0 -Requires-Dist: typer>=0.9.0 -Requires-Dist: click>=8.1.7 -Requires-Dist: pathlib2>=2.3.7 -Requires-Dist: python-dotenv>=1.0.0 -Requires-Dist: PyYAML>=6.0.0 -Requires-Dist: requests>=2.31.0 -Requires-Dist: Pillow>=10.0.0 -Requires-Dist: google-genai>=1.0.0 -Requires-Dist: google-generativeai>=0.3.0 -Requires-Dist: opentelemetry-distro>=0.40b0 -Requires-Dist: opentelemetry-exporter-otlp>=1.20.0 -Requires-Dist: psutil>=5.9.0 -Requires-Dist: ffmpeg-python>=0.2.0 -Requires-Dist: qrcode[pil]>=7.0 -Requires-Dist: opencv-python>=4.8.0 -Requires-Dist: orjson>=3.9.0 -Provides-Extra: dev -Requires-Dist: pytest>=7.4.0; extra == "dev" -Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev" -Requires-Dist: pytest-cov>=4.1.0; extra == "dev" -Requires-Dist: pytest-xdist>=3.5.0; extra == "dev" -Requires-Dist: pytest-mock>=3.12.0; extra == "dev" -Requires-Dist: black>=23.0.0; extra == "dev" -Requires-Dist: isort>=5.12.0; extra == "dev" -Requires-Dist: flake8>=6.0.0; extra == "dev" -Requires-Dist: mypy>=1.7.0; extra == "dev" -Requires-Dist: pre-commit>=3.5.0; extra == "dev" -Requires-Dist: ruff>=0.1.0; extra == "dev" -Requires-Dist: jupyter>=1.0.0; extra == "dev" -Requires-Dist: ipykernel>=6.25.0; extra == "dev" -Requires-Dist: notebook>=7.0.0; extra == "dev" -Provides-Extra: docs -Requires-Dist: mkdocs>=1.5.0; extra == "docs" -Requires-Dist: mkdocs-material>=9.4.0; extra == "docs" -Requires-Dist: mkdocstrings[python]>=0.23.0; extra == "docs" -Requires-Dist: mkdocs-autorefs>=0.5.0; extra == "docs" -Provides-Extra: deploy -Requires-Dist: docker>=6.1.0; extra == "deploy" -Requires-Dist: kubernetes>=28.1.0; extra == "deploy" -Requires-Dist: helm>=3.12.0; extra == "deploy" -Requires-Dist: flyctl>=0.1.0; extra == "deploy" -Provides-Extra: youtube -Requires-Dist: youtube-transcript-api>=0.6.0; extra == "youtube" -Requires-Dist: google-api-python-client>=2.100.0; extra == "youtube" -Requires-Dist: google-cloud-speech>=2.26.0; extra == "youtube" -Requires-Dist: yt-dlp>=2023.7.6; extra == "youtube" -Requires-Dist: aiohttp>=3.8.0; extra == "youtube" -Requires-Dist: asyncio-throttle>=1.0.0; extra == "youtube" -Requires-Dist: websockets>=12.0; extra == "youtube" -Requires-Dist: gitpython>=3.1.0; extra == "youtube" -Requires-Dist: cachetools>=5.0.0; extra == "youtube" -Requires-Dist: google-cloud-storage>=2.13.0; extra == "youtube" -Requires-Dist: google-cloud-pubsub>=2.19.0; extra == "youtube" -Requires-Dist: google-cloud-vision>=3.7.0; extra == "youtube" -Requires-Dist: google-cloud-videointelligence>=2.13.0; extra == "youtube" -Provides-Extra: postgres -Requires-Dist: psycopg2-binary>=2.9.0; extra == "postgres" -Requires-Dist: asyncpg>=0.29.0; extra == "postgres" -Provides-Extra: ml -Requires-Dist: torch>=2.1.0; extra == "ml" -Requires-Dist: torchvision>=0.16.0; extra == "ml" -Requires-Dist: torchaudio>=2.1.0; extra == "ml" -Requires-Dist: transformers>=4.35.0; extra == "ml" -Requires-Dist: datasets>=2.15.0; extra == "ml" -Requires-Dist: accelerate>=0.24.0; extra == "ml" -Requires-Dist: tokenizers>=0.15.0; extra == "ml" -Requires-Dist: sentence-transformers>=2.2.0; extra == "ml" -Requires-Dist: openai>=1.3.0; extra == "ml" -Requires-Dist: anthropic>=0.7.0; extra == "ml" -Requires-Dist: google-generativeai>=0.3.0; extra == "ml" -Requires-Dist: cohere>=4.37.0; extra == "ml" -Requires-Dist: numpy>=1.24.0; extra == "ml" -Requires-Dist: pandas>=2.0.0; extra == "ml" -Dynamic: license-file - -# 🎯 EventRelay — AI Video Processing & Event Extraction Platform - -[![CI](https://github.com/groupthinking/EventRelay/actions/workflows/ci.yml/badge.svg)](https://github.com/groupthinking/EventRelay/actions/workflows/ci.yml) -[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) -![Node >= 20](https://img.shields.io/badge/Node-%3E%3D20-green) -![Python >= 3.11](https://img.shields.io/badge/Python-%3E%3D3.11-blue) - -AI-powered video transcript capture, structured event extraction, and agent execution for YouTube content. Paste a URL → get a word-for-word transcript, typed events, actionable tasks, and AI-driven insights. - -## Architecture - -``` -┌──────────────────────────────────────────────────────────┐ -│ Next.js Frontend (apps/web) localhost:3000 │ -│ ┌─────────────┐ ┌──────────────┐ ┌────────────────┐ │ -│ │ Dashboard │ │ /api/video │ │ /api/extract- │ │ -│ │ (React + │──│ (proxy to │──│ events │ │ -│ │ Zustand) │ │ backend) │ │ (OpenAI │ │ -│ └─────────────┘ └──────┬───────┘ │ Responses API) │ │ -│ │ └────────────────┘ │ -│ ┌────────────────┐ │ │ -│ │ /api/transcribe │ │ OpenAI STT fallback │ -│ └────────────────┘ │ │ -└──────────────────────────┼──────────────────────────────┘ - │ -┌──────────────────────────┼──────────────────────────────┐ -│ FastAPI Backend (src/) localhost:8000 │ -│ │ │ -│ ┌───────────────────────▼─────────────────────────┐ │ -│ │ /api/v1/transcript-action │ │ -│ │ YouTube transcript → 3 Gemini agents: │ │ -│ │ • transcript_action (summary + tasks) │ │ -│ │ • personality_agent (intent analysis) │ │ -│ │ • strategy_agent (strategic insights) │ │ -│ └─────────────────────────────────────────────────┘ │ -│ │ -│ /api/v1/health /api/v1/capabilities /api/v1/videos │ -│ /api/v1/events /api/v1/agents /api/v1/chat │ -└─────────────────────────────────────────────────────────┘ -``` - -**Hybrid AI:** Gemini handles deep analysis (personality, strategy), OpenAI Responses API handles structured event/action extraction with JSON Schema strict mode, and OpenAI STT provides transcription fallback when YouTube captions are unavailable. - -## Quick Start - -### Prerequisites - -- Python >= 3.11 -- Node.js >= 20 -- API keys: `GEMINI_API_KEY` and `OPENAI_API_KEY` - -### Setup - -```bash -# Clone -git clone https://github.com/groupthinking/EventRelay.git -cd EventRelay - -# Backend -python3 -m venv .venv && source .venv/bin/activate -pip install -e .[dev] - -# Frontend -npm install - -# API keys (add to shell profile or .env) -export GEMINI_API_KEY="your-key" -export OPENAI_API_KEY="your-key" -``` - -### Run - -```bash -# Terminal 1: Backend -PYTHONPATH=src python3 -m uvicorn youtube_extension.main:app --port 8000 - -# Terminal 2: Frontend -cd apps/web && BACKEND_URL=http://localhost:8000 npx next dev --port 3000 -``` - -Open http://localhost:3000/dashboard — paste a YouTube URL and watch it process. - -## How It Works - -1. **Paste URL** → Dashboard sends to `/api/video` -2. **Transcribe** → Backend fetches YouTube transcript (falls back to OpenAI STT if unavailable) -3. **Analyze** → 3 Gemini agents run: summary, personality mapping, strategy -4. **Extract** → OpenAI Responses API returns structured events, actions, topics via strict JSON Schema -5. **Display** → Dashboard shows everything in tabs: insights, transcript, events, agents - -## API Endpoints - -### Frontend Routes (Next.js) - -| Method | Route | Description | -|--------|-------|-------------| -| POST | `/api/video` | Process YouTube URL → transcript + AI analysis | -| POST | `/api/extract-events` | Structured event/action extraction (OpenAI) | -| POST | `/api/transcribe` | Transcription with YouTube/OpenAI STT fallback | -| POST | `/api/chat` | Chat with AI about video content | -| GET | `/api/dashboard` | Backend health check proxy | - -### Backend Routes (FastAPI) - -| Method | Route | Description | -|--------|-------|-------------| -| POST | `/api/v1/transcript-action` | Core pipeline: transcript → agents → results | -| GET | `/api/v1/health` | Service health check | -| GET | `/api/v1/capabilities` | Available features and providers | -| POST | `/api/v1/videos/process` | Async video processing job | -| GET | `/api/v1/videos/{job_id}/status` | Job status polling | -| POST | `/api/v1/events/extract` | Backend event extraction | -| POST | `/api/v1/agents/dispatch` | Dispatch agent execution | -| POST | `/api/v1/chat` | Conversational AI about videos | - -Full API docs at http://localhost:8000/docs (Swagger UI). - -## Project Structure - -``` -EventRelay/ -├── apps/web/ # Next.js frontend -│ └── src/ -│ ├── app/ -│ │ ├── dashboard/page.tsx # Main dashboard UI -│ │ └── api/ # API routes (video, extract-events, transcribe, chat) -│ ├── components/ # TranscriptViewer, EventList, AgentDashboard, ResultsViewer -│ ├── store/ # Zustand state management -│ └── lib/ # API client, services, types -├── src/youtube_extension/ # FastAPI backend -│ ├── main.py # App entry point -│ └── backend/ -│ ├── api/v1/ # Router + Pydantic models -│ └── services/ai/ # Gemini service, health monitoring -├── tests/unit/ # Python unit tests -├── docs/ # Documentation -├── .github/ # CI workflows, Copilot agent configs -├── Dockerfile # Production container -└── package.json # Monorepo root (npm workspaces) -``` - -## Testing - -```bash -# Python unit tests (15 tests) -PYTHONPATH=src python3 -m pytest tests/unit/test_api_v1_models.py -v --override-ini="addopts=" - -# Frontend build check -npm run build:web - -# Lint -cd apps/web && npx next lint -``` - -## Environment Variables - -| Variable | Required | Description | -|----------|----------|-------------| -| `GEMINI_API_KEY` | Yes | Google AI Studio key for Gemini agents | -| `OPENAI_API_KEY` | Yes | OpenAI key for event extraction + STT | -| `BACKEND_URL` | No | Backend URL (default: `http://localhost:8000`) | -| `YOUTUBE_API_KEY` | No | YouTube Data API for enhanced metadata | - -## Deployment - -```bash -# Docker -docker build -t eventrelay . -docker run -p 8000:8000 -e GEMINI_API_KEY=... -e OPENAI_API_KEY=... eventrelay - -# Vercel (frontend) -vercel deploy --prod -``` - -## Contributing - -- Follow [Conventional Commits](https://www.conventionalcommits.org/): `feat:`, `fix:`, `chore:`, etc. -- Run tests before opening PRs -- See [CONTRIBUTING.md](CONTRIBUTING.md) and [AGENTS.md](AGENTS.md) for detailed guidelines - -## License - -MIT — see [LICENSE](LICENSE) diff --git a/src/youtube_extension.egg-info/SOURCES.txt b/src/youtube_extension.egg-info/SOURCES.txt deleted file mode 100644 index ab3d0c6a6..000000000 --- a/src/youtube_extension.egg-info/SOURCES.txt +++ /dev/null @@ -1,249 +0,0 @@ -LICENSE -README.md -pyproject.toml -src/agents/__init__.py -src/agents/a2a_framework.py -src/agents/a2a_remediation_orchestrator.py -src/agents/action_implementer.py -src/agents/enhanced_video_processor.py -src/agents/gemini_video_master_agent.py -src/agents/grok4_video_subagent.py -src/agents/interactive_metadata_extractor.py -src/agents/llama_background_agent.py -src/agents/markdown_video_processor.py -src/agents/mcp_agent_network.py -src/agents/mcp_ecosystem_coordinator.py -src/agents/mcp_enhanced_video_processor.py -src/agents/multi_llm_video_processor.py -src/agents/observability_setup.py -src/agents/openai_dev_task_manager.py -src/agents/orchestrator_minimal.py -src/agents/packaging_agent.py -src/agents/pipeline_orchestrator.py -src/agents/process_video_with_mcp.py -src/agents/real_mode_guard.py -src/agents/skill_monitor_emitter.py -src/agents/validate_authenticity.py -src/agents/video_to_action_workflow.py -src/agents/mcp_tools/__init__.py -src/agents/mcp_tools/build_validator_tool.py -src/agents/mcp_tools/deployment_tool.py -src/agents/mcp_tools/tri_model_consensus_tool.py -src/agents/mcp_tools/youtube_tool.py -src/agents/specialized/__init__.py -src/agents/specialized/architecture_agent.py -src/agents/specialized/code_generator.py -src/agents/specialized/performance_agent.py -src/agents/specialized/personality_agent.py -src/agents/specialized/precision_extractor.py -src/agents/specialized/quality_agent.py -src/agents/specialized/security_agent.py -src/agents/specialized/strategy_agent.py -src/agents/unified/mcp_a2a_mojo_integration.py -src/analysis/code_structure_analyzer.py -src/backend/__init__.py -src/backend/main_v2.py -src/backend/repositories/__init__.py -src/backend/repositories/action_repository.py -src/connectors/__init__.py -src/connectors/mcp_base.py -src/core/__init__.py -src/core/canary_router.py -src/core/collections.py -src/core/feature_flags.py -src/core/model_router.py -src/integration/__init__.py -src/integration/api_gateway.py -src/integration/cloudevents_publisher.py -src/integration/component_registry.py -src/integration/context_manager.py -src/integration/data_pipeline.py -src/integration/gemini_video.py -src/integration/gemini_video_fix.py -src/integration/health_checker.py -src/integration/mcp_orchestrator.py -src/integration/openai_voice.py -src/integration/performance_monitor.py -src/integration/routes.py -src/integration/stripe_payments.py -src/integration/supabase_db.py -src/integration/temporal_video_analysis.py -src/integration/vercel_deploy.py -src/integration/youtube_api.py -src/mcp/bridge.py -src/mcp/mcp_ecosystem_coordinator.py -src/mcp/mcp_video_processor.py -src/mcp/test_integrated_servers.py -src/mcp/validation-scope-mcp.py -src/shared/__init__.py -src/shared/run_validation.py -src/shared/youtube/__init__.py -src/unified_ai_sdk/__init__.py -src/unified_ai_sdk/rate_limiter.py -src/unified_ai_sdk/unified_ai_sdk.py -src/utils/__init__.py -src/utils/notebooklm_ingest.py -src/utils/path_utils.py -src/uvai/main_v2.py -src/uvai/server.py -src/uvai/api/__init__.py -src/uvai/api/main.py -src/uvai/api/server.py -src/uvai/api/v1/services/issue_tracker.py -src/uvai/security_protocol/__init__.py -src/uvai/security_protocol/encode_video.py -src/uvai/security_protocol/generate_keys.py -src/uvai/security_protocol/video_listener.py -src/youtube_extension/__init__.py -src/youtube_extension/cli.py -src/youtube_extension/main.py -src/youtube_extension.egg-info/PKG-INFO -src/youtube_extension.egg-info/SOURCES.txt -src/youtube_extension.egg-info/dependency_links.txt -src/youtube_extension.egg-info/entry_points.txt -src/youtube_extension.egg-info/requires.txt -src/youtube_extension.egg-info/top_level.txt -src/youtube_extension/backend/__init__.py -src/youtube_extension/backend/ai_code_generator.py -src/youtube_extension/backend/ai_insights_processor.py -src/youtube_extension/backend/cloud_ai_routes.py -src/youtube_extension/backend/code_generator.py -src/youtube_extension/backend/deployment_manager.py -src/youtube_extension/backend/enhanced_video_processor.py -src/youtube_extension/backend/main.py -src/youtube_extension/backend/real_api_endpoints.py -src/youtube_extension/backend/video_processor_factory.py -src/youtube_extension/backend/video_processor_interface.py -src/youtube_extension/backend/worker.py -src/youtube_extension/backend/api/__init__.py -src/youtube_extension/backend/api/advanced_video_routes.py -src/youtube_extension/backend/api/event_routes.py -src/youtube_extension/backend/api/mcp_bridge.py -src/youtube_extension/backend/api/v1/__init__.py -src/youtube_extension/backend/api/v1/models.py -src/youtube_extension/backend/api/v1/router.py -src/youtube_extension/backend/config/database.py -src/youtube_extension/backend/config/logging_config.py -src/youtube_extension/backend/config/production_config.py -src/youtube_extension/backend/containers/service_container.py -src/youtube_extension/backend/deepmcp/orchestrator.py -src/youtube_extension/backend/deploy/__init__.py -src/youtube_extension/backend/deploy/core.py -src/youtube_extension/backend/deploy/fly.py -src/youtube_extension/backend/deploy/netlify.py -src/youtube_extension/backend/deploy/vercel.py -src/youtube_extension/backend/middleware/__init__.py -src/youtube_extension/backend/middleware/api_key_auth.py -src/youtube_extension/backend/middleware/error_handling_middleware.py -src/youtube_extension/backend/middleware/rate_limiting.py -src/youtube_extension/backend/middleware/security_headers.py -src/youtube_extension/backend/migrations/env.py -src/youtube_extension/backend/migrations/versions/20241231_1200_001_initial_schema.py -src/youtube_extension/backend/migrations/versions/20260107_0057_002_secure_alembic_secure_alembic_version_table.py -src/youtube_extension/backend/models/__init__.py -src/youtube_extension/backend/models/analytics.py -src/youtube_extension/backend/models/audit.py -src/youtube_extension/backend/models/base.py -src/youtube_extension/backend/models/cache.py -src/youtube_extension/backend/models/learning.py -src/youtube_extension/backend/models/tenant.py -src/youtube_extension/backend/models/user.py -src/youtube_extension/backend/models/video.py -src/youtube_extension/backend/repositories/__init__.py -src/youtube_extension/backend/repositories/base.py -src/youtube_extension/backend/services/api_cost_monitor.py -src/youtube_extension/backend/services/cache_service.py -src/youtube_extension/backend/services/comprehensive_benchmarking.py -src/youtube_extension/backend/services/data_service.py -src/youtube_extension/backend/services/database_cleanup_service.py -src/youtube_extension/backend/services/database_optimizer.py -src/youtube_extension/backend/services/health_monitoring_service.py -src/youtube_extension/backend/services/horizontal_scaling_system.py -src/youtube_extension/backend/services/innertube_transcript.py -src/youtube_extension/backend/services/intelligent_cache.py -src/youtube_extension/backend/services/load_balancer.py -src/youtube_extension/backend/services/logging_service.py -src/youtube_extension/backend/services/memory_manager.py -src/youtube_extension/backend/services/memory_optimizer.py -src/youtube_extension/backend/services/metrics_service.py -src/youtube_extension/backend/services/notification_service.py -src/youtube_extension/backend/services/optimized_video_processor.py -src/youtube_extension/backend/services/parallel_video_processor.py -src/youtube_extension/backend/services/performance_benchmark_system.py -src/youtube_extension/backend/services/performance_monitor.py -src/youtube_extension/backend/services/pubsub_service.py -src/youtube_extension/backend/services/real_ai_processor.py -src/youtube_extension/backend/services/real_video_processor.py -src/youtube_extension/backend/services/real_youtube_api.py -src/youtube_extension/backend/services/robust_youtube_service.py -src/youtube_extension/backend/services/video_processing_service.py -src/youtube_extension/backend/services/websocket_service.py -src/youtube_extension/backend/services/youtube/__init__.py -src/youtube_extension/backend/services/youtube/balancer.py -src/youtube_extension/backend/services/youtube/provider.py -src/youtube_extension/backend/services/youtube/adapters/innertube.py -src/youtube_extension/backend/services/youtube/adapters/official_api.py -src/youtube_extension/backend/services/youtube/adapters/robust.py -src/youtube_extension/config/__init__.py -src/youtube_extension/core/__init__.py -src/youtube_extension/core/config/__init__.py -src/youtube_extension/core/mcp/__init__.py -src/youtube_extension/core/mcp/context_manager.py -src/youtube_extension/core/mcp/protocol_bridge.py -src/youtube_extension/core/mcp/server_registry.py -src/youtube_extension/core/mcp/validation.py -src/youtube_extension/integrations/__init__.py -src/youtube_extension/integrations/cloud_ai.py -src/youtube_extension/integrations/cloud_ai/__init__.py -src/youtube_extension/integrations/cloud_ai/base.py -src/youtube_extension/integrations/cloud_ai/config.py -src/youtube_extension/integrations/cloud_ai/exceptions.py -src/youtube_extension/integrations/cloud_ai/integrator.py -src/youtube_extension/integrations/cloud_ai/providers/__init__.py -src/youtube_extension/integrations/cloud_ai/providers/aws_rekognition.py -src/youtube_extension/integrations/cloud_ai/providers/azure_vision.py -src/youtube_extension/integrations/cloud_ai/providers/google_cloud.py -src/youtube_extension/intelligence/__init__.py -src/youtube_extension/mcp/enterprise_mcp_server.py -src/youtube_extension/mcp/notebooklm_processor.py -src/youtube_extension/orchestrator/main.py -src/youtube_extension/processors/__init__.py -src/youtube_extension/processors/enhanced_extractor.py -src/youtube_extension/processors/strategies.py -src/youtube_extension/processors/video_processor.py -src/youtube_extension/services/__init__.py -src/youtube_extension/services/deployment_manager.py -src/youtube_extension/services/video_subagent.py -src/youtube_extension/services/agents/__init__.py -src/youtube_extension/services/agents/action_implementer_agent.py -src/youtube_extension/services/agents/agent_gap_analyzer.py -src/youtube_extension/services/agents/agent_orchestrator.py -src/youtube_extension/services/agents/base_agent.py -src/youtube_extension/services/agents/dto.py -src/youtube_extension/services/agents/hybrid_vision_agent.py -src/youtube_extension/services/agents/monitor.py -src/youtube_extension/services/agents/registry.py -src/youtube_extension/services/agents/video_master_agent.py -src/youtube_extension/services/agents/adapters/action_implementer_agent.py -src/youtube_extension/services/agents/adapters/agent_orchestrator.py -src/youtube_extension/services/agents/adapters/hybrid_vision_agent.py -src/youtube_extension/services/agents/adapters/personality_agent.py -src/youtube_extension/services/agents/adapters/strategy_agent.py -src/youtube_extension/services/agents/adapters/transcript_action_agent.py -src/youtube_extension/services/agents/adapters/video_master_agent.py -src/youtube_extension/services/ai/__init__.py -src/youtube_extension/services/ai/gemini_service.py -src/youtube_extension/services/ai/hybrid_processor_service.py -src/youtube_extension/services/ai/speech_to_text_service.py -src/youtube_extension/services/workflows/transcript_action_workflow.py -src/youtube_extension/utils/__init__.py -src/youtube_extension/utils/performance.py -src/youtube_extension/utils/repro.py -src/youtube_extension/utils/video_utils.py -src/youtube_extension/videopack/__init__.py -src/youtube_extension/videopack/exceptions.py -src/youtube_extension/videopack/io.py -src/youtube_extension/videopack/provenance.py -src/youtube_extension/videopack/schema.py -src/youtube_extension/videopack/validate.py -src/youtube_extension/videopack/versioning.py \ No newline at end of file diff --git a/src/youtube_extension.egg-info/dependency_links.txt b/src/youtube_extension.egg-info/dependency_links.txt deleted file mode 100644 index 8b1378917..000000000 --- a/src/youtube_extension.egg-info/dependency_links.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/youtube_extension.egg-info/entry_points.txt b/src/youtube_extension.egg-info/entry_points.txt deleted file mode 100644 index aa278e9e7..000000000 --- a/src/youtube_extension.egg-info/entry_points.txt +++ /dev/null @@ -1,7 +0,0 @@ -[console_scripts] -uvai.api = uvai.api.server:main -uvai.core = uvai.core.server:main -youtube-extension = youtube_extension.cli:main -youtube-migrate = youtube_extension.cli:migrate -youtube-test = youtube_extension.cli:test -youtube-worker = youtube_extension.backend.worker:main diff --git a/src/youtube_extension.egg-info/requires.txt b/src/youtube_extension.egg-info/requires.txt deleted file mode 100644 index e37cff1f9..000000000 --- a/src/youtube_extension.egg-info/requires.txt +++ /dev/null @@ -1,99 +0,0 @@ -fastapi>=0.110.0 -slowapi>=0.1.8 -sentry-sdk>=1.39.0 -ddtrace>=2.1.0 -google-cloud-aiplatform>=1.38.0 -uvicorn[standard]>=0.24.0 -pydantic>=2.5.0 -pydantic-settings>=2.1.0 -httpx>=0.25.0 -aiofiles>=23.2.1 -python-multipart>=0.0.6 -jinja2>=3.1.2 -alembic>=1.12.0 -sqlalchemy>=2.0.0 -aiosqlite>=0.19.0 -python-jose[cryptography]>=3.3.0 -passlib[bcrypt]>=1.7.4 -python-decouple>=3.8 -structlog>=23.2.0 -rich>=13.7.0 -typer>=0.9.0 -click>=8.1.7 -pathlib2>=2.3.7 -python-dotenv>=1.0.0 -PyYAML>=6.0.0 -requests>=2.31.0 -Pillow>=10.0.0 -google-genai>=1.0.0 -google-generativeai>=0.3.0 -opentelemetry-distro>=0.40b0 -opentelemetry-exporter-otlp>=1.20.0 -psutil>=5.9.0 -ffmpeg-python>=0.2.0 -qrcode[pil]>=7.0 -opencv-python>=4.8.0 -orjson>=3.9.0 - -[deploy] -docker>=6.1.0 -kubernetes>=28.1.0 -helm>=3.12.0 -flyctl>=0.1.0 - -[dev] -pytest>=7.4.0 -pytest-asyncio>=0.21.0 -pytest-cov>=4.1.0 -pytest-xdist>=3.5.0 -pytest-mock>=3.12.0 -black>=23.0.0 -isort>=5.12.0 -flake8>=6.0.0 -mypy>=1.7.0 -pre-commit>=3.5.0 -ruff>=0.1.0 -jupyter>=1.0.0 -ipykernel>=6.25.0 -notebook>=7.0.0 - -[docs] -mkdocs>=1.5.0 -mkdocs-material>=9.4.0 -mkdocstrings[python]>=0.23.0 -mkdocs-autorefs>=0.5.0 - -[ml] -torch>=2.1.0 -torchvision>=0.16.0 -torchaudio>=2.1.0 -transformers>=4.35.0 -datasets>=2.15.0 -accelerate>=0.24.0 -tokenizers>=0.15.0 -sentence-transformers>=2.2.0 -openai>=1.3.0 -anthropic>=0.7.0 -google-generativeai>=0.3.0 -cohere>=4.37.0 -numpy>=1.24.0 -pandas>=2.0.0 - -[postgres] -psycopg2-binary>=2.9.0 -asyncpg>=0.29.0 - -[youtube] -youtube-transcript-api>=0.6.0 -google-api-python-client>=2.100.0 -google-cloud-speech>=2.26.0 -yt-dlp>=2023.7.6 -aiohttp>=3.8.0 -asyncio-throttle>=1.0.0 -websockets>=12.0 -gitpython>=3.1.0 -cachetools>=5.0.0 -google-cloud-storage>=2.13.0 -google-cloud-pubsub>=2.19.0 -google-cloud-vision>=3.7.0 -google-cloud-videointelligence>=2.13.0 diff --git a/src/youtube_extension.egg-info/top_level.txt b/src/youtube_extension.egg-info/top_level.txt deleted file mode 100644 index 937ce0213..000000000 --- a/src/youtube_extension.egg-info/top_level.txt +++ /dev/null @@ -1,12 +0,0 @@ -agents -analysis -backend -connectors -core -integration -mcp -shared -unified_ai_sdk -utils -uvai -youtube_extension diff --git a/stainless.config.ts b/stainless.config.ts new file mode 100644 index 000000000..84d55eed1 --- /dev/null +++ b/stainless.config.ts @@ -0,0 +1,39 @@ +import { defineConfig } from "stainless"; + +export default defineConfig({ + openapi: "./openapi/eventrelay.openapi.json", + sdks: [ + { language: "typescript", output: "./sdks/typescript" }, + { language: "python", output: "./sdks/python" }, + ], + resources: { + health: { + methods: { + basic: { operationId: "health_check_v1_api_v1_health_get" }, + detailed: { operationId: "detailed_health_check_v1_api_v1_health_detailed_get" }, + }, + }, + videos: { + models: { + videoProcessingRequest: "#/components/schemas/VideoProcessingRequest", + videoToSoftwareRequest: "#/components/schemas/VideoToSoftwareRequest", + transcriptActionRequest: "#/components/schemas/TranscriptActionRequest", + }, + methods: { + process: { operationId: "process_video_v1_api_v1_process_video_post" }, + transcriptAction: { operationId: "run_transcript_action_api_v1_transcript_action_post" }, + videoToSoftware: { operationId: "video_to_software_v1_api_v1_video_to_software_post" }, + markdown: { operationId: "process_video_markdown_v1_api_v1_process_video_markdown_post" }, + jobStatus: { operationId: "get_video_job_status_api_v1_videos__job_id__status_get" }, + }, + }, + events: { + methods: { + extract: { operationId: "extract_events_api_v1_events_extract_post" }, + }, + models: { + eventExtractRequest: "#/components/schemas/EventExtractRequest", + }, + }, + }, +}); diff --git a/tests/test_openapi_export.py b/tests/test_openapi_export.py new file mode 100644 index 000000000..3298c5fd4 --- /dev/null +++ b/tests/test_openapi_export.py @@ -0,0 +1,19 @@ +import sys +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +if str(ROOT) not in sys.path: + sys.path.insert(0, str(ROOT)) + +from scripts.export_openapi import export_openapi + + +def test_export_openapi_writes_schema(tmp_path: Path) -> None: + output = tmp_path / "openapi.json" + schema = export_openapi(output) + + assert output.exists() + data = output.read_text(encoding="utf-8") + assert '"paths"' in data + assert "/api/v1/transcript-action" in data + assert schema.get("info", {}).get("title") in {"YouTube Extension API", "UVAI API"}