abstractvoice 0.3.1__tar.gz → 0.4.6__tar.gz

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 (28) hide show
  1. {abstractvoice-0.3.1 → abstractvoice-0.4.6}/PKG-INFO +125 -19
  2. {abstractvoice-0.3.1 → abstractvoice-0.4.6}/README.md +116 -18
  3. {abstractvoice-0.3.1 → abstractvoice-0.4.6}/abstractvoice/__init__.py +5 -2
  4. {abstractvoice-0.3.1 → abstractvoice-0.4.6}/abstractvoice/examples/cli_repl.py +81 -44
  5. {abstractvoice-0.3.1 → abstractvoice-0.4.6}/abstractvoice/examples/voice_cli.py +56 -20
  6. abstractvoice-0.4.6/abstractvoice/instant_setup.py +83 -0
  7. abstractvoice-0.4.6/abstractvoice/simple_model_manager.py +500 -0
  8. {abstractvoice-0.3.1 → abstractvoice-0.4.6}/abstractvoice/tts/tts_engine.py +253 -23
  9. {abstractvoice-0.3.1 → abstractvoice-0.4.6}/abstractvoice/voice_manager.py +176 -21
  10. {abstractvoice-0.3.1 → abstractvoice-0.4.6}/abstractvoice.egg-info/PKG-INFO +125 -19
  11. {abstractvoice-0.3.1 → abstractvoice-0.4.6}/abstractvoice.egg-info/SOURCES.txt +2 -0
  12. {abstractvoice-0.3.1 → abstractvoice-0.4.6}/abstractvoice.egg-info/requires.txt +8 -0
  13. {abstractvoice-0.3.1 → abstractvoice-0.4.6}/pyproject.toml +9 -0
  14. {abstractvoice-0.3.1 → abstractvoice-0.4.6}/LICENSE +0 -0
  15. {abstractvoice-0.3.1 → abstractvoice-0.4.6}/abstractvoice/__main__.py +0 -0
  16. {abstractvoice-0.3.1 → abstractvoice-0.4.6}/abstractvoice/dependency_check.py +0 -0
  17. {abstractvoice-0.3.1 → abstractvoice-0.4.6}/abstractvoice/examples/__init__.py +0 -0
  18. {abstractvoice-0.3.1 → abstractvoice-0.4.6}/abstractvoice/examples/web_api.py +0 -0
  19. {abstractvoice-0.3.1 → abstractvoice-0.4.6}/abstractvoice/recognition.py +0 -0
  20. {abstractvoice-0.3.1 → abstractvoice-0.4.6}/abstractvoice/stt/__init__.py +0 -0
  21. {abstractvoice-0.3.1 → abstractvoice-0.4.6}/abstractvoice/stt/transcriber.py +0 -0
  22. {abstractvoice-0.3.1 → abstractvoice-0.4.6}/abstractvoice/tts/__init__.py +0 -0
  23. {abstractvoice-0.3.1 → abstractvoice-0.4.6}/abstractvoice/vad/__init__.py +0 -0
  24. {abstractvoice-0.3.1 → abstractvoice-0.4.6}/abstractvoice/vad/voice_detector.py +0 -0
  25. {abstractvoice-0.3.1 → abstractvoice-0.4.6}/abstractvoice.egg-info/dependency_links.txt +0 -0
  26. {abstractvoice-0.3.1 → abstractvoice-0.4.6}/abstractvoice.egg-info/entry_points.txt +0 -0
  27. {abstractvoice-0.3.1 → abstractvoice-0.4.6}/abstractvoice.egg-info/top_level.txt +0 -0
  28. {abstractvoice-0.3.1 → abstractvoice-0.4.6}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: abstractvoice
3
- Version: 0.3.1
3
+ Version: 0.4.6
4
4
  Summary: A modular Python library for voice interactions with AI systems
5
5
  Author-email: Laurent-Philippe Albou <contact@abstractcore.ai>
6
6
  License-Expression: MIT
@@ -19,6 +19,14 @@ Description-Content-Type: text/markdown
19
19
  License-File: LICENSE
20
20
  Requires-Dist: numpy>=1.24.0
21
21
  Requires-Dist: requests>=2.31.0
22
+ Requires-Dist: appdirs>=1.4.0
23
+ Requires-Dist: coqui-tts<0.30.0,>=0.27.0
24
+ Requires-Dist: torch<2.4.0,>=2.0.0
25
+ Requires-Dist: torchvision<0.19.0,>=0.15.0
26
+ Requires-Dist: torchaudio<2.4.0,>=2.0.0
27
+ Requires-Dist: librosa>=0.10.0
28
+ Requires-Dist: sounddevice>=0.4.6
29
+ Requires-Dist: soundfile>=0.12.1
22
30
  Provides-Extra: voice
23
31
  Requires-Dist: sounddevice>=0.4.6; extra == "voice"
24
32
  Requires-Dist: webrtcvad>=2.0.10; extra == "voice"
@@ -164,34 +172,58 @@ AbstractVoice automatically detects espeak-ng and upgrades to premium quality vo
164
172
 
165
173
  ## Quick Start
166
174
 
167
- ### Basic Usage (Minimal Installation)
175
+ ### Instant TTS (v0.4.0+)
168
176
 
169
177
  ```python
170
- # First install with minimal dependencies
171
- # pip install abstractvoice
172
-
173
178
  from abstractvoice import VoiceManager
174
179
 
175
- # This will show a helpful error message with installation instructions
176
- try:
177
- vm = VoiceManager()
178
- except ImportError as e:
179
- print(e) # Shows: "TTS functionality requires optional dependencies..."
180
- # Follow the instructions to install: pip install abstractvoice[all]
180
+ # Initialize voice manager - automatically downloads essential model if needed
181
+ vm = VoiceManager()
182
+
183
+ # Text-to-speech works immediately!
184
+ vm.speak("Hello! TTS works out of the box!")
181
185
  ```
182
186
 
183
- ### Full Usage Example
187
+ **That's it!** AbstractVoice v0.4.0+ automatically:
188
+ - ✅ Downloads essential English model (107MB) on first use
189
+ - ✅ Caches models permanently for offline use
190
+ - ✅ Works immediately after first setup
191
+ - ✅ No complex configuration needed
184
192
 
185
- ```python
186
- # After installing with: pip install abstractvoice[all]
193
+ ### 🌍 Multi-Language Support
187
194
 
188
- from abstractvoice import VoiceManager
195
+ ```python
196
+ # Download and use French voice
197
+ vm.download_model('fr.css10_vits') # Downloads automatically
198
+ vm.set_language('fr')
199
+ vm.speak("Bonjour! Je parle français maintenant.")
200
+
201
+ # Download and use German voice
202
+ vm.download_model('de.thorsten_vits')
203
+ vm.set_language('de')
204
+ vm.speak("Hallo! Ich spreche jetzt Deutsch.")
205
+ ```
189
206
 
190
- # Initialize voice manager
191
- vm = VoiceManager(language='en', debug_mode=True)
207
+ ### 🔧 Check System Status
192
208
 
193
- # Text-to-speech
194
- vm.speak("Hello! I can speak text and listen for responses.")
209
+ ```python
210
+ from abstractvoice import is_ready, get_status, list_models
211
+ import json
212
+
213
+ # Quick readiness check
214
+ ready = is_ready()
215
+ print(f"TTS ready: {ready}")
216
+
217
+ # Get detailed status
218
+ status = json.loads(get_status())
219
+ print(f"Models cached: {status['total_cached']}")
220
+ print(f"Offline ready: {status['ready_for_offline']}")
221
+
222
+ # List all available models
223
+ models = json.loads(list_models())
224
+ for lang, voices in models.items():
225
+ print(f"{lang}: {len(voices)} voices available")
226
+ ```
195
227
 
196
228
  # Speech-to-text with callbacks
197
229
  def on_transcription(text):
@@ -1289,6 +1321,80 @@ voice_manager.listen(
1289
1321
  )
1290
1322
  ```
1291
1323
 
1324
+ ## 💻 CLI Commands (v0.4.0+)
1325
+
1326
+ AbstractVoice provides powerful CLI commands for model management and voice interactions.
1327
+
1328
+ ### Model Management
1329
+
1330
+ ```bash
1331
+ # Download essential model for offline use (recommended first step)
1332
+ abstractvoice download-models
1333
+
1334
+ # Download models for specific languages
1335
+ abstractvoice download-models --language fr # French
1336
+ abstractvoice download-models --language de # German
1337
+ abstractvoice download-models --language it # Italian
1338
+ abstractvoice download-models --language es # Spanish
1339
+
1340
+ # Download specific model by name
1341
+ abstractvoice download-models --model tts_models/fr/css10/vits
1342
+
1343
+ # Download all available models (large download!)
1344
+ abstractvoice download-models --all
1345
+
1346
+ # Check current cache status
1347
+ abstractvoice download-models --status
1348
+
1349
+ # Clear model cache
1350
+ abstractvoice download-models --clear
1351
+ ```
1352
+
1353
+ ### Voice Interface
1354
+
1355
+ ```bash
1356
+ # Start voice interface (default)
1357
+ abstractvoice
1358
+
1359
+ # Start CLI REPL with specific language
1360
+ abstractvoice cli --language fr
1361
+
1362
+ # Start with specific model
1363
+ abstractvoice --model granite3.3:2b --language de
1364
+
1365
+ # Run simple example
1366
+ abstractvoice simple
1367
+
1368
+ # Check dependencies
1369
+ abstractvoice check-deps
1370
+ ```
1371
+
1372
+ ### CLI Voice Commands
1373
+
1374
+ In the CLI REPL, use these commands:
1375
+
1376
+ ```bash
1377
+ # List all available voices with download status
1378
+ /setvoice
1379
+
1380
+ # Download and set specific voice
1381
+ /setvoice fr.css10_vits # French CSS10 VITS
1382
+ /setvoice de.thorsten_vits # German Thorsten
1383
+ /setvoice it.mai_male_vits # Italian Male
1384
+
1385
+ # Change language
1386
+ /language fr
1387
+ /language de
1388
+
1389
+ # Voice controls
1390
+ /pause # Pause current speech
1391
+ /resume # Resume speech
1392
+ /stop # Stop speech
1393
+
1394
+ # Exit
1395
+ /exit
1396
+ ```
1397
+
1292
1398
  ## Perspectives
1293
1399
 
1294
1400
  This is a test project that I designed with examples to work with Ollama, but I will adapt the examples and abstractvoice to work with any LLM provider (anthropic, openai, etc).
@@ -82,34 +82,58 @@ AbstractVoice automatically detects espeak-ng and upgrades to premium quality vo
82
82
 
83
83
  ## Quick Start
84
84
 
85
- ### Basic Usage (Minimal Installation)
85
+ ### Instant TTS (v0.4.0+)
86
86
 
87
87
  ```python
88
- # First install with minimal dependencies
89
- # pip install abstractvoice
90
-
91
88
  from abstractvoice import VoiceManager
92
89
 
93
- # This will show a helpful error message with installation instructions
94
- try:
95
- vm = VoiceManager()
96
- except ImportError as e:
97
- print(e) # Shows: "TTS functionality requires optional dependencies..."
98
- # Follow the instructions to install: pip install abstractvoice[all]
90
+ # Initialize voice manager - automatically downloads essential model if needed
91
+ vm = VoiceManager()
92
+
93
+ # Text-to-speech works immediately!
94
+ vm.speak("Hello! TTS works out of the box!")
99
95
  ```
100
96
 
101
- ### Full Usage Example
97
+ **That's it!** AbstractVoice v0.4.0+ automatically:
98
+ - ✅ Downloads essential English model (107MB) on first use
99
+ - ✅ Caches models permanently for offline use
100
+ - ✅ Works immediately after first setup
101
+ - ✅ No complex configuration needed
102
102
 
103
- ```python
104
- # After installing with: pip install abstractvoice[all]
103
+ ### 🌍 Multi-Language Support
105
104
 
106
- from abstractvoice import VoiceManager
105
+ ```python
106
+ # Download and use French voice
107
+ vm.download_model('fr.css10_vits') # Downloads automatically
108
+ vm.set_language('fr')
109
+ vm.speak("Bonjour! Je parle français maintenant.")
110
+
111
+ # Download and use German voice
112
+ vm.download_model('de.thorsten_vits')
113
+ vm.set_language('de')
114
+ vm.speak("Hallo! Ich spreche jetzt Deutsch.")
115
+ ```
107
116
 
108
- # Initialize voice manager
109
- vm = VoiceManager(language='en', debug_mode=True)
117
+ ### 🔧 Check System Status
110
118
 
111
- # Text-to-speech
112
- vm.speak("Hello! I can speak text and listen for responses.")
119
+ ```python
120
+ from abstractvoice import is_ready, get_status, list_models
121
+ import json
122
+
123
+ # Quick readiness check
124
+ ready = is_ready()
125
+ print(f"TTS ready: {ready}")
126
+
127
+ # Get detailed status
128
+ status = json.loads(get_status())
129
+ print(f"Models cached: {status['total_cached']}")
130
+ print(f"Offline ready: {status['ready_for_offline']}")
131
+
132
+ # List all available models
133
+ models = json.loads(list_models())
134
+ for lang, voices in models.items():
135
+ print(f"{lang}: {len(voices)} voices available")
136
+ ```
113
137
 
114
138
  # Speech-to-text with callbacks
115
139
  def on_transcription(text):
@@ -1207,6 +1231,80 @@ voice_manager.listen(
1207
1231
  )
1208
1232
  ```
1209
1233
 
1234
+ ## 💻 CLI Commands (v0.4.0+)
1235
+
1236
+ AbstractVoice provides powerful CLI commands for model management and voice interactions.
1237
+
1238
+ ### Model Management
1239
+
1240
+ ```bash
1241
+ # Download essential model for offline use (recommended first step)
1242
+ abstractvoice download-models
1243
+
1244
+ # Download models for specific languages
1245
+ abstractvoice download-models --language fr # French
1246
+ abstractvoice download-models --language de # German
1247
+ abstractvoice download-models --language it # Italian
1248
+ abstractvoice download-models --language es # Spanish
1249
+
1250
+ # Download specific model by name
1251
+ abstractvoice download-models --model tts_models/fr/css10/vits
1252
+
1253
+ # Download all available models (large download!)
1254
+ abstractvoice download-models --all
1255
+
1256
+ # Check current cache status
1257
+ abstractvoice download-models --status
1258
+
1259
+ # Clear model cache
1260
+ abstractvoice download-models --clear
1261
+ ```
1262
+
1263
+ ### Voice Interface
1264
+
1265
+ ```bash
1266
+ # Start voice interface (default)
1267
+ abstractvoice
1268
+
1269
+ # Start CLI REPL with specific language
1270
+ abstractvoice cli --language fr
1271
+
1272
+ # Start with specific model
1273
+ abstractvoice --model granite3.3:2b --language de
1274
+
1275
+ # Run simple example
1276
+ abstractvoice simple
1277
+
1278
+ # Check dependencies
1279
+ abstractvoice check-deps
1280
+ ```
1281
+
1282
+ ### CLI Voice Commands
1283
+
1284
+ In the CLI REPL, use these commands:
1285
+
1286
+ ```bash
1287
+ # List all available voices with download status
1288
+ /setvoice
1289
+
1290
+ # Download and set specific voice
1291
+ /setvoice fr.css10_vits # French CSS10 VITS
1292
+ /setvoice de.thorsten_vits # German Thorsten
1293
+ /setvoice it.mai_male_vits # Italian Male
1294
+
1295
+ # Change language
1296
+ /language fr
1297
+ /language de
1298
+
1299
+ # Voice controls
1300
+ /pause # Pause current speech
1301
+ /resume # Resume speech
1302
+ /stop # Stop speech
1303
+
1304
+ # Exit
1305
+ /exit
1306
+ ```
1307
+
1210
1308
  ## Perspectives
1211
1309
 
1212
1310
  This is a test project that I designed with examples to work with Ollama, but I will adapt the examples and abstractvoice to work with any LLM provider (anthropic, openai, etc).
@@ -29,5 +29,8 @@ warnings.filterwarnings(
29
29
  # Import the main class for public API
30
30
  from .voice_manager import VoiceManager
31
31
 
32
- __version__ = "0.3.1"
33
- __all__ = ['VoiceManager']
32
+ # Import simple APIs for third-party applications
33
+ from .simple_model_manager import list_models, download_model, get_status, is_ready
34
+
35
+ __version__ = "0.4.6"
36
+ __all__ = ['VoiceManager', 'list_models', 'download_model', 'get_status', 'is_ready']
@@ -38,7 +38,7 @@ class VoiceREPL(cmd.Cmd):
38
38
  use_rawinput = True
39
39
 
40
40
  def __init__(self, api_url="http://localhost:11434/api/chat",
41
- model="granite3.3:2b", debug_mode=False, language="en", tts_model=None):
41
+ model="granite3.3:2b", debug_mode=False, language="en", tts_model=None, disable_tts=False):
42
42
  super().__init__()
43
43
 
44
44
  # Debug mode
@@ -54,11 +54,15 @@ class VoiceREPL(cmd.Cmd):
54
54
  self.current_language = language
55
55
 
56
56
  # Initialize voice manager with language support
57
- self.voice_manager = VoiceManager(
58
- language=language,
59
- tts_model=tts_model,
60
- debug_mode=debug_mode
61
- )
57
+ if disable_tts:
58
+ self.voice_manager = None
59
+ print("🔇 TTS disabled - text-only mode")
60
+ else:
61
+ self.voice_manager = VoiceManager(
62
+ language=language,
63
+ tts_model=tts_model,
64
+ debug_mode=debug_mode
65
+ )
62
66
 
63
67
  # Settings
64
68
  self.use_tts = True
@@ -90,8 +94,11 @@ class VoiceREPL(cmd.Cmd):
90
94
  def _get_intro(self):
91
95
  """Generate intro message with help."""
92
96
  intro = f"\n{Colors.BOLD}Welcome to AbstractVoice CLI REPL{Colors.END}\n"
93
- lang_name = self.voice_manager.get_language_name()
94
- intro += f"API: {self.api_url} | Model: {self.model} | Voice: {lang_name}\n"
97
+ if self.voice_manager:
98
+ lang_name = self.voice_manager.get_language_name()
99
+ intro += f"API: {self.api_url} | Model: {self.model} | Voice: {lang_name}\n"
100
+ else:
101
+ intro += f"API: {self.api_url} | Model: {self.model} | Voice: Disabled\n"
95
102
  intro += f"\n{Colors.CYAN}Quick Start:{Colors.END}\n"
96
103
  intro += " • Type messages to chat with the LLM\n"
97
104
  intro += " • Use /voice <mode> to enable voice input\n"
@@ -232,7 +239,7 @@ class VoiceREPL(cmd.Cmd):
232
239
  print(f"{Colors.CYAN}{response_text}{Colors.END}")
233
240
 
234
241
  # Speak the response if voice manager is available
235
- if self.voice_manager:
242
+ if self.voice_manager and self.use_tts:
236
243
  self.voice_manager.speak(response_text)
237
244
 
238
245
  except requests.exceptions.ConnectionError as e:
@@ -376,18 +383,47 @@ class VoiceREPL(cmd.Cmd):
376
383
  /setvoice <voice_id> # Set voice (format: language.voice_id)
377
384
 
378
385
  Examples:
379
- /setvoice # List all voices
386
+ /setvoice # List all voices with JSON-like info
380
387
  /setvoice fr.css10_vits # Set French CSS10 VITS voice
381
388
  /setvoice it.mai_male_vits # Set Italian male VITS voice
382
389
  """
383
390
  if not args:
384
- # Show all available voices organized by language
391
+ # Show all available voices with metadata
385
392
  print(f"\n{Colors.CYAN}Available Voice Models:{Colors.END}")
386
- self.voice_manager.list_voices()
387
393
 
388
- print(f"\n{Colors.YELLOW}Usage:{Colors.END}")
389
- print(" /setvoice <language>.<voice_id>")
390
- print(" Example: /setvoice fr.css10_vits")
394
+ try:
395
+ models = self.voice_manager.list_available_models()
396
+
397
+ for language, voices in models.items():
398
+ # Get language name
399
+ lang_names = {
400
+ 'en': 'English', 'fr': 'French', 'es': 'Spanish',
401
+ 'de': 'German', 'it': 'Italian'
402
+ }
403
+ lang_name = lang_names.get(language, language.upper())
404
+
405
+ print(f"\n🌍 {lang_name} ({language}):")
406
+
407
+ for voice_id, voice_info in voices.items():
408
+ cached_icon = "✅" if voice_info.get('cached', False) else "📥"
409
+ quality_icon = "✨" if voice_info['quality'] == 'excellent' else "🔧"
410
+ size_text = f"{voice_info['size_mb']}MB"
411
+
412
+ print(f" {cached_icon} {quality_icon} {language}.{voice_id}")
413
+ print(f" {voice_info['name']} ({size_text})")
414
+ print(f" {voice_info['description']}")
415
+ if voice_info.get('requires_espeak', False):
416
+ print(f" ⚠️ Requires espeak-ng")
417
+
418
+ print(f"\n{Colors.YELLOW}Usage:{Colors.END}")
419
+ print(" /setvoice <language>.<voice_id>")
420
+ print(" Example: /setvoice fr.css10_vits")
421
+ print("\n📥 = Download needed ✅ = Ready ✨ = High quality 🔧 = Good quality")
422
+
423
+ except Exception as e:
424
+ print(f"❌ Error listing models: {e}")
425
+ # Fallback to old method
426
+ self.voice_manager.list_voices()
391
427
  return
392
428
 
393
429
  voice_spec = args.strip()
@@ -412,45 +448,46 @@ class VoiceREPL(cmd.Cmd):
412
448
  else:
413
449
  was_active = False
414
450
 
415
- # Set the specific voice
451
+ # Download and set the specific voice using programmatic API
416
452
  try:
417
- success = self.voice_manager.set_voice(language, voice_id)
453
+ print(f"🔄 Setting voice {voice_spec}...")
454
+
455
+ # Use the programmatic download API
456
+ success = self.voice_manager.download_model(voice_spec)
457
+
418
458
  if success:
419
- # Update current language to match the voice
420
- self.current_language = language
459
+ # Now set the language to match
460
+ success = self.voice_manager.set_language(language)
421
461
 
422
- # Get voice info for confirmation
423
- voice_info = self.voice_manager.VOICE_CATALOG.get(language, {}).get(voice_id, {})
424
- lang_name = self.voice_manager.get_language_name(language)
462
+ if success:
463
+ # Update current language
464
+ self.current_language = language
425
465
 
426
- print(f"✅ Voice changed successfully!")
427
- print(f" Language: {lang_name} ({language})")
428
- print(f" Voice: {voice_id}")
429
- if voice_info:
430
- quality_icon = "✨" if voice_info.get('quality') == 'premium' else "🔧"
431
- gender_icon = {"male": "👨", "female": "👩", "multiple": "👥"}.get(voice_info.get('gender'), "🗣️")
432
- print(f" Details: {quality_icon} {gender_icon} {voice_info.get('accent', 'Unknown accent')}")
466
+ print(f"✅ Voice set to {voice_spec}")
433
467
 
434
- # Test the new voice
435
- test_messages = {
436
- 'en': "Voice changed to English.",
437
- 'fr': "Voix changée en français.",
438
- 'es': "Voz cambiada al español.",
439
- 'de': "Stimme auf Deutsch geändert.",
440
- 'it': "Voce cambiata in italiano."
441
- }
442
- test_msg = test_messages.get(language, "Voice changed successfully.")
443
- self.voice_manager.speak(test_msg)
468
+ # Test the voice
469
+ test_messages = {
470
+ 'en': 'Voice changed to English.',
471
+ 'fr': 'Voix changée en français.',
472
+ 'es': 'Voz cambiada al español.',
473
+ 'de': 'Stimme auf Deutsch geändert.',
474
+ 'it': 'Voce cambiata in italiano.'
475
+ }
476
+ test_msg = test_messages.get(language, f'Voice changed to {language}.')
477
+ self.voice_manager.speak(test_msg)
444
478
 
445
- # Restart voice mode if it was active
446
- if was_active:
447
- self.do_voice(self.voice_mode)
479
+ # Restart voice mode if it was active
480
+ if was_active:
481
+ self.do_voice(self.voice_mode)
482
+ else:
483
+ print(f"❌ Failed to set language: {language}")
448
484
  else:
449
- print(f"❌ Failed to set voice: {voice_spec}")
450
- print(f" Run '/setvoice' to see available voices")
485
+ print(f"❌ Failed to download voice: {voice_spec}")
486
+ print(" Check your internet connection or try a different voice")
451
487
 
452
488
  except Exception as e:
453
489
  print(f"❌ Error setting voice: {e}")
490
+ print(f" Run '/setvoice' to see available voices")
454
491
  if self.debug_mode:
455
492
  import traceback
456
493
  traceback.print_exc()
@@ -11,18 +11,20 @@ from abstractvoice.examples.cli_repl import VoiceREPL
11
11
 
12
12
  def print_examples():
13
13
  """Print available examples."""
14
- print("Available examples:")
15
- print(" cli - Command-line REPL example")
16
- print(" web - Web API example")
17
- print(" simple - Simple usage example")
18
- print(" check-deps - Check dependency compatibility")
19
- print("\nUsage: abstractvoice <example> [--language <lang>] [args...]")
14
+ print("Available commands:")
15
+ print(" cli - Command-line REPL example")
16
+ print(" web - Web API example")
17
+ print(" simple - Simple usage example")
18
+ print(" check-deps - Check dependency compatibility")
19
+ print(" download-models - Download TTS models for offline use")
20
+ print("\nUsage: abstractvoice <command> [--language <lang>] [args...]")
20
21
  print("\nSupported languages: en, fr, es, de, it, ru, multilingual")
21
22
  print("\nExamples:")
22
- print(" abstractvoice cli --language fr # French CLI")
23
- print(" abstractvoice simple --language ru # Russian simple example")
24
- print(" abstractvoice check-deps # Check dependencies")
25
- print(" abstractvoice # Direct voice mode (default)")
23
+ print(" abstractvoice cli --language fr # French CLI")
24
+ print(" abstractvoice simple --language ru # Russian simple example")
25
+ print(" abstractvoice check-deps # Check dependencies")
26
+ print(" abstractvoice download-models # Download models for offline use")
27
+ print(" abstractvoice # Direct voice mode (default)")
26
28
 
27
29
  def simple_example():
28
30
  """Run a simple example demonstrating basic usage."""
@@ -95,10 +97,22 @@ def simple_example():
95
97
 
96
98
  def parse_args():
97
99
  """Parse command line arguments."""
100
+ import sys
101
+
102
+ # Check if it's a download-models command and handle separately
103
+ if len(sys.argv) > 1 and sys.argv[1] == "download-models":
104
+ # Return early with just the command to handle in main()
105
+ class DownloadModelsArgs:
106
+ command = "download-models"
107
+ # Add dummy attributes to prevent AttributeError
108
+ model = "granite3.3:2b"
109
+ debug = False
110
+ return DownloadModelsArgs()
111
+
98
112
  parser = argparse.ArgumentParser(description="AbstractVoice - Voice interactions with AI")
99
113
 
100
114
  # Examples and special commands
101
- parser.add_argument("command", nargs="?", help="Command to run: cli, web, simple, check-deps (default: voice mode)")
115
+ parser.add_argument("command", nargs="?", help="Command to run: cli, web, simple, check-deps, download-models (default: voice mode)")
102
116
 
103
117
  # Voice mode arguments
104
118
  parser.add_argument("--debug", action="store_true", help="Enable debug mode")
@@ -110,6 +124,8 @@ def parse_args():
110
124
  help="Whisper model to use (tiny, base, small, medium, large)")
111
125
  parser.add_argument("--no-listening", action="store_true",
112
126
  help="Disable speech-to-text (listening), TTS still works")
127
+ parser.add_argument("--no-tts", action="store_true",
128
+ help="Disable text-to-speech (TTS), text-only mode")
113
129
  parser.add_argument("--system",
114
130
  help="Custom system prompt")
115
131
  parser.add_argument("--temperature", type=float, default=0.4,
@@ -141,6 +157,17 @@ def main():
141
157
  import traceback
142
158
  traceback.print_exc()
143
159
  return
160
+ elif args.command == "download-models":
161
+ from abstractvoice.simple_model_manager import download_models_cli
162
+ # Pass remaining arguments to download_models_cli
163
+ import sys
164
+ original_argv = sys.argv
165
+ sys.argv = ["download-models"] + sys.argv[2:] # Remove script name and "download-models"
166
+ try:
167
+ download_models_cli()
168
+ finally:
169
+ sys.argv = original_argv
170
+ return
144
171
  elif args.command == "cli":
145
172
  # Import and run CLI REPL example
146
173
  repl = VoiceREPL(
@@ -188,7 +215,8 @@ def main():
188
215
  model=args.model,
189
216
  debug_mode=args.debug,
190
217
  language=args.language,
191
- tts_model=args.tts_model
218
+ tts_model=args.tts_model,
219
+ disable_tts=args.no_tts
192
220
  )
193
221
 
194
222
  # Set custom system prompt if provided
@@ -224,22 +252,30 @@ def main():
224
252
  print("\nExiting AbstractVoice...")
225
253
  except Exception as e:
226
254
  error_msg = str(e).lower()
227
- if "model file not found" in error_msg or "no such file" in error_msg:
228
- print(f"❌ Model '{args.model}' not found")
229
- print(f" The model file is missing or not fully downloaded")
230
- print(f" Try: ollama pull {args.model}")
231
- print(f" Or check available models: ollama list")
232
- elif "connection" in error_msg or "refused" in error_msg:
233
- print(f" Cannot connect to Ollama")
255
+
256
+ # Check if it's a TTS-related error (not Ollama model error)
257
+ if "model file not found in the output path" in error_msg:
258
+ print(f" TTS model download failed")
259
+ print(f" This is a TTS voice model issue, not your Ollama model")
260
+ print(f" Your Ollama model '{args.model}' is fine")
261
+ print(f" Try: rm -rf ~/.cache/tts && pip install --force-reinstall coqui-tts")
262
+ print(f" Or check network connectivity for model downloads")
263
+ elif "ollama" in error_msg or "11434" in error_msg:
264
+ print(f"❌ Cannot connect to Ollama at {args.api}")
234
265
  print(f" Make sure Ollama is running: ollama serve")
235
- print(f" API URL: {args.api}")
266
+ print(f" Your model '{args.model}' exists but Ollama server isn't responding")
236
267
  elif "importerror" in error_msg or "no module" in error_msg:
237
268
  print(f"❌ Missing dependencies")
238
269
  print(f" Try running: abstractvoice check-deps")
239
270
  print(f" Or install dependencies: pip install abstractvoice[voice-full]")
271
+ elif "espeak" in error_msg or "phoneme" in error_msg:
272
+ print(f"❌ Voice synthesis setup issue")
273
+ print(f" Install espeak-ng for better voice quality: brew install espeak-ng")
274
+ print(f" Or this might be a TTS model download issue")
240
275
  else:
241
276
  print(f"❌ Application error: {e}")
242
277
  print(f" Try running with --debug for more details")
278
+ print(f" Note: Your Ollama model '{args.model}' appears to be available")
243
279
 
244
280
  if args.debug:
245
281
  import traceback