Skip to content

Commit 0d3d9ce

Browse files
committed
Update ASR services setup with new dependencies and configuration
- Consolidated dependencies into a single setup-requirements.txt for Friend-Lite setup scripts. - Updated command paths in wizard.py to reference the new location of setup-requirements.txt. - Added support for PYTORCH_CUDA_VERSION in asr-services to enhance compatibility. - Introduced init.py for interactive configuration of the ASR service. - Removed outdated setup-requirements.txt files from advanced and speaker-recognition services. - Updated docker-compose.yml files to use the new PYTORCH_CUDA_VERSION variable.
1 parent ab506dc commit 0d3d9ce

File tree

11 files changed

+2900
-242
lines changed

11 files changed

+2900
-242
lines changed

backends/advanced/setup-requirements.txt

Lines changed: 0 additions & 4 deletions
This file was deleted.

extras/asr-services/.env.template

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
# ASR Services Configuration
22
# Copy this file to .env and configure as needed
33

4+
# PyTorch CUDA version for Docker build
5+
# Options: cu121 (CUDA 12.1), cu126 (CUDA 12.6), cu128 (CUDA 12.8)
6+
# Should match your system's CUDA version (check with: nvidia-smi)
7+
PYTORCH_CUDA_VERSION=cu126
8+
49
# Parakeet ASR Model Selection
510
PARAKEET_MODEL=nvidia/parakeet-tdt-0.6b-v3
611

extras/asr-services/Dockerfile_Parakeet

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
######################### builder #################################
44
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim AS builder
55

6-
# Accept CUDA version as build argument
7-
ARG CUDA_VERSION
6+
# Accept PyTorch CUDA version as build argument
7+
ARG PYTORCH_CUDA_VERSION
88

99
WORKDIR /app
1010

@@ -16,7 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
1616

1717
# Dependency manifest first for cache‑friendly installs
1818
COPY pyproject.toml uv.lock ./
19-
RUN uv sync --no-install-project --group parakeet --extra ${CUDA_VERSION} && \
19+
RUN uv sync --no-install-project --group parakeet --extra ${PYTORCH_CUDA_VERSION} && \
2020
uv cache clean
2121

2222
# Should prepare the .venv for use :)

extras/asr-services/docker-compose.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ services:
44
context: .
55
dockerfile: Dockerfile_Parakeet
66
args:
7-
CUDA_VERSION: ${CUDA_VERSION:-cu121}
7+
PYTORCH_CUDA_VERSION: ${PYTORCH_CUDA_VERSION:-cu126}
88
image: parakeet-asr:latest
99
ports:
1010
- "${PARAKEET_HOST_PORT:-8767}:${PARAKEET_CONTAINER_PORT:-8765}"

extras/asr-services/init.py

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Chronicle ASR Services Setup Script
4+
Interactive configuration for offline ASR (Parakeet) service
5+
"""
6+
7+
import argparse
8+
import os
9+
import shutil
10+
import subprocess
11+
import sys
12+
from datetime import datetime
13+
from pathlib import Path
14+
from typing import Any, Dict
15+
16+
from dotenv import set_key
17+
from rich import print as rprint
18+
from rich.console import Console
19+
from rich.panel import Panel
20+
from rich.prompt import Confirm, Prompt
21+
from rich.text import Text
22+
23+
24+
class ASRServicesSetup:
25+
def __init__(self, args=None):
26+
self.console = Console()
27+
self.config: Dict[str, Any] = {}
28+
self.args = args or argparse.Namespace()
29+
30+
def print_header(self, title: str):
31+
"""Print a colorful header"""
32+
self.console.print()
33+
panel = Panel(
34+
Text(title, style="cyan bold"),
35+
style="cyan",
36+
expand=False
37+
)
38+
self.console.print(panel)
39+
self.console.print()
40+
41+
def print_section(self, title: str):
42+
"""Print a section header"""
43+
self.console.print()
44+
self.console.print(f"[magenta]► {title}[/magenta]")
45+
self.console.print("[magenta]" + "─" * len(f"► {title}") + "[/magenta]")
46+
47+
def prompt_value(self, prompt: str, default: str = "") -> str:
48+
"""Prompt for a value with optional default"""
49+
try:
50+
return Prompt.ask(prompt, default=default)
51+
except EOFError:
52+
self.console.print(f"Using default: {default}")
53+
return default
54+
55+
def prompt_choice(self, prompt: str, choices: Dict[str, str], default: str = "1") -> str:
56+
"""Prompt for a choice from options"""
57+
self.console.print(prompt)
58+
for key, desc in choices.items():
59+
self.console.print(f" {key}) {desc}")
60+
self.console.print()
61+
62+
while True:
63+
try:
64+
choice = Prompt.ask("Enter choice", default=default)
65+
if choice in choices:
66+
return choice
67+
self.console.print(f"[red]Invalid choice. Please select from {list(choices.keys())}[/red]")
68+
except EOFError:
69+
self.console.print(f"Using default choice: {default}")
70+
return default
71+
72+
def read_existing_env_value(self, key: str) -> str:
73+
"""Read a value from existing .env file"""
74+
env_path = Path(".env")
75+
if not env_path.exists():
76+
return None
77+
78+
from dotenv import get_key
79+
value = get_key(str(env_path), key)
80+
# get_key returns None if key doesn't exist or value is empty
81+
return value if value else None
82+
83+
def backup_existing_env(self):
84+
"""Backup existing .env file"""
85+
env_path = Path(".env")
86+
if env_path.exists():
87+
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
88+
backup_path = f".env.backup.{timestamp}"
89+
shutil.copy2(env_path, backup_path)
90+
self.console.print(f"[blue][INFO][/blue] Backed up existing .env file to {backup_path}")
91+
92+
def detect_cuda_version(self) -> str:
93+
"""Detect system CUDA version from nvidia-smi"""
94+
try:
95+
result = subprocess.run(
96+
["nvidia-smi", "--query-gpu=driver_version", "--format=csv,noheader"],
97+
capture_output=True,
98+
text=True,
99+
timeout=5
100+
)
101+
if result.returncode == 0:
102+
# Try to get CUDA version from nvidia-smi
103+
result = subprocess.run(
104+
["nvidia-smi"],
105+
capture_output=True,
106+
text=True,
107+
timeout=5
108+
)
109+
if result.returncode == 0:
110+
output = result.stdout
111+
# Parse CUDA Version from nvidia-smi output
112+
# Format: "CUDA Version: 12.6"
113+
import re
114+
match = re.search(r'CUDA Version:\s*(\d+)\.(\d+)', output)
115+
if match:
116+
major, minor = match.groups()
117+
cuda_ver = f"{major}.{minor}"
118+
119+
# Map to available PyTorch CUDA versions
120+
if cuda_ver >= "12.8":
121+
return "cu128"
122+
elif cuda_ver >= "12.6":
123+
return "cu126"
124+
elif cuda_ver >= "12.1":
125+
return "cu121"
126+
except (subprocess.SubprocessError, FileNotFoundError):
127+
pass
128+
return "cu126" # Default fallback to cu126
129+
130+
def setup_cuda_version(self):
131+
"""Configure PyTorch CUDA version"""
132+
self.print_section("PyTorch CUDA Version Configuration")
133+
134+
# Check if provided via command line
135+
if hasattr(self.args, 'pytorch_cuda_version') and self.args.pytorch_cuda_version:
136+
cuda_version = self.args.pytorch_cuda_version
137+
self.console.print(f"[green][SUCCESS][/green] PyTorch CUDA version configured from command line: {cuda_version}")
138+
else:
139+
# Detect system CUDA version and suggest as default
140+
detected_cuda = self.detect_cuda_version()
141+
142+
# Map to default choice number
143+
cuda_to_choice = {
144+
"cu121": "1",
145+
"cu126": "2",
146+
"cu128": "3"
147+
}
148+
default_choice = cuda_to_choice.get(detected_cuda, "2")
149+
150+
self.console.print()
151+
self.console.print(f"[blue][INFO][/blue] Detected CUDA version: {detected_cuda}")
152+
self.console.print("[blue][INFO][/blue] This controls which PyTorch version is installed for GPU acceleration")
153+
self.console.print()
154+
155+
cuda_choices = {
156+
"1": "CUDA 12.1 (cu121)",
157+
"2": "CUDA 12.6 (cu126) - Recommended",
158+
"3": "CUDA 12.8 (cu128)"
159+
}
160+
cuda_choice = self.prompt_choice(
161+
"Choose CUDA version for PyTorch:",
162+
cuda_choices,
163+
default_choice
164+
)
165+
166+
choice_to_cuda = {
167+
"1": "cu121",
168+
"2": "cu126",
169+
"3": "cu128"
170+
}
171+
cuda_version = choice_to_cuda[cuda_choice]
172+
173+
self.config["PYTORCH_CUDA_VERSION"] = cuda_version
174+
self.console.print(f"[blue][INFO][/blue] Using PyTorch with CUDA version: {cuda_version}")
175+
176+
def generate_env_file(self):
177+
"""Generate .env file from template and update with configuration"""
178+
env_path = Path(".env")
179+
env_template = Path(".env.template")
180+
181+
# Backup existing .env if it exists
182+
self.backup_existing_env()
183+
184+
# Copy template to .env
185+
if env_template.exists():
186+
shutil.copy2(env_template, env_path)
187+
self.console.print("[blue][INFO][/blue] Copied .env.template to .env")
188+
else:
189+
self.console.print("[yellow][WARNING][/yellow] .env.template not found, creating new .env")
190+
env_path.touch(mode=0o600)
191+
192+
# Update configured values using set_key
193+
env_path_str = str(env_path)
194+
for key, value in self.config.items():
195+
if value: # Only set non-empty values
196+
set_key(env_path_str, key, value)
197+
198+
# Ensure secure permissions
199+
os.chmod(env_path, 0o600)
200+
201+
self.console.print("[green][SUCCESS][/green] .env file configured successfully with secure permissions")
202+
203+
def show_summary(self):
204+
"""Show configuration summary"""
205+
self.print_section("Configuration Summary")
206+
self.console.print()
207+
208+
self.console.print(f"✅ PyTorch CUDA Version: {self.config.get('PYTORCH_CUDA_VERSION', 'Not configured')}")
209+
210+
def show_next_steps(self):
211+
"""Show next steps"""
212+
self.print_section("Next Steps")
213+
self.console.print()
214+
215+
self.console.print("1. Start the Parakeet ASR service:")
216+
self.console.print(" [cyan]docker compose up --build -d parakeet-asr[/cyan]")
217+
self.console.print()
218+
self.console.print("2. Service will be available at:")
219+
self.console.print(" [cyan]http://host.docker.internal:8767[/cyan]")
220+
self.console.print()
221+
self.console.print("3. Configure your backend to use offline ASR:")
222+
self.console.print(" Set PARAKEET_ASR_URL=http://host.docker.internal:8767 in backend .env")
223+
224+
def run(self):
225+
"""Run the complete setup process"""
226+
self.print_header("🎤 ASR Services (Parakeet) Setup")
227+
self.console.print("Configure offline speech-to-text service")
228+
self.console.print()
229+
230+
try:
231+
# Run setup steps
232+
self.setup_cuda_version()
233+
234+
# Generate files
235+
self.print_header("Configuration Complete!")
236+
self.generate_env_file()
237+
238+
# Show results
239+
self.show_summary()
240+
self.show_next_steps()
241+
242+
self.console.print()
243+
self.console.print("[green][SUCCESS][/green] ASR Services setup complete! 🎉")
244+
245+
except KeyboardInterrupt:
246+
self.console.print()
247+
self.console.print("[yellow]Setup cancelled by user[/yellow]")
248+
sys.exit(0)
249+
except Exception as e:
250+
self.console.print(f"[red][ERROR][/red] Setup failed: {e}")
251+
sys.exit(1)
252+
253+
254+
def main():
255+
"""Main entry point"""
256+
parser = argparse.ArgumentParser(description="ASR Services (Parakeet) Setup")
257+
parser.add_argument("--pytorch-cuda-version",
258+
choices=["cu121", "cu126", "cu128"],
259+
help="PyTorch CUDA version (default: auto-detect)")
260+
261+
args = parser.parse_args()
262+
263+
setup = ASRServicesSetup(args)
264+
setup.run()
265+
266+
267+
if __name__ == "__main__":
268+
main()

extras/asr-services/pyproject.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,7 @@ parakeet = [
105105
[build-system]
106106
requires = ["setuptools>=64", "wheel"]
107107
build-backend = "setuptools.build_meta"
108+
109+
[tool.setuptools]
110+
# No packages - this project only contains standalone scripts
111+
packages = []

0 commit comments

Comments
 (0)