oneword-ai 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,237 @@
1
+ Metadata-Version: 2.4
2
+ Name: oneword-ai
3
+ Version: 0.1.0
4
+ Summary: A minimalist one-word subtitle generator with Neobrutalism UI
5
+ Author-email: Ambrish <ambrishyadav1110@gmail.com>
6
+ License: Copyright 2025 Ambrish
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the β€œSoftware”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11
+
12
+ THE SOFTWARE IS PROVIDED β€œAS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13
+ Project-URL: Homepage, https://github.com/Ambrishyadav-byte/OnewordAI
14
+ Project-URL: Bug Tracker, https://github.com/Ambrishyadav-byte/OnewordAI/issues
15
+ Keywords: subtitles,ai,whisper,content-creation,video-editing
16
+ Requires-Python: >=3.9
17
+ Description-Content-Type: text/markdown
18
+ License-File: license.txt
19
+ Requires-Dist: openai-whisper>=20231117
20
+ Requires-Dist: torch>=2.0.0
21
+ Requires-Dist: fastapi>=0.100.0
22
+ Requires-Dist: uvicorn[standard]>=0.23.0
23
+ Requires-Dist: python-multipart>=0.0.6
24
+ Requires-Dist: ffmpeg-python>=0.2.0
25
+ Requires-Dist: gradio>=4.0.0
26
+ Requires-Dist: tqdm>=4.65.0
27
+ Requires-Dist: aiofiles>=23.0.0
28
+ Requires-Dist: transformers>=4.30.0
29
+ Requires-Dist: accelerate>=0.20.0
30
+ Requires-Dist: huggingface_hub>=0.16.0
31
+ Dynamic: license-file
32
+
33
+ # 🎬 OneWord AI - Subtitle Generator
34
+
35
+ <div align="center">
36
+
37
+ **Generate cinematic one-word subtitles from video/audio using Whisper AI**
38
+
39
+ [![Python](https://img.shields.io/badge/Python-3.8%2B-blue)](https://www.python.org/)
40
+ [![License](https://img.shields.io/badge/License-MIT-green)](license.txt)
41
+ [![Whisper](https://img.shields.io/badge/OpenAI-Whisper-orange)](https://github.com/openai/whisper)
42
+
43
+ Perfect for creators making high-energy reels, shorts, and TikToks!
44
+
45
+ </div>
46
+
47
+ ---
48
+
49
+ ## ✨ Features
50
+
51
+ - 🎯 **Three Subtitle Modes**: One Word, Two Word Punch, Phrase Mode
52
+ - 🌍 **Multi-Language**: Auto-detect or specify (English, Hindi, Urdu, Spanish)
53
+ - πŸ€– **Multiple Models**: Medium, Large, and **Hindi2Hinglish** (Oriserve/Prime) πŸ†•
54
+ - πŸ“¦ **Python Package**: Installable via pip with `oneword-cli` and `oneword-web` commands
55
+ - πŸ’» **Local CLI**: Robust command-line tool for batch processing
56
+ - 🌐 **Web UI**: Beautiful Neobrutalism-styled web interface
57
+ - ☁️ **Cloud Ready**: Works on Google Colab and Hugging Face Spaces
58
+ - 🐳 **Docker Support**: Containerized deployment
59
+
60
+ ## πŸš€ Quick Start
61
+
62
+ ### Installation
63
+
64
+ ```bash
65
+ # Clone the repository
66
+ git clone https://github.com/Ambrishyadav-byte/OnewordAI.git
67
+ cd OnewordAI
68
+
69
+ # Install as a package
70
+ pip install -e .
71
+ ```
72
+
73
+ **Prerequisites**: Ensure [FFmpeg](https://ffmpeg.org/) is installed on your system.
74
+
75
+ ### Usage
76
+
77
+ #### πŸ–₯️ CLI (Command Line)
78
+
79
+ See [CLI.md](CLI.md) for full documentation.
80
+
81
+ ```bash
82
+ # Basic usage
83
+ oneword-cli -i video.mp4
84
+
85
+ # Full options
86
+ oneword-cli -i video.mp4 -m medium -lang hi -mode oneword
87
+ ```
88
+
89
+ #### 🌐 Web UI
90
+
91
+ ```bash
92
+ # Start server & open browser
93
+ oneword-web
94
+ ```
95
+
96
+ Features:
97
+ - Drag & drop file upload
98
+ - Real-time progress tracking
99
+ - Instant SRT download
100
+ - Responsive Neobrutalism design
101
+
102
+ #### ☁️ Google Colab
103
+
104
+ [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/)
105
+
106
+ 1. Open `OneWord_Colab.ipynb` in Colab
107
+ 2. Run all cells
108
+ 3. Upload your video
109
+ 4. Download your SRT!
110
+
111
+ #### πŸ€— Hugging Face Space
112
+
113
+ ```bash
114
+ python app_gradio.py
115
+ ```
116
+
117
+ Or deploy to Hugging Face Spaces for a hosted version!
118
+
119
+ ## πŸ“Š Subtitle Modes
120
+
121
+ | Mode | Description | Use Case |
122
+ |------|-------------|----------|
123
+ | **One Word** | Each word = separate subtitle | High-energy, attention-grabbing content |
124
+ | **Two Word Punch** | Groups of 2 words | Punchy, impactful messaging |
125
+ | **Phrase Mode** | Full sentence segments | Traditional subtitle style |
126
+
127
+ ## 🎨 Web UI Preview
128
+
129
+ The web interface features a stunning **Neobrutalism** design:
130
+ - Bold black borders
131
+ - Vibrant color palette
132
+ - Sharp shadows
133
+ - Grid background pattern
134
+ - Smooth animations
135
+
136
+ ## 🐳 Docker Deployment
137
+
138
+ ```bash
139
+ # Build image
140
+ docker build -t oneword-ai .
141
+
142
+ # Run container
143
+ docker run -p 8000:8000 oneword-ai
144
+ ```
145
+
146
+ ## πŸ“ Project Structure
147
+
148
+ ```
149
+ minimalist-one-word-subtitle-generator/
150
+ β”œβ”€β”€ onewordai/ # Source code (package)
151
+ β”‚ β”œβ”€β”€ core/
152
+ β”‚ β”‚ β”œβ”€β”€ __init__.py
153
+ β”‚ β”‚ └── engine.py # Core subtitle generation logic
154
+ β”‚ β”œβ”€β”€ api/
155
+ β”‚ β”‚ β”œβ”€β”€ __init__.py
156
+ β”‚ β”‚ └── main.py # FastAPI backend
157
+ β”‚ └── web/
158
+ β”‚ β”œβ”€β”€ index.html # Web UI
159
+ β”‚ β”œβ”€β”€ style.css # Neobrutalism styles
160
+ β”‚ └── app.js # Frontend logic
161
+ β”œβ”€β”€ cli.py # CLI interface
162
+ β”œβ”€β”€ app_gradio.py # Gradio app for HF Spaces
163
+ β”œβ”€β”€ OneWord_Colab.ipynb # Google Colab notebook
164
+ β”œβ”€β”€ Dockerfile # Docker configuration
165
+ β”œβ”€β”€ requirements.txt # Python dependencies
166
+ └── README.md
167
+ ```
168
+
169
+ ## πŸ› οΈ Development
170
+
171
+ ### API Endpoints
172
+
173
+ - `POST /upload` - Upload video/audio file
174
+ - `POST /process` - Start transcription job
175
+ - `GET /status/{job_id}` - Check job progress
176
+ - `GET /download/{job_id}` - Download generated SRT
177
+
178
+ ### Requirements
179
+
180
+ - Python 3.8+
181
+ - FFmpeg
182
+ - PyTorch
183
+ - OpenAI Whisper
184
+ - FastAPI (for web server)
185
+ - Gradio (for HF Spaces)
186
+
187
+ ## πŸ’‘ Tips for Creators
188
+
189
+ ### Video Editing Workflow
190
+
191
+ 1. Generate SRT using OneWord AI
192
+ 2. Import into your editor:
193
+ - **CapCut**: Text β†’ Local Captions β†’ Upload
194
+ - **VN Editor**: Text β†’ SRT β†’ Import
195
+ - **Premiere Pro**: File β†’ Import β†’ Captions
196
+ 3. Apply animations (Pop, Spring, Bounce)
197
+ 4. Customize colors and fonts
198
+
199
+ ### Best Practices
200
+
201
+ - Use **Tiny** model for quick drafts
202
+ - Use **Base** model for production (best balance)
203
+ - Use **Small** model for technical/complex content
204
+ - **One Word** mode works best for 30-60 sec reels
205
+ - Enable language selection for multilingual content
206
+
207
+ ## 🀝 Contributing
208
+
209
+ Contributions welcome! Open an issue or submit a PR.
210
+
211
+ Ideas for improvements:
212
+ - Auto-capitalization for emphasis
213
+ - Color-coded keywords
214
+ - Export with burned-in subtitles
215
+ - Batch processing multiple files
216
+
217
+ ## πŸ“œ License
218
+
219
+ MIT License - see [license.txt](license.txt)
220
+
221
+ ## 🀝 Credits
222
+
223
+ - [OpenAI Whisper](https://github.com/openai/whisper) - Speech recognition
224
+ - [FastAPI](https://fastapi.tiangolo.com/) - Backend framework
225
+ - [Gradio](https://gradio.app/) - ML web interfaces
226
+
227
+ Built with ❀️ by [Ambrish](https://github.com/ambrish-yadav)
228
+
229
+ Follow for updates: [@ambrish.yadav.1](https://instagram.com/ambrish.yadav.1)
230
+
231
+ ---
232
+
233
+ <div align="center">
234
+
235
+ ⭐ Star this repo if you find it useful!
236
+
237
+ </div>
@@ -0,0 +1,15 @@
1
+ oneword_ai-0.1.0.dist-info/licenses/license.txt,sha256=ZlGk1ZMpgK_LQB1VTiN27JbvU-KL31byRxgM7wAmEu4,1060
2
+ onewordai/__init__.py,sha256=DW7ib3o1W0lchP960Mqdg_a-_aPPhPWgYKu5efR56ME,73
3
+ onewordai/cli.py,sha256=kz8epolGelaSfbOXdIB8IaiwUBLaKD8uyP6RBGOkCMM,2008
4
+ onewordai/api/__init__.py,sha256=W5bQNZGz2YLMXx1hC9e_eKhbf_GNFVYy3MC3D7gugUc,20
5
+ onewordai/api/main.py,sha256=QGyg4q72QkodF4HFAz6KOA8d3AlucisUB1OAw2XpANk,7964
6
+ onewordai/core/__init__.py,sha256=oTsOiTuWDAh1O6N9ZXfNFuiCmP3R99dBkEFljt3LI6Q,114
7
+ onewordai/core/engine.py,sha256=CqHVfvRjXSHgkjcPagYEhvCGwM2ywSlhyTvTran7MK0,15631
8
+ onewordai/web/app.js,sha256=mOp_RRear_N8RTpNEsYs2oj6mkji_AaKXlpxFsAtH-M,11166
9
+ onewordai/web/index.html,sha256=r1OSgeb35diHKmj1uWGnd-ltPBPz6aQp5mmcp2jTDmY,5995
10
+ onewordai/web/style.css,sha256=InsF-b_e5-zRhwaUHKf7cHnenNv87zA82VjcjqIsOnE,10485
11
+ oneword_ai-0.1.0.dist-info/METADATA,sha256=v5LBayOqcOffEvF6G7JXLumYGzdocKO1C5pzGy0ZeaE,7621
12
+ oneword_ai-0.1.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
13
+ oneword_ai-0.1.0.dist-info/entry_points.txt,sha256=qJ4u04rCiYtI5fCyPRBfTzW_-xc05BCSEct8YHzXX9Y,97
14
+ oneword_ai-0.1.0.dist-info/top_level.txt,sha256=otwwf_hwyKfUYUJnculUSznHz9iCFJRrHgIHyLQRbfE,10
15
+ oneword_ai-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.10.2)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ oneword-cli = onewordai.cli:main
3
+ oneword-web = onewordai.api.main:start_server
@@ -0,0 +1,7 @@
1
+ Copyright 2025 Ambrish
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the β€œSoftware”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED β€œAS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1 @@
1
+ onewordai
onewordai/__init__.py ADDED
@@ -0,0 +1,2 @@
1
+ """OneWord AI - Cinematic subtitle generator."""
2
+ __version__ = "2.0.0"
@@ -0,0 +1 @@
1
+ """API package."""
onewordai/api/main.py ADDED
@@ -0,0 +1,262 @@
1
+ """
2
+ FastAPI backend for OneWord AI Subtitle Generator.
3
+ Handles file uploads, transcription processing, and SRT downloads.
4
+ """
5
+ from fastapi import FastAPI, File, UploadFile, Form, HTTPException, BackgroundTasks
6
+ from fastapi.responses import FileResponse, JSONResponse
7
+ from fastapi.staticfiles import StaticFiles
8
+ from fastapi.middleware.cors import CORSMiddleware
9
+ from pathlib import Path
10
+ import uuid
11
+ import shutil
12
+ import asyncio
13
+ from typing import Optional, Dict
14
+ from datetime import datetime
15
+
16
+ from onewordai.core.engine import SubtitleGenerator
17
+
18
+ app = FastAPI(title="OneWord AI Subtitle Generator")
19
+
20
+ # CORS middleware
21
+ app.add_middleware(
22
+ CORSMiddleware,
23
+ allow_origins=["*"],
24
+ allow_credentials=True,
25
+ allow_methods=["*"],
26
+ allow_headers=["*"],
27
+ )
28
+
29
+ # Directories
30
+ UPLOAD_DIR = Path("uploads")
31
+ OUTPUT_DIR = Path("outputs")
32
+ UPLOAD_DIR.mkdir(exist_ok=True)
33
+ OUTPUT_DIR.mkdir(exist_ok=True)
34
+
35
+ # Job storage (in-memory, replace with Redis for production)
36
+ jobs: Dict[str, dict] = {}
37
+
38
+
39
+ class JobStatus:
40
+ PENDING = "pending"
41
+ PROCESSING = "processing"
42
+ COMPLETED = "completed"
43
+ FAILED = "failed"
44
+ CANCELLED = "cancelled"
45
+
46
+
47
+ def process_video_task(
48
+ job_id: str,
49
+ input_path: str,
50
+ model: str,
51
+ language: Optional[str],
52
+ mode: str
53
+ ):
54
+ """Background task to process video."""
55
+ try:
56
+ jobs[job_id]["status"] = JobStatus.PROCESSING
57
+ jobs[job_id]["progress"] = 0
58
+
59
+ # Create generator
60
+ generator = SubtitleGenerator(model_name=model)
61
+
62
+ # Process
63
+ output_path = OUTPUT_DIR / f"{job_id}.srt"
64
+
65
+ def progress_callback(percent):
66
+ jobs[job_id]["progress"] = percent
67
+
68
+ def status_callback(msg):
69
+ jobs[job_id]["status_message"] = msg
70
+
71
+ generator.process(
72
+ input_path=input_path,
73
+ output_path=str(output_path),
74
+ language=language,
75
+ mode=mode,
76
+ progress_callback=progress_callback,
77
+ status_callback=status_callback
78
+ )
79
+
80
+ jobs[job_id]["status"] = JobStatus.COMPLETED
81
+ jobs[job_id]["progress"] = 100
82
+ jobs[job_id]["output_file"] = str(output_path)
83
+ jobs[job_id]["completed_at"] = datetime.now().isoformat()
84
+
85
+ except Exception as e:
86
+ jobs[job_id]["status"] = JobStatus.FAILED
87
+ jobs[job_id]["error"] = str(e)
88
+ print(f"❌ Job {job_id} failed: {e}")
89
+
90
+
91
+
92
+ @app.get("/api/health")
93
+ async def health_check():
94
+ """Health check."""
95
+ return {"status": "ok", "service": "OneWord AI Subtitle Generator"}
96
+
97
+
98
+ @app.post("/api/upload")
99
+ async def upload_file(file: UploadFile = File(...)):
100
+ """
101
+ Upload a video/audio file.
102
+ Returns a file_id for use in processing.
103
+ """
104
+ if not file.filename:
105
+ raise HTTPException(status_code=400, detail="No file provided")
106
+
107
+ # Generate unique file ID
108
+ file_id = str(uuid.uuid4())
109
+ file_ext = Path(file.filename).suffix
110
+ file_path = UPLOAD_DIR / f"{file_id}{file_ext}"
111
+
112
+ # Save file
113
+ with file_path.open("wb") as buffer:
114
+ shutil.copyfileobj(file.file, buffer)
115
+
116
+ return {
117
+ "file_id": file_id,
118
+ "filename": file.filename,
119
+ "size": file_path.stat().st_size
120
+ }
121
+
122
+
123
+ @app.post("/api/process")
124
+ async def process_file(
125
+ background_tasks: BackgroundTasks,
126
+ file_id: str = Form(...),
127
+ model: str = Form("medium"),
128
+ language: Optional[str] = Form(None),
129
+ mode: str = Form("oneword")
130
+ ):
131
+ """
132
+ Start processing a previously uploaded file.
133
+ Returns a job_id to track progress.
134
+ """
135
+ # Find uploaded file
136
+ uploaded_files = list(UPLOAD_DIR.glob(f"{file_id}.*"))
137
+ if not uploaded_files:
138
+ raise HTTPException(status_code=404, detail="File not found")
139
+
140
+ input_path = str(uploaded_files[0])
141
+
142
+ # Validate inputs
143
+ allowed_models = ["medium", "large", "Oriserve/Whisper-Hindi2Hinglish-Prime"]
144
+ if model not in allowed_models:
145
+ raise HTTPException(status_code=400, detail="Invalid model")
146
+
147
+ if language and language not in ["hi", "en", "ur", "es"]:
148
+ raise HTTPException(status_code=400, detail="Invalid language")
149
+
150
+ if mode not in ["oneword", "twoword", "phrase"]:
151
+ raise HTTPException(status_code=400, detail="Invalid mode")
152
+
153
+ # Create job
154
+ job_id = str(uuid.uuid4())
155
+ jobs[job_id] = {
156
+ "job_id": job_id,
157
+ "file_id": file_id,
158
+ "status": JobStatus.PENDING,
159
+ "progress": 0,
160
+ "status_message": "πŸ“¦ Checking model... (First-time download ~1.5GB)" if "/" in model else "πŸš€ Preparing to transcribe...",
161
+ "model": model,
162
+ "language": language,
163
+ "mode": mode,
164
+ "created_at": datetime.now().isoformat()
165
+ }
166
+
167
+ # Start background task
168
+ background_tasks.add_task(
169
+ process_video_task,
170
+ job_id, input_path, model, language, mode
171
+ )
172
+
173
+ return {"job_id": job_id}
174
+
175
+
176
+ @app.get("/api/status/{job_id}")
177
+ async def get_status(job_id: str):
178
+ """Get processing status for a job."""
179
+ if job_id not in jobs:
180
+ raise HTTPException(status_code=404, detail="Job not found")
181
+
182
+ return jobs[job_id]
183
+
184
+
185
+ @app.get("/api/download/{job_id}")
186
+ async def download_srt(job_id: str):
187
+ """Download the generated SRT file."""
188
+ if job_id not in jobs:
189
+ raise HTTPException(status_code=404, detail="Job not found")
190
+
191
+ job = jobs[job_id]
192
+
193
+ if job["status"] != JobStatus.COMPLETED:
194
+ raise HTTPException(status_code=400, detail="Job not completed yet")
195
+
196
+ output_file = Path(job["output_file"])
197
+ if not output_file.exists():
198
+ raise HTTPException(status_code=404, detail="Output file not found")
199
+
200
+ return FileResponse(
201
+ output_file,
202
+ media_type="application/x-subrip",
203
+ filename=f"subtitles_{job['mode']}.srt"
204
+ )
205
+
206
+
207
+ @app.post("/api/cancel/{job_id}")
208
+ async def cancel_job(job_id: str):
209
+ """Cancel a running job."""
210
+ if job_id not in jobs:
211
+ raise HTTPException(status_code=404, detail="Job not found")
212
+
213
+ job = jobs[job_id]
214
+
215
+ # Only cancel if still processing
216
+ if job["status"] in [JobStatus.PENDING, JobStatus.PROCESSING]:
217
+ jobs[job_id]["status"] = JobStatus.CANCELLED
218
+ jobs[job_id]["status_message"] = "❌ Cancelled by user"
219
+ return {"message": "Job cancelled successfully"}
220
+ else:
221
+ return {"message": f"Job already {job['status']}"}
222
+
223
+
224
+ # Mount static files (web UI) at root
225
+ try:
226
+ # Try resolving relative to package install location
227
+ package_root = Path(__file__).parent.parent
228
+ web_dir = package_root / "web"
229
+
230
+ if not web_dir.exists():
231
+ # Fallback for local development if running from root
232
+ web_dir = Path("onewordai/web")
233
+
234
+ app.mount("/", StaticFiles(directory=str(web_dir), html=True), name="web")
235
+ except Exception as e:
236
+ print(f"⚠️ Warning: Could not mount web UI: {e}")
237
+
238
+
239
+ if __name__ == "__main__":
240
+ import uvicorn
241
+ print("\n✨ OneWord AI running at: http://localhost:8000\n")
242
+ uvicorn.run(app, host="0.0.0.0", port=8000)
243
+
244
+ # Entry point for package
245
+ def start_server():
246
+ """Start the web server (used by oneword-web command)."""
247
+ import uvicorn
248
+ import webbrowser
249
+ import threading
250
+ import time
251
+
252
+ def open_browser():
253
+ time.sleep(2)
254
+ print("πŸš€ Opening browser at http://localhost:8000")
255
+ webbrowser.open("http://localhost:8000")
256
+
257
+ threading.Thread(target=open_browser, daemon=True).start()
258
+
259
+ # Run server
260
+ print("✨ Starting OneWord AI Web Server...")
261
+ # Use reload=False for production package usage
262
+ uvicorn.run("onewordai.api.main:app", host="0.0.0.0", port=8000, reload=False)
onewordai/cli.py ADDED
@@ -0,0 +1,67 @@
1
+ """
2
+ CLI interface for OneWord AI Subtitle Generator.
3
+ """
4
+ import argparse
5
+ from pathlib import Path
6
+ from .core.engine import SubtitleGenerator
7
+
8
+
9
+ def main():
10
+ parser = argparse.ArgumentParser(
11
+ description="OneWord AI - Generate cinematic one-word subtitles using Whisper"
12
+ )
13
+ parser.add_argument(
14
+ "-i", "--input",
15
+ required=True,
16
+ help="Path to input video/audio file"
17
+ )
18
+ parser.add_argument(
19
+ "-m", "--model",
20
+ default="medium",
21
+ choices=["medium", "large", "Oriserve/Whisper-Hindi2Hinglish-Prime"], help="Whisper model to use (default: medium)"
22
+ )
23
+ parser.add_argument(
24
+ "-lang", "--language",
25
+ default=None,
26
+ choices=["hi", "en", "ur", "es"],
27
+ help="Language code (hi=Hindi, en=English, ur=Urdu, es=Spanish). Auto-detect if not specified."
28
+ )
29
+ parser.add_argument(
30
+ "-mode", "--mode",
31
+ default="oneword",
32
+ choices=["oneword", "twoword", "phrase"],
33
+ help="Subtitle mode: oneword (default), twoword (punch effect), phrase (full segment)"
34
+ )
35
+ parser.add_argument(
36
+ "-o", "--output",
37
+ help="Output SRT file path (optional, auto-generated if not specified)"
38
+ )
39
+
40
+ args = parser.parse_args()
41
+
42
+ # Validate input file
43
+ input_path = Path(args.input)
44
+ if not input_path.exists():
45
+ print(f"❌ Error: Input file '{args.input}' not found.")
46
+ return 1
47
+
48
+ # Create generator
49
+ generator = SubtitleGenerator(model_name=args.model)
50
+
51
+ # Process
52
+ try:
53
+ output_file = generator.process(
54
+ input_path=str(input_path),
55
+ output_path=args.output,
56
+ language=args.language,
57
+ mode=args.mode
58
+ )
59
+ print(f"\nπŸŽ‰ Done! SRT file: {output_file}")
60
+ return 0
61
+ except Exception as e:
62
+ print(f"\n❌ Error: {e}")
63
+ return 1
64
+
65
+
66
+ if __name__ == "__main__":
67
+ exit(main())
@@ -0,0 +1,4 @@
1
+ """Core subtitle generation engine."""
2
+ from .engine import SubtitleGenerator
3
+
4
+ __all__ = ["SubtitleGenerator"]