superbrain-server 1.0.2-beta.0

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.
Files changed (39) hide show
  1. package/bin/superbrain.js +196 -0
  2. package/package.json +23 -0
  3. package/payload/.dockerignore +45 -0
  4. package/payload/.env.example +58 -0
  5. package/payload/Dockerfile +73 -0
  6. package/payload/analyzers/__init__.py +0 -0
  7. package/payload/analyzers/audio_transcribe.py +225 -0
  8. package/payload/analyzers/caption.py +244 -0
  9. package/payload/analyzers/music_identifier.py +346 -0
  10. package/payload/analyzers/text_analyzer.py +117 -0
  11. package/payload/analyzers/visual_analyze.py +218 -0
  12. package/payload/analyzers/webpage_analyzer.py +789 -0
  13. package/payload/analyzers/youtube_analyzer.py +320 -0
  14. package/payload/api.py +1676 -0
  15. package/payload/config/.api_keys.example +22 -0
  16. package/payload/config/model_rankings.json +492 -0
  17. package/payload/config/openrouter_free_models.json +1364 -0
  18. package/payload/config/whisper_model.txt +1 -0
  19. package/payload/config_settings.py +185 -0
  20. package/payload/core/__init__.py +0 -0
  21. package/payload/core/category_manager.py +219 -0
  22. package/payload/core/database.py +811 -0
  23. package/payload/core/link_checker.py +300 -0
  24. package/payload/core/model_router.py +1253 -0
  25. package/payload/docker-compose.yml +120 -0
  26. package/payload/instagram/__init__.py +0 -0
  27. package/payload/instagram/instagram_downloader.py +253 -0
  28. package/payload/instagram/instagram_login.py +190 -0
  29. package/payload/main.py +912 -0
  30. package/payload/requirements.txt +39 -0
  31. package/payload/reset.py +311 -0
  32. package/payload/start-docker-prod.sh +125 -0
  33. package/payload/start-docker.sh +56 -0
  34. package/payload/start.py +1302 -0
  35. package/payload/static/favicon.ico +0 -0
  36. package/payload/stop-docker.sh +16 -0
  37. package/payload/utils/__init__.py +0 -0
  38. package/payload/utils/db_stats.py +108 -0
  39. package/payload/utils/manage_token.py +91 -0
@@ -0,0 +1,196 @@
1
+ #!/usr/bin/env node
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const os = require('os');
5
+ const { spawnSync, spawn } = require('child_process');
6
+
7
+ const pkgMeta = require('../package.json');
8
+ const TARGET_DIR = path.join(os.homedir(), '.superbrain-server');
9
+ const PAYLOAD_DIR = path.join(__dirname, '../payload');
10
+
11
+ // Files that should NEVER be overwritten during an unpack/upgrade if they already exist in the target
12
+ const PROTECTED_FILES = [
13
+ 'superbrain.db',
14
+ 'superbrain.db-shm',
15
+ 'superbrain.db-wal',
16
+ 'token.txt',
17
+ '.env',
18
+ '.api_keys',
19
+ 'localtunnel.log',
20
+ 'localtunnel_enabled.txt',
21
+ '.setup_done',
22
+ 'config/instagram_session.json',
23
+ 'config/.api_keys',
24
+ 'config/localtunnel_enabled.txt',
25
+ 'config/localtunnel.log'
26
+ ];
27
+
28
+ function log(msg) {
29
+ console.log(`\x1b[36m✨ [SuperBrain CLI]\x1b[0m ${msg}`);
30
+ }
31
+
32
+ function warn(msg) {
33
+ console.log(`\x1b[33m⚠️ [SuperBrain CLI]\x1b[0m ${msg}`);
34
+ }
35
+
36
+ function errorOut(msg) {
37
+ console.log(`\x1b[31m❌ [SuperBrain CLI]\x1b[0m ${msg}`);
38
+ process.exit(1);
39
+ }
40
+
41
+ function parsePythonVersion(rawText) {
42
+ const match = (rawText || '').match(/Python\s+(\d+)\.(\d+)\.(\d+)/i);
43
+ if (!match) return null;
44
+ return {
45
+ major: Number(match[1]),
46
+ minor: Number(match[2]),
47
+ patch: Number(match[3]),
48
+ };
49
+ }
50
+
51
+ function isSupportedPython(version) {
52
+ if (!version) return false;
53
+ if (version.major > 3) return true;
54
+ return version.major === 3 && version.minor >= 10;
55
+ }
56
+
57
+ // Check if Python binaries are accessible
58
+ function getPythonCommand() {
59
+ const candidates = os.platform() === 'win32'
60
+ ? [
61
+ { cmd: 'py', args: ['-3', '--version'], execPrefix: ['-3'] },
62
+ { cmd: 'python', args: ['--version'], execPrefix: [] },
63
+ { cmd: 'python3', args: ['--version'], execPrefix: [] },
64
+ ]
65
+ : [
66
+ { cmd: 'python3', args: ['--version'], execPrefix: [] },
67
+ { cmd: 'python', args: ['--version'], execPrefix: [] },
68
+ ];
69
+
70
+ for (const candidate of candidates) {
71
+ try {
72
+ const res = spawnSync(candidate.cmd, candidate.args, { encoding: 'utf-8', timeout: 5000 });
73
+ const combinedOutput = `${res.stdout || ''}\n${res.stderr || ''}`.trim();
74
+ const version = parsePythonVersion(combinedOutput);
75
+
76
+ if (res.status === 0 && isSupportedPython(version)) {
77
+ return {
78
+ command: candidate.cmd,
79
+ execPrefix: candidate.execPrefix,
80
+ version,
81
+ };
82
+ }
83
+ } catch (e) {
84
+ // Command missing
85
+ }
86
+ }
87
+ return null;
88
+ }
89
+
90
+ function safeUnpack() {
91
+ if (!fs.existsSync(TARGET_DIR)) {
92
+ fs.mkdirSync(TARGET_DIR, { recursive: true });
93
+ }
94
+
95
+ log(`Unpacking server core to ${TARGET_DIR} ...`);
96
+
97
+ // Recursively copy files from payload
98
+ function copyRecursive(src, dest) {
99
+ const stat = fs.statSync(src);
100
+ if (stat.isDirectory()) {
101
+ if (!fs.existsSync(dest)) fs.mkdirSync(dest);
102
+ for (const child of fs.readdirSync(src)) {
103
+ copyRecursive(path.join(src, child), path.join(dest, child));
104
+ }
105
+ } else {
106
+ // It's a file
107
+ const relativePath = path.relative(TARGET_DIR, dest).replace(/\\/g, '/');
108
+ const isProtected = PROTECTED_FILES.includes(relativePath);
109
+
110
+ if (isProtected && fs.existsSync(dest)) {
111
+ // Skip overwriting user's database or tokens
112
+ return;
113
+ }
114
+ fs.copyFileSync(src, dest);
115
+ }
116
+ }
117
+
118
+ if (!fs.existsSync(PAYLOAD_DIR)) {
119
+ errorOut("Payload directory missing inside npm package!");
120
+ }
121
+
122
+ copyRecursive(PAYLOAD_DIR, TARGET_DIR);
123
+
124
+ // Write out version explicitly
125
+ fs.writeFileSync(path.join(TARGET_DIR, 'VERSION'), pkgMeta.version, 'utf-8');
126
+ log(`Extraction complete (v${pkgMeta.version}). Data persisted cleanly.`);
127
+ }
128
+
129
+ function checkUpgrades() {
130
+ const versionFile = path.join(TARGET_DIR, 'VERSION');
131
+ let currentVersion = '0.0.0';
132
+ if (fs.existsSync(versionFile)) {
133
+ currentVersion = fs.readFileSync(versionFile, 'utf-8').trim();
134
+ }
135
+
136
+ if (currentVersion !== pkgMeta.version) {
137
+ log(`Version mismatch detected (Local: ${currentVersion} -> NPM: ${pkgMeta.version}). Auto-upgrading...`);
138
+ safeUnpack();
139
+ }
140
+ }
141
+
142
+ // ─────────────────────────────────────────────────────────────────────────────
143
+ // EXECUTOR
144
+ // ─────────────────────────────────────────────────────────────────────────────
145
+
146
+ // 1. Python check
147
+ const pythonInfo = getPythonCommand();
148
+ if (!pythonInfo) {
149
+ errorOut('Could not find Python >= 3.10 on this system. Please install Python 3.10+ to run SuperBrain.');
150
+ }
151
+
152
+ // 2. Safe unpack/upgrade
153
+ checkUpgrades();
154
+
155
+ // 3. Command Routing logic
156
+ const userArgs = process.argv.slice(2);
157
+ let targetScript = 'start.py';
158
+ let finalArgs = userArgs;
159
+
160
+ if (userArgs.length > 0) {
161
+ const cmd = userArgs[0].toLowerCase();
162
+ if (cmd === 'reset') {
163
+ targetScript = 'reset.py';
164
+ finalArgs = userArgs.slice(1); // remove 'reset' from arguments passed to python
165
+ } else if (cmd === '-h' || cmd === '--help') {
166
+ console.log(`
167
+ SuperBrain Server Wrapper (v${pkgMeta.version})
168
+
169
+ Usage:
170
+ superbrain-server -> Starts the backend engine
171
+ superbrain-server reset -> Open Reset Menu
172
+ superbrain-server reset --all -> Force complete wipe
173
+ `);
174
+ process.exit(0);
175
+ }
176
+ }
177
+
178
+ // 4. Execution
179
+ log(`Spinning up Python Engine via ${targetScript} (Python ${pythonInfo.version.major}.${pythonInfo.version.minor}.${pythonInfo.version.patch})...`);
180
+ const child = spawn(pythonInfo.command, [...pythonInfo.execPrefix, targetScript, ...finalArgs], {
181
+ cwd: TARGET_DIR,
182
+ stdio: 'inherit'
183
+ });
184
+
185
+ // 5. Zombie Protection
186
+ function handleShutdown(signal) {
187
+ warn(`Received ${signal}. Shutting down Python engine...`);
188
+ child.kill('SIGINT');
189
+ }
190
+
191
+ process.on('SIGINT', () => handleShutdown('SIGINT'));
192
+ process.on('SIGTERM', () => handleShutdown('SIGTERM'));
193
+
194
+ child.on('close', (code) => {
195
+ process.exit(code || 0);
196
+ });
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "superbrain-server",
3
+ "version": "1.0.2-beta.0",
4
+ "description": "1-Line Auto-Installer and Server Execution wrapper for SuperBrain",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "superbrain-server": "bin/superbrain.js"
8
+ },
9
+ "scripts": {
10
+ "build": "node scripts/build.js"
11
+ },
12
+ "keywords": [
13
+ "superbrain",
14
+ "server"
15
+ ],
16
+ "author": "sidinsearch",
17
+ "license": "MIT",
18
+ "dependencies": {},
19
+ "files": [
20
+ "bin/",
21
+ "payload/"
22
+ ]
23
+ }
@@ -0,0 +1,45 @@
1
+ # Git and local metadata
2
+ .git
3
+ .gitignore
4
+
5
+ # Python caches and virtual environments
6
+ .venv
7
+ venv
8
+ __pycache__
9
+ *.pyc
10
+ *.pyo
11
+ *.pyd
12
+ .pytest_cache
13
+ .mypy_cache
14
+
15
+ # Local runtime data
16
+ superbrain.db
17
+ superbrain.db-shm
18
+ superbrain.db-wal
19
+ token.txt
20
+ .setup_done
21
+ .env
22
+ *.env
23
+
24
+ # Secrets/config generated at runtime
25
+ .api_keys
26
+ config/.api_keys
27
+ config/ngrok_token.txt
28
+ config/test_credentials.txt
29
+ config/localtunnel.log
30
+
31
+ # Logs and transient artifacts
32
+ logs/
33
+ temp/
34
+ error_log_utf8.txt
35
+ failures.txt
36
+ final_test.txt
37
+ test_results.txt
38
+ yt_error.txt
39
+ err.json
40
+
41
+ # Build outputs
42
+ *.apk
43
+
44
+ # Optional local uploads
45
+ static/uploads/
@@ -0,0 +1,58 @@
1
+ # ────────────────────────────────────────────────────────────────────────────────
2
+ # SuperBrain Environment Configuration Template
3
+ # ────────────────────────────────────────────────────────────────────────────────
4
+ # Copy this file to .env and fill in your actual values
5
+ # NEVER commit .env file to version control
6
+ # ────────────────────────────────────────────────────────────────────────────────
7
+
8
+ # ──── Application Settings ────
9
+ ENVIRONMENT=production
10
+ DEBUG=false
11
+ LOG_LEVEL=INFO
12
+
13
+ # ──── Server Configuration ────
14
+ HOST=0.0.0.0
15
+ PORT=5000
16
+ WORKERS=4
17
+ API_PORT=5000
18
+
19
+ # ──── Database Configuration ────
20
+ DATABASE_PATH=superbrain.db
21
+ DATABASE_TIMEOUT=30
22
+
23
+ # ──── AI Provider API Keys ────
24
+ # Get these from the respective provider accounts
25
+ GROQ_API_KEY=
26
+ GEMINI_API_KEY=
27
+ OPENROUTER_API_KEY=
28
+
29
+ # ──── Whisper Configuration ────
30
+ # Options: tiny, base, small, medium, large
31
+ WHISPER_MODEL=base
32
+ WHISPER_USE_CLOUD=true
33
+
34
+ # ──── Instagram Credentials ────
35
+ # Use a bot account or app-specific credentials, NOT your personal account
36
+ INSTAGRAM_USERNAME=
37
+ INSTAGRAM_PASSWORD=
38
+
39
+ # ──── File Upload Configuration ────
40
+ MAX_UPLOAD_SIZE=52428800
41
+ UPLOAD_DIR=static/uploads
42
+ TEMP_DIR=temp
43
+
44
+ # ──── Request Timeout Settings ────
45
+ REQUEST_TIMEOUT=60
46
+ ANALYSIS_TIMEOUT=120
47
+ MAX_RETRIES=3
48
+ RETRY_DELAY=5
49
+
50
+ # ──── Feature Flags ────
51
+ ENABLE_METRICS=true
52
+ ENABLE_HEALTH_CHECK=true
53
+ ENABLE_API_DOCS=false
54
+
55
+ # ────────────────────────────────────────────────────────────────────────────────
56
+ # NOTE: Update only the values you need
57
+ # Leave blank if optional or use defaults
58
+ # ────────────────────────────────────────────────────────────────────────────────
@@ -0,0 +1,73 @@
1
+ # ────────────────────────────────────────────────────────────────────────────────
2
+ # Multi-stage build for optimized image size
3
+ # ────────────────────────────────────────────────────────────────────────────────
4
+
5
+ FROM python:3.11-slim as builder
6
+
7
+ WORKDIR /app
8
+
9
+ # Install system build dependencies
10
+ RUN apt-get update && apt-get install -y --no-install-recommends \
11
+ gcc \
12
+ && rm -rf /var/lib/apt/lists/*
13
+
14
+ # Copy requirements
15
+ COPY requirements.txt .
16
+
17
+ # Build dependencies in separate layer
18
+ RUN pip install --user --no-cache-dir -r requirements.txt
19
+
20
+
21
+ # ────────────────────────────────────────────────────────────────────────────────
22
+ # Final production image
23
+ # ────────────────────────────────────────────────────────────────────────────────
24
+
25
+ FROM python:3.11-slim
26
+
27
+ LABEL maintainer="SuperBrain <sidinsearch@gmail.com>"
28
+ LABEL description="SuperBrain API - AI-powered content analysis and archival"
29
+ LABEL version="1.0.0"
30
+
31
+ WORKDIR /app
32
+
33
+ # ──── Install runtime dependencies only ────
34
+ RUN apt-get update && apt-get install -y --no-install-recommends \
35
+ ffmpeg \
36
+ libmagic1 \
37
+ libgl1-mesa-glx \
38
+ libglib2.0-0 \
39
+ curl \
40
+ && rm -rf /var/lib/apt/lists/*
41
+
42
+ # ──── Copy Python dependencies from builder ────
43
+ COPY --from=builder /root/.local /root/.local
44
+
45
+ # ──── Set environment variables ────
46
+ ENV PATH=/root/.local/bin:$PATH \
47
+ PYTHONUNBUFFERED=1 \
48
+ PYTHONDONTWRITEBYTECODE=1 \
49
+ ENVIRONMENT=production \
50
+ WORKERS=2
51
+
52
+ # ──── Copy application code ────
53
+ COPY . .
54
+
55
+ # ──── Create necessary directories with proper permissions ────
56
+ RUN mkdir -p temp config static logs data && \
57
+ chmod 755 temp config static logs data
58
+
59
+ # ──── Health check ────
60
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
61
+ CMD curl -f http://localhost:5000/health || exit 1
62
+
63
+ # ──── Run as non-root user for security ────
64
+ RUN useradd -m -u 1000 appuser && \
65
+ chown -R appuser:appuser /app
66
+
67
+ USER appuser
68
+
69
+ # ──── Expose port ────
70
+ EXPOSE 5000
71
+
72
+ # ──── Run the application ────
73
+ CMD ["sh", "-c", "python -m uvicorn api:app --host 0.0.0.0 --port 5000 --workers ${WORKERS:-2} --loop uvloop --no-access-log"]
File without changes
@@ -0,0 +1,225 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Audio Transcriber — Multi-language Support
4
+ Primary: Groq Whisper API (whisper-large-v3-turbo → whisper-large-v3)
5
+ Fallback: Local OpenAI Whisper (model from config/whisper_model.txt, default: base)
6
+ """
7
+
8
+ import os
9
+ import sys
10
+ from pathlib import Path
11
+
12
+ # ── API key loader (mirrors model_router.py) ─────────────────────────────────
13
+
14
+ _CONFIG_DIR = Path(__file__).resolve().parent.parent / "config"
15
+
16
+
17
+ def _load_local_model() -> str:
18
+ """Return the Whisper model name saved by start.py, defaulting to 'base'."""
19
+ cfg = _CONFIG_DIR / "whisper_model.txt"
20
+ if cfg.exists():
21
+ model = cfg.read_text().strip()
22
+ if model:
23
+ return model
24
+ return "base"
25
+
26
+
27
+ def _load_groq_key():
28
+ key = os.environ.get("GROQ_API_KEY")
29
+ if key:
30
+ return key
31
+ keys_file = _CONFIG_DIR / ".api_keys"
32
+ if keys_file.exists():
33
+ for line in keys_file.read_text(encoding="utf-8").splitlines():
34
+ line = line.strip()
35
+ if line.startswith("GROQ_API_KEY="):
36
+ v = line.split("=", 1)[1].strip()
37
+ return v or None
38
+ return None
39
+
40
+
41
+ LANGUAGE_NAMES = {
42
+ "en": "English", "hi": "Hindi", "es": "Spanish", "fr": "French",
43
+ "de": "German", "it": "Italian", "pt": "Portuguese", "ru": "Russian",
44
+ "ja": "Japanese", "ko": "Korean", "zh": "Chinese", "ar": "Arabic",
45
+ "tr": "Turkish", "vi": "Vietnamese", "th": "Thai", "id": "Indonesian",
46
+ "nl": "Dutch", "pl": "Polish", "uk": "Ukrainian", "bn": "Bengali",
47
+ "ta": "Tamil", "te": "Telugu", "mr": "Marathi", "gu": "Gujarati",
48
+ "kn": "Kannada", "ml": "Malayalam", "pa": "Punjabi", "ur": "Urdu",
49
+ }
50
+
51
+ VALID_EXTENSIONS = {".mp3", ".wav", ".m4a", ".ogg", ".flac", ".aac", ".webm", ".mp4"}
52
+
53
+ # Groq Whisper API max file size (25 MB)
54
+ GROQ_MAX_BYTES = 25 * 1024 * 1024
55
+
56
+
57
+ # ── Transcription backends ────────────────────────────────────────────────────
58
+
59
+ def _transcribe_groq(audio_path, api_key):
60
+ """
61
+ Transcribe using Groq Whisper API.
62
+ Tries whisper-large-v3-turbo first (fast, multilingual),
63
+ then whisper-large-v3 (highest accuracy).
64
+ Returns (text, language_code). Raises on failure.
65
+ """
66
+ from groq import Groq
67
+
68
+ client = Groq(api_key=api_key)
69
+
70
+ file_size = audio_path.stat().st_size
71
+ if file_size > GROQ_MAX_BYTES:
72
+ raise ValueError(
73
+ f"File too large for Groq API ({file_size / 1024 / 1024:.1f} MB > 25 MB). "
74
+ "Using local fallback."
75
+ )
76
+
77
+ models = [
78
+ ("whisper-large-v3-turbo", "fast multilingual"),
79
+ ("whisper-large-v3", "highest accuracy"),
80
+ ]
81
+
82
+ last_err = None
83
+ for model_id, label in models:
84
+ try:
85
+ print(f" 🌐 Groq Whisper [{label}] …")
86
+ with open(audio_path, "rb") as f:
87
+ response = client.audio.transcriptions.create(
88
+ model=model_id,
89
+ file=(audio_path.name, f),
90
+ response_format="verbose_json",
91
+ )
92
+ text = (response.text or "").strip()
93
+ lang = getattr(response, "language", None) or "unknown"
94
+ return text, lang
95
+ except Exception as e:
96
+ print(f" ⚠️ Groq {model_id} failed: {e}")
97
+ last_err = e
98
+
99
+ raise RuntimeError(f"All Groq Whisper models failed. Last error: {last_err}")
100
+
101
+
102
+ def _transcribe_local(audio_path):
103
+ """
104
+ Transcribe using local OpenAI Whisper.
105
+ Model is read from config/whisper_model.txt (set by start.py), default 'base'.
106
+ Returns (text, language_code).
107
+ """
108
+ import whisper # type: ignore
109
+
110
+ model_name = _load_local_model()
111
+ print(f" 💻 Loading local Whisper model ({model_name}) …")
112
+ model = whisper.load_model(model_name)
113
+ print(" ✓ Local model loaded")
114
+
115
+ result = model.transcribe(
116
+ str(audio_path),
117
+ fp16=False,
118
+ task="transcribe",
119
+ verbose=False,
120
+ )
121
+ text = result["text"].strip()
122
+ lang = result.get("language", "unknown")
123
+ return text, lang
124
+
125
+
126
+ # ── Main entry point ──────────────────────────────────────────────────────────
127
+
128
+ def transcribe_audio(audio_path):
129
+ """Transcribe audio file — Groq Whisper primary, local Whisper fallback."""
130
+
131
+ print("=" * 70)
132
+ print("🎙️ AUDIO TRANSCRIBER — Multi-Language (Groq → Local fallback)")
133
+ print("=" * 70)
134
+ print()
135
+
136
+ path = Path(audio_path)
137
+ if not path.exists():
138
+ print(f"❌ File not found: {audio_path}")
139
+ return
140
+
141
+ if path.suffix.lower() not in VALID_EXTENSIONS:
142
+ print(f"❌ Unsupported file type: {path.suffix}")
143
+ print(f" Supported: {', '.join(sorted(VALID_EXTENSIONS))}")
144
+ return
145
+
146
+ print(f"🎧 File: {path.name} ({path.stat().st_size / 1024:.1f} KB)")
147
+ print()
148
+
149
+ text = ""
150
+ lang_code = "unknown"
151
+ backend_used = ""
152
+
153
+ # ── 1. Try Groq Whisper API ───────────────────────────────────────────────
154
+ api_key = _load_groq_key()
155
+ if api_key:
156
+ try:
157
+ text, lang_code = _transcribe_groq(path, api_key)
158
+ backend_used = "Groq Whisper API"
159
+ except Exception as e:
160
+ print(f" ⚠️ Groq transcription failed: {e}")
161
+ print(" 🔁 Falling back to local Whisper …")
162
+ print()
163
+ else:
164
+ print(" ℹ️ GROQ_API_KEY not set — using local Whisper directly")
165
+ print()
166
+
167
+ # ── 2. Local Whisper fallback ─────────────────────────────────────────────
168
+ if not text:
169
+ try:
170
+ text, lang_code = _transcribe_local(path)
171
+ backend_used = f"Local Whisper ({_load_local_model()})"
172
+ except Exception as e:
173
+ print(f"❌ Local Whisper also failed: {e}")
174
+ import traceback
175
+ traceback.print_exc()
176
+ return
177
+
178
+ # ── Print results ─────────────────────────────────────────────────────────
179
+ lang_name = LANGUAGE_NAMES.get(lang_code, lang_code.title())
180
+
181
+ print()
182
+ print("=" * 70)
183
+ print("📊 TRANSCRIPTION RESULTS")
184
+ print("=" * 70)
185
+ print()
186
+ print(f"🔧 Backend: {backend_used}")
187
+ print(f"🌍 Detected Language: {lang_name} ({lang_code})")
188
+ print()
189
+ print("📝 TRANSCRIBED TEXT:")
190
+ print("-" * 70)
191
+ print(text)
192
+ print("-" * 70)
193
+ print()
194
+ print(f"ℹ️ Words: {len(text.split())}")
195
+ print()
196
+ print("=" * 70)
197
+ print("✅ Transcription complete!")
198
+ print("=" * 70)
199
+
200
+
201
+ def main():
202
+ """CLI entry point."""
203
+ if len(sys.argv) > 1:
204
+ audio_path = sys.argv[1]
205
+ else:
206
+ print("=" * 70)
207
+ print("🎙️ AUDIO TRANSCRIBER — Multi-Language")
208
+ print("=" * 70)
209
+ print()
210
+ print("Supports: English, Hindi, Spanish, French, German, Italian,")
211
+ print(" Portuguese, Russian, Japanese, Korean, Chinese, Arabic,")
212
+ print(" and 85+ more languages!")
213
+ print()
214
+ audio_path = input("📂 Enter audio file path: ").strip()
215
+
216
+ audio_path = audio_path.strip('"').strip("'").strip()
217
+ if not audio_path:
218
+ print("❌ No path provided!")
219
+ return
220
+
221
+ transcribe_audio(audio_path)
222
+
223
+
224
+ if __name__ == "__main__":
225
+ main()