lattifai 1.0.1__py3-none-any.whl → 1.0.4__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.
- lattifai/alignment/lattice1_worker.py +70 -27
- lattifai/cli/app_installer.py +140 -0
- lattifai/cli/server.py +28 -5
- lattifai/mixin.py +1 -1
- lattifai/server/app.py +6 -0
- {lattifai-1.0.1.dist-info → lattifai-1.0.4.dist-info}/METADATA +62 -11
- {lattifai-1.0.1.dist-info → lattifai-1.0.4.dist-info}/RECORD +11 -10
- {lattifai-1.0.1.dist-info → lattifai-1.0.4.dist-info}/entry_points.txt +1 -0
- {lattifai-1.0.1.dist-info → lattifai-1.0.4.dist-info}/WHEEL +0 -0
- {lattifai-1.0.1.dist-info → lattifai-1.0.4.dist-info}/licenses/LICENSE +0 -0
- {lattifai-1.0.1.dist-info → lattifai-1.0.4.dist-info}/top_level.txt +0 -0
|
@@ -30,28 +30,42 @@ class Lattice1Worker:
|
|
|
30
30
|
sess_options.execution_mode = ort.ExecutionMode.ORT_PARALLEL
|
|
31
31
|
sess_options.add_session_config_entry("session.intra_op.allow_spinning", "0")
|
|
32
32
|
|
|
33
|
+
acoustic_model_path = f"{model_path}/acoustic_opt.onnx"
|
|
34
|
+
|
|
33
35
|
providers = []
|
|
34
|
-
|
|
36
|
+
all_providers = ort.get_all_providers()
|
|
37
|
+
if device.startswith("cuda") and all_providers.count("CUDAExecutionProvider") > 0:
|
|
35
38
|
providers.append("CUDAExecutionProvider")
|
|
36
|
-
|
|
39
|
+
if "MPSExecutionProvider" in all_providers:
|
|
37
40
|
providers.append("MPSExecutionProvider")
|
|
41
|
+
if "CoreMLExecutionProvider" in all_providers:
|
|
42
|
+
if "quant" in acoustic_model_path:
|
|
43
|
+
# NOTE: CPUExecutionProvider is faster for quantized models
|
|
44
|
+
pass
|
|
45
|
+
else:
|
|
46
|
+
providers.append("CoreMLExecutionProvider")
|
|
38
47
|
|
|
39
48
|
try:
|
|
40
49
|
self.acoustic_ort = ort.InferenceSession(
|
|
41
|
-
|
|
50
|
+
acoustic_model_path,
|
|
42
51
|
sess_options,
|
|
43
|
-
providers=providers + ["CPUExecutionProvider"
|
|
52
|
+
providers=providers + ["CPUExecutionProvider"],
|
|
44
53
|
)
|
|
45
54
|
except Exception as e:
|
|
46
55
|
raise ModelLoadError(f"acoustic model from {model_path}", original_error=e)
|
|
47
56
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
57
|
+
# get input_names
|
|
58
|
+
input_names = [inp.name for inp in self.acoustic_ort.get_inputs()]
|
|
59
|
+
if "audios" not in input_names:
|
|
60
|
+
try:
|
|
61
|
+
config = FbankConfig(num_mel_bins=80, device=device, snip_edges=False)
|
|
62
|
+
config_dict = config.to_dict()
|
|
63
|
+
config_dict.pop("device")
|
|
64
|
+
self.extractor = Wav2LogFilterBank(**config_dict).to(device).eval()
|
|
65
|
+
except Exception as e:
|
|
66
|
+
raise ModelLoadError(f"feature extractor for device {device}", original_error=e)
|
|
67
|
+
else:
|
|
68
|
+
self.extractor = None # ONNX model includes feature extractor
|
|
55
69
|
|
|
56
70
|
self.device = torch.device(device)
|
|
57
71
|
self.timings = defaultdict(lambda: 0.0)
|
|
@@ -63,28 +77,57 @@ class Lattice1Worker:
|
|
|
63
77
|
@torch.inference_mode()
|
|
64
78
|
def emission(self, audio: torch.Tensor) -> torch.Tensor:
|
|
65
79
|
_start = time.time()
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
80
|
+
if self.extractor is not None:
|
|
81
|
+
# audio -> features -> emission
|
|
82
|
+
features = self.extractor(audio) # (1, T, D)
|
|
83
|
+
if features.shape[1] > 6000:
|
|
84
|
+
features_list = torch.split(features, 6000, dim=1)
|
|
85
|
+
emissions = []
|
|
86
|
+
for features in features_list:
|
|
87
|
+
ort_inputs = {
|
|
88
|
+
"features": features.cpu().numpy(),
|
|
89
|
+
"feature_lengths": np.array([features.size(1)], dtype=np.int64),
|
|
90
|
+
}
|
|
91
|
+
emission = self.acoustic_ort.run(None, ort_inputs)[0] # (1, T, vocab_size) numpy
|
|
92
|
+
emissions.append(emission)
|
|
93
|
+
emission = torch.cat(
|
|
94
|
+
[torch.from_numpy(emission).to(self.device) for emission in emissions], dim=1
|
|
95
|
+
) # (1, T, vocab_size)
|
|
96
|
+
else:
|
|
72
97
|
ort_inputs = {
|
|
73
98
|
"features": features.cpu().numpy(),
|
|
74
99
|
"feature_lengths": np.array([features.size(1)], dtype=np.int64),
|
|
75
100
|
}
|
|
76
101
|
emission = self.acoustic_ort.run(None, ort_inputs)[0] # (1, T, vocab_size) numpy
|
|
77
|
-
|
|
78
|
-
emission = torch.cat(
|
|
79
|
-
[torch.from_numpy(emission).to(self.device) for emission in emissions], dim=1
|
|
80
|
-
) # (1, T, vocab_size)
|
|
102
|
+
emission = torch.from_numpy(emission).to(self.device)
|
|
81
103
|
else:
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
104
|
+
CHUNK_SIZE = 60 * 16000 # 60 seconds
|
|
105
|
+
if audio.shape[1] > CHUNK_SIZE:
|
|
106
|
+
audio_list = torch.split(audio, CHUNK_SIZE, dim=1)
|
|
107
|
+
emissions = []
|
|
108
|
+
for audios in audio_list:
|
|
109
|
+
emission = self.acoustic_ort.run(
|
|
110
|
+
None,
|
|
111
|
+
{
|
|
112
|
+
"audios": audios.cpu().numpy(),
|
|
113
|
+
},
|
|
114
|
+
)[
|
|
115
|
+
0
|
|
116
|
+
] # (1, T, vocab_size) numpy
|
|
117
|
+
emissions.append(emission)
|
|
118
|
+
emission = torch.cat(
|
|
119
|
+
[torch.from_numpy(emission).to(self.device) for emission in emissions], dim=1
|
|
120
|
+
) # (1, T, vocab_size)
|
|
121
|
+
else:
|
|
122
|
+
emission = self.acoustic_ort.run(
|
|
123
|
+
None,
|
|
124
|
+
{
|
|
125
|
+
"audios": audio.cpu().numpy(),
|
|
126
|
+
},
|
|
127
|
+
)[
|
|
128
|
+
0
|
|
129
|
+
] # (1, T, vocab_size) numpy
|
|
130
|
+
emission = torch.from_numpy(emission).to(self.device)
|
|
88
131
|
|
|
89
132
|
self.timings["emission"] += time.time() - _start
|
|
90
133
|
return emission # (1, T, vocab_size) torch
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"""CLI tool to install lai-app (frontend web application)."""
|
|
2
|
+
|
|
3
|
+
import platform
|
|
4
|
+
import subprocess
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def check_command_exists(cmd: str) -> bool:
|
|
10
|
+
"""Check if a command exists in PATH."""
|
|
11
|
+
try:
|
|
12
|
+
subprocess.run([cmd, "--version"], check=True, capture_output=True, text=True)
|
|
13
|
+
return True
|
|
14
|
+
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
15
|
+
return False
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def install_nodejs():
|
|
19
|
+
"""Install Node.js based on the operating system."""
|
|
20
|
+
system = platform.system().lower()
|
|
21
|
+
|
|
22
|
+
print("📦 Node.js not found. Installing Node.js...\n")
|
|
23
|
+
|
|
24
|
+
try:
|
|
25
|
+
if system == "darwin": # macOS
|
|
26
|
+
# Check if Homebrew is installed
|
|
27
|
+
if check_command_exists("brew"):
|
|
28
|
+
print("🍺 Using Homebrew to install Node.js...")
|
|
29
|
+
subprocess.run(["brew", "install", "node"], check=True)
|
|
30
|
+
print("✓ Node.js installed via Homebrew\n")
|
|
31
|
+
else:
|
|
32
|
+
print("❌ Homebrew not found.")
|
|
33
|
+
print(" Please install Homebrew first:")
|
|
34
|
+
print(
|
|
35
|
+
' /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"'
|
|
36
|
+
)
|
|
37
|
+
print("\n Or install Node.js manually from: https://nodejs.org/")
|
|
38
|
+
sys.exit(1)
|
|
39
|
+
|
|
40
|
+
elif system == "linux":
|
|
41
|
+
# Try common package managers
|
|
42
|
+
if check_command_exists("apt"):
|
|
43
|
+
print("🐧 Using apt to install Node.js...")
|
|
44
|
+
subprocess.run(["sudo", "apt", "update"], check=True)
|
|
45
|
+
subprocess.run(["sudo", "apt", "install", "-y", "nodejs", "npm"], check=True)
|
|
46
|
+
print("✓ Node.js installed via apt\n")
|
|
47
|
+
elif check_command_exists("yum"):
|
|
48
|
+
print("🐧 Using yum to install Node.js...")
|
|
49
|
+
subprocess.run(["sudo", "yum", "install", "-y", "nodejs", "npm"], check=True)
|
|
50
|
+
print("✓ Node.js installed via yum\n")
|
|
51
|
+
elif check_command_exists("dnf"):
|
|
52
|
+
print("🐧 Using dnf to install Node.js...")
|
|
53
|
+
subprocess.run(["sudo", "dnf", "install", "-y", "nodejs", "npm"], check=True)
|
|
54
|
+
print("✓ Node.js installed via dnf\n")
|
|
55
|
+
elif check_command_exists("pacman"):
|
|
56
|
+
print("🐧 Using pacman to install Node.js...")
|
|
57
|
+
subprocess.run(["sudo", "pacman", "-S", "--noconfirm", "nodejs", "npm"], check=True)
|
|
58
|
+
print("✓ Node.js installed via pacman\n")
|
|
59
|
+
else:
|
|
60
|
+
print("❌ No supported package manager found (apt/yum/dnf/pacman).")
|
|
61
|
+
print(" Please install Node.js manually from: https://nodejs.org/")
|
|
62
|
+
sys.exit(1)
|
|
63
|
+
|
|
64
|
+
elif system == "windows":
|
|
65
|
+
print("❌ Automatic installation on Windows is not supported.")
|
|
66
|
+
print(" Please download and install Node.js from: https://nodejs.org/")
|
|
67
|
+
print(" Then run this command again.")
|
|
68
|
+
sys.exit(1)
|
|
69
|
+
|
|
70
|
+
else:
|
|
71
|
+
print(f"❌ Unsupported operating system: {system}")
|
|
72
|
+
print(" Please install Node.js manually from: https://nodejs.org/")
|
|
73
|
+
sys.exit(1)
|
|
74
|
+
|
|
75
|
+
# Verify installation
|
|
76
|
+
if not check_command_exists("npm"):
|
|
77
|
+
print("❌ Node.js installation verification failed.")
|
|
78
|
+
print(" Please restart your terminal and try again.")
|
|
79
|
+
sys.exit(1)
|
|
80
|
+
|
|
81
|
+
except subprocess.CalledProcessError as e:
|
|
82
|
+
print(f"\n❌ Error during Node.js installation: {e}")
|
|
83
|
+
print(" Please install Node.js manually from: https://nodejs.org/")
|
|
84
|
+
sys.exit(1)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def main():
|
|
88
|
+
"""Install lai-app Node.js application."""
|
|
89
|
+
# Get the app directory relative to this package
|
|
90
|
+
app_dir = Path(__file__).parent.parent.parent.parent / "app"
|
|
91
|
+
|
|
92
|
+
if not app_dir.exists():
|
|
93
|
+
print(f"❌ Error: app directory not found at {app_dir}")
|
|
94
|
+
print(" Make sure you're in the lattifai-python repository.")
|
|
95
|
+
sys.exit(1)
|
|
96
|
+
|
|
97
|
+
print("🚀 Installing lai-app (LattifAI Web Application)...\n")
|
|
98
|
+
|
|
99
|
+
# Check if npm is installed, if not, install Node.js
|
|
100
|
+
if not check_command_exists("npm"):
|
|
101
|
+
install_nodejs()
|
|
102
|
+
else:
|
|
103
|
+
npm_version = subprocess.run(["npm", "--version"], capture_output=True, text=True, check=True).stdout.strip()
|
|
104
|
+
print(f"✓ npm is already installed (v{npm_version})\n")
|
|
105
|
+
|
|
106
|
+
# Change to app directory and run installation
|
|
107
|
+
try:
|
|
108
|
+
print(f"📁 Working directory: {app_dir}\n")
|
|
109
|
+
|
|
110
|
+
# Install dependencies
|
|
111
|
+
print("📦 Installing dependencies...")
|
|
112
|
+
subprocess.run(["npm", "install"], cwd=app_dir, check=True)
|
|
113
|
+
print("✓ Dependencies installed\n")
|
|
114
|
+
|
|
115
|
+
# Build the application
|
|
116
|
+
print("🔨 Building application...")
|
|
117
|
+
subprocess.run(["npm", "run", "build"], cwd=app_dir, check=True)
|
|
118
|
+
print("✓ Application built\n")
|
|
119
|
+
|
|
120
|
+
# Link globally
|
|
121
|
+
print("🔗 Linking lai-app command globally...")
|
|
122
|
+
subprocess.run(["npm", "link"], cwd=app_dir, check=True)
|
|
123
|
+
print("✓ lai-app command linked globally\n")
|
|
124
|
+
|
|
125
|
+
print("=" * 60)
|
|
126
|
+
print("✅ lai-app installed successfully!")
|
|
127
|
+
print("=" * 60)
|
|
128
|
+
print("\n🎉 You can now run:")
|
|
129
|
+
print(" lai-app # Start the web application")
|
|
130
|
+
print(" lai-app --help # Show help")
|
|
131
|
+
print(" lai-app --port 8080 # Use custom port")
|
|
132
|
+
print("\n📖 For more information, see app/CLI_USAGE.md\n")
|
|
133
|
+
|
|
134
|
+
except subprocess.CalledProcessError as e:
|
|
135
|
+
print(f"\n❌ Error during installation: {e}")
|
|
136
|
+
sys.exit(1)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
if __name__ == "__main__":
|
|
140
|
+
main()
|
lattifai/cli/server.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import argparse
|
|
1
2
|
import os
|
|
2
3
|
|
|
3
4
|
import colorful
|
|
@@ -6,13 +7,35 @@ import uvicorn
|
|
|
6
7
|
|
|
7
8
|
def main():
|
|
8
9
|
"""Launch the LattifAI Web Interface."""
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
parser = argparse.ArgumentParser(description="LattifAI Backend Server")
|
|
11
|
+
parser.add_argument(
|
|
12
|
+
"-p",
|
|
13
|
+
"--port",
|
|
14
|
+
type=int,
|
|
15
|
+
default=8001,
|
|
16
|
+
help="Port to run the server on (default: 8001)",
|
|
17
|
+
)
|
|
18
|
+
parser.add_argument(
|
|
19
|
+
"--host",
|
|
20
|
+
type=str,
|
|
21
|
+
default="0.0.0.0",
|
|
22
|
+
help="Host to bind the server to (default: 0.0.0.0)",
|
|
23
|
+
)
|
|
24
|
+
parser.add_argument(
|
|
25
|
+
"--no-reload",
|
|
26
|
+
action="store_true",
|
|
27
|
+
help="Disable auto-reload on code changes",
|
|
28
|
+
)
|
|
11
29
|
|
|
12
|
-
|
|
13
|
-
# We might need to adjust python path or just rely on installed package
|
|
30
|
+
args = parser.parse_args()
|
|
14
31
|
|
|
15
|
-
|
|
32
|
+
print(colorful.bold_green("🚀 Launching LattifAI Backend Server..."))
|
|
33
|
+
print(colorful.cyan(f"Server running at http://localhost:{args.port}"))
|
|
34
|
+
print(colorful.yellow(f"Host: {args.host}"))
|
|
35
|
+
print(colorful.yellow(f"Auto-reload: {'disabled' if args.no_reload else 'enabled'}"))
|
|
36
|
+
print()
|
|
37
|
+
|
|
38
|
+
uvicorn.run("lattifai.server.app:app", host=args.host, port=args.port, reload=not args.no_reload, log_level="info")
|
|
16
39
|
|
|
17
40
|
|
|
18
41
|
if __name__ == "__main__":
|
lattifai/mixin.py
CHANGED
|
@@ -404,7 +404,7 @@ class LattifAIClientMixin:
|
|
|
404
404
|
transcription = await self.transcriber.transcribe_file(media_file, language=source_lang)
|
|
405
405
|
print(colorful.green(" ✓ Transcription completed."))
|
|
406
406
|
|
|
407
|
-
if "
|
|
407
|
+
if "gemini" in self.transcriber.name.lower():
|
|
408
408
|
# write to temp file and use Caption read
|
|
409
409
|
with tempfile.NamedTemporaryFile(suffix=self.transcriber.file_suffix, delete=True) as tmp_file:
|
|
410
410
|
tmp_path = Path(tmp_file.name)
|
lattifai/server/app.py
CHANGED
|
@@ -58,6 +58,12 @@ app.add_middleware(
|
|
|
58
58
|
)
|
|
59
59
|
|
|
60
60
|
|
|
61
|
+
@app.get("/health")
|
|
62
|
+
async def health_check():
|
|
63
|
+
"""Health check endpoint for server status monitoring."""
|
|
64
|
+
return {"status": "ok", "message": "LattifAI backend server is running"}
|
|
65
|
+
|
|
66
|
+
|
|
61
67
|
def mask_api_key(key: str) -> str:
|
|
62
68
|
"""Mask API key for display, showing only first 6 and last 4 characters."""
|
|
63
69
|
if len(key) <= 10:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lattifai
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.4
|
|
4
4
|
Summary: Lattifai Python SDK: Seamless Integration with Lattifai's Speech and Video AI Services
|
|
5
5
|
Author-email: Lattifai Technologies <tech@lattifai.com>
|
|
6
6
|
Maintainer-email: Lattice <tech@lattifai.com>
|
|
@@ -50,7 +50,7 @@ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
|
50
50
|
Requires-Python: <3.15,>=3.10
|
|
51
51
|
Description-Content-Type: text/markdown
|
|
52
52
|
License-File: LICENSE
|
|
53
|
-
Requires-Dist: lattifai-core>=0.4.
|
|
53
|
+
Requires-Dist: lattifai-core>=0.4.6
|
|
54
54
|
Requires-Dist: lattifai-run>=1.0.1
|
|
55
55
|
Requires-Dist: python-dotenv
|
|
56
56
|
Requires-Dist: lhotse>=1.26.0
|
|
@@ -64,6 +64,7 @@ Requires-Dist: msgpack
|
|
|
64
64
|
Requires-Dist: g2p-phonemizer>=0.4.0
|
|
65
65
|
Requires-Dist: av
|
|
66
66
|
Requires-Dist: wtpsplit>=2.1.6
|
|
67
|
+
Requires-Dist: kaldi-native-fbank
|
|
67
68
|
Requires-Dist: OmniSenseVoice>=0.4.0
|
|
68
69
|
Requires-Dist: nemo_toolkit_asr[asr]>=2.7.0rc1
|
|
69
70
|
Requires-Dist: pyannote-audio-notorchdeps>=4.0.2
|
|
@@ -155,7 +156,7 @@ Advanced forced alignment and subtitle generation powered by [ 🤗 Lattice-1](h
|
|
|
155
156
|
pip install install-k2
|
|
156
157
|
install-k2 --torch-version 2.9.1 # if not set will auto-detect PyTorch version and install compatible k2
|
|
157
158
|
|
|
158
|
-
pip install lattifai
|
|
159
|
+
pip install lattifai
|
|
159
160
|
```
|
|
160
161
|
|
|
161
162
|
**Using uv (Recommended - 10-100x faster):**
|
|
@@ -173,8 +174,8 @@ uv pip install install-k2
|
|
|
173
174
|
uv pip install pip
|
|
174
175
|
uv run install-k2 --torch-version 2.9.1
|
|
175
176
|
|
|
176
|
-
# Install LattifAI
|
|
177
|
-
uv pip install lattifai
|
|
177
|
+
# Install LattifAI
|
|
178
|
+
uv pip install lattifai
|
|
178
179
|
```
|
|
179
180
|
|
|
180
181
|
> **Note**: `install-k2` automatically detects your PyTorch version (up to 2.9) and installs the compatible k2 wheel.
|
|
@@ -257,19 +258,69 @@ That's it! Your aligned subtitles are saved to `aligned.srt`.
|
|
|
257
258
|
|
|
258
259
|
### Web Interface
|
|
259
260
|
|
|
260
|
-
|
|
261
|
+

|
|
262
|
+
|
|
263
|
+
1. **Install the web application (one-time setup):**
|
|
264
|
+
```bash
|
|
265
|
+
lai-app-install
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
This command will:
|
|
269
|
+
- Check if Node.js/npm is installed (and install if needed)
|
|
270
|
+
- Install frontend dependencies
|
|
271
|
+
- Build the application
|
|
272
|
+
- Setup the `lai-app` command globally
|
|
273
|
+
|
|
274
|
+
2. **Start the backend server:**
|
|
261
275
|
```bash
|
|
262
276
|
lai-server
|
|
277
|
+
|
|
278
|
+
# Custom port (default: 8001)
|
|
279
|
+
lai-server --port 9000
|
|
280
|
+
|
|
281
|
+
# Custom host
|
|
282
|
+
lai-server --host 127.0.0.1 --port 9000
|
|
283
|
+
|
|
284
|
+
# Production mode (disable auto-reload)
|
|
285
|
+
lai-server --no-reload
|
|
263
286
|
```
|
|
264
287
|
|
|
265
|
-
|
|
288
|
+
**Backend Server Options:**
|
|
289
|
+
- `-p, --port` - Server port (default: 8001)
|
|
290
|
+
- `--host` - Host address (default: 0.0.0.0)
|
|
291
|
+
- `--no-reload` - Disable auto-reload for production
|
|
292
|
+
- `-h, --help` - Show help message
|
|
293
|
+
|
|
294
|
+
3. **Start the frontend application:**
|
|
266
295
|
```bash
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
296
|
+
lai-app
|
|
297
|
+
|
|
298
|
+
# Custom port (default: 5173)
|
|
299
|
+
lai-app --port 8080
|
|
300
|
+
|
|
301
|
+
# Custom backend URL
|
|
302
|
+
lai-app --backend http://localhost:9000
|
|
303
|
+
|
|
304
|
+
# Don't auto-open browser
|
|
305
|
+
lai-app --no-open
|
|
270
306
|
```
|
|
271
307
|
|
|
272
|
-
|
|
308
|
+
**Frontend Application Options:**
|
|
309
|
+
- `-p, --port` - Frontend server port (default: 5173)
|
|
310
|
+
- `--backend` - Backend API URL (default: http://localhost:8001)
|
|
311
|
+
- `--no-open` - Don't automatically open browser
|
|
312
|
+
- `-h, --help` - Show help message
|
|
313
|
+
|
|
314
|
+
The web interface will automatically open in your browser at `http://localhost:5173`.
|
|
315
|
+
|
|
316
|
+
**Features:**
|
|
317
|
+
- ✅ Automatic backend server status detection
|
|
318
|
+
- ✅ Visual file upload with drag-and-drop
|
|
319
|
+
- ✅ Real-time alignment progress
|
|
320
|
+
- ✅ Multiple subtitle format support
|
|
321
|
+
- ✅ Built-in transcription with multiple models
|
|
322
|
+
- ✅ API key management interface
|
|
323
|
+
- ✅ Download aligned subtitles in various formats
|
|
273
324
|
|
|
274
325
|
---
|
|
275
326
|
|
|
@@ -3,12 +3,12 @@ lattifai/audio2.py,sha256=WPAhcaEoIMRQBf2QZe-0yyAbgyyiqUVAthJ-z54R9Wc,7761
|
|
|
3
3
|
lattifai/client.py,sha256=Wkz7Q1XvCQ9KxD0uZ_M1ix457ZbgIG1gAxxt8nMBUj4,22147
|
|
4
4
|
lattifai/errors.py,sha256=dFQ_7c8rwuHrq2pDPjpzA755tAV3t8daXXFbHmWblbs,11015
|
|
5
5
|
lattifai/logging.py,sha256=MbUEeOUFlF92pA9v532DiPPWKl03S7UHCJ6Z652cf0w,2860
|
|
6
|
-
lattifai/mixin.py,sha256=
|
|
6
|
+
lattifai/mixin.py,sha256=2QnWMG2E_cyZaa98Wtdf6Duo8w3DTIiD-EEfrmtDhGk,23388
|
|
7
7
|
lattifai/types.py,sha256=SjYBfwrCBOXlICvH04niFQJ7OzTx7oTaa_npfRkB67U,659
|
|
8
8
|
lattifai/utils.py,sha256=TqOPrd_Et7KxrbfI_JbBNIGZ5-oGJY8ZUyJMPDTih1I,3848
|
|
9
9
|
lattifai/alignment/__init__.py,sha256=ehpkKfjNIYUx7_M-RWD_8Efcrzd9bE-NSm0QgMMVLW0,178
|
|
10
10
|
lattifai/alignment/lattice1_aligner.py,sha256=soBRZ98jRIju-wN5eqYUmQfF56KiEUxVGw0UvtRcx4A,4464
|
|
11
|
-
lattifai/alignment/lattice1_worker.py,sha256=
|
|
11
|
+
lattifai/alignment/lattice1_worker.py,sha256=XGICEzLygspqC7SMj5s45M7VNSj-l2zemkawdKKjssw,9233
|
|
12
12
|
lattifai/alignment/phonemizer.py,sha256=fbhN2DOl39lW4nQWKzyUUTMUabg7v61lB1kj8SKK-Sw,1761
|
|
13
13
|
lattifai/alignment/segmenter.py,sha256=-FKtIwv9Z4fU9Fs08jhL9VyREVSYcfcwuTqb8jxCiuo,6228
|
|
14
14
|
lattifai/alignment/tokenizer.py,sha256=WilqU9Ecdkl_cW86IkB1mh_PFlHN-35Jsreiyse2r-8,22355
|
|
@@ -20,8 +20,9 @@ lattifai/caption/supervision.py,sha256=DRrM8lfKU_x9aVBcLG6xnT0xIJrnc8jzHpzcSwQOg
|
|
|
20
20
|
lattifai/caption/text_parser.py,sha256=XDb8KTt031uJ1hg6dpbINglGOTX-6pBcghbg3DULM1I,4633
|
|
21
21
|
lattifai/cli/__init__.py,sha256=dIUmrpN-OwR4h6BqMhXp87_5ZwgO41ShPru_iZGnpQs,463
|
|
22
22
|
lattifai/cli/alignment.py,sha256=uKMTE95_JMikfbyCcwLbQxms-EQmZXEj7oYugiupk9I,5890
|
|
23
|
+
lattifai/cli/app_installer.py,sha256=0xBQnJZKhyx4JT_PkHXkZ0XlAWxCGz9o0Jjq99poKew,5680
|
|
23
24
|
lattifai/cli/caption.py,sha256=ucgYxJ43ab71nGpZBAiVn8QA0DAVht2QMZFE5IdgxP0,6853
|
|
24
|
-
lattifai/cli/server.py,sha256=
|
|
25
|
+
lattifai/cli/server.py,sha256=Vo6_ANgwu7WtC5h4BebQLmhqLNpqzPoYrPQPANpP7rw,1142
|
|
25
26
|
lattifai/cli/transcribe.py,sha256=6uJfvtB1o_u1uQwxt4fje_koyfN93mGaFLlskmjqx2c,7406
|
|
26
27
|
lattifai/cli/youtube.py,sha256=9_erdIkhX8pCiy7BRzNstEiO9saM-VKZ1WVqvbXbmrc,5267
|
|
27
28
|
lattifai/config/__init__.py,sha256=Z8OudvS6fgfLNLu_2fvoXartQiYCECOnNfzDt-PfCN4,543
|
|
@@ -33,7 +34,7 @@ lattifai/config/media.py,sha256=5JOPjifXDM2WWQERySDZen4-7YfgQNcYM2NkkKp0LjQ,1361
|
|
|
33
34
|
lattifai/config/transcription.py,sha256=bzghOGgcNWzTnDYd_cqCOB7GT8OnzHDiyam7LSixqxM,2901
|
|
34
35
|
lattifai/diarization/__init__.py,sha256=MgBDQ1ehL2qDnZprEp8KqON7CmbG-qaP37gzBsV0jzk,119
|
|
35
36
|
lattifai/diarization/lattifai.py,sha256=SE2BpIZ3_deKyhXdBqe77bsDLXIUV9AQV34gfINv7_s,2657
|
|
36
|
-
lattifai/server/app.py,sha256=
|
|
37
|
+
lattifai/server/app.py,sha256=UpHsKJHtK1-sdp5mtDPBSxEl8xYTbe7cVO8dLp9Xiuo,15380
|
|
37
38
|
lattifai/transcription/__init__.py,sha256=mEoMTbs5jAgtXQn1jTjlFY_GUr-S0WmPn8uZ6WZCkU0,2643
|
|
38
39
|
lattifai/transcription/base.py,sha256=59b4nQHFMyTRyyzBJTM8ZpEuUy1KjwA2o6rNfrNluKY,3911
|
|
39
40
|
lattifai/transcription/gemini.py,sha256=1VNi9gl-Kpkw3ljZcOZG5oq_OY8fMC9Xv4kOwyQpI0Q,7992
|
|
@@ -47,9 +48,9 @@ lattifai/workflow/agents.py,sha256=yEOnxnhcTvr1iOhCorNvp8B76P6nQsLRXJCu_rCYFfM,3
|
|
|
47
48
|
lattifai/workflow/base.py,sha256=8QoVIBZwJfr5mppJbtUFafHv5QR9lL-XrULjTWD0oBg,6257
|
|
48
49
|
lattifai/workflow/file_manager.py,sha256=d106KHLY8A9amLy5h1vR32e4od8mmJGqMD-iDyiRPLI,32917
|
|
49
50
|
lattifai/workflow/youtube.py,sha256=n8L1c6tl8FuYzAzKZ-B76zf5yZsvVggZEJ9mPdbEWGQ,22989
|
|
50
|
-
lattifai-1.0.
|
|
51
|
-
lattifai-1.0.
|
|
52
|
-
lattifai-1.0.
|
|
53
|
-
lattifai-1.0.
|
|
54
|
-
lattifai-1.0.
|
|
55
|
-
lattifai-1.0.
|
|
51
|
+
lattifai-1.0.4.dist-info/licenses/LICENSE,sha256=_IkHdwOWLAWcE1M_tIpDoRWdNSJwFdtIqI-XSkK3yPU,1066
|
|
52
|
+
lattifai-1.0.4.dist-info/METADATA,sha256=uijheuHzvh-AhZwIFCGTc2_UX-x3ZXxhnlPsvcaMQ4c,24582
|
|
53
|
+
lattifai-1.0.4.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91
|
|
54
|
+
lattifai-1.0.4.dist-info/entry_points.txt,sha256=F8Akof3VtKtrbnYSav1umgoo9Xbv34rUcKn-ioRfeGQ,474
|
|
55
|
+
lattifai-1.0.4.dist-info/top_level.txt,sha256=tHSoXF26r-IGfbIP_JoYATqbmf14h5NrnNJGH4j5reI,9
|
|
56
|
+
lattifai-1.0.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|