orbitalsai 1.1.0__tar.gz → 1.2.0__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 (49) hide show
  1. orbitalsai-1.2.0/PKG-INFO +850 -0
  2. orbitalsai-1.2.0/README.md +790 -0
  3. orbitalsai-1.2.0/examples/streaming_async.py +116 -0
  4. orbitalsai-1.2.0/examples/streaming_callbacks.py +115 -0
  5. orbitalsai-1.2.0/examples/streaming_microphone.py +165 -0
  6. orbitalsai-1.2.0/examples/streaming_sync.py +169 -0
  7. {orbitalsai-1.1.0 → orbitalsai-1.2.0}/orbitalsai/__init__.py +24 -2
  8. orbitalsai-1.2.0/orbitalsai/streaming/__init__.py +117 -0
  9. orbitalsai-1.2.0/orbitalsai/streaming/async_client.py +507 -0
  10. orbitalsai-1.2.0/orbitalsai/streaming/audio/__init__.py +33 -0
  11. orbitalsai-1.2.0/orbitalsai/streaming/audio/buffer.py +171 -0
  12. orbitalsai-1.2.0/orbitalsai/streaming/audio/converter.py +327 -0
  13. orbitalsai-1.2.0/orbitalsai/streaming/audio/formats.py +112 -0
  14. orbitalsai-1.2.0/orbitalsai/streaming/audio/source.py +317 -0
  15. orbitalsai-1.2.0/orbitalsai/streaming/client.py +384 -0
  16. orbitalsai-1.2.0/orbitalsai/streaming/config.py +207 -0
  17. orbitalsai-1.2.0/orbitalsai/streaming/connection.py +298 -0
  18. orbitalsai-1.2.0/orbitalsai/streaming/events.py +360 -0
  19. orbitalsai-1.2.0/orbitalsai/streaming/exceptions.py +179 -0
  20. orbitalsai-1.2.0/orbitalsai/streaming/protocol.py +245 -0
  21. orbitalsai-1.2.0/orbitalsai.egg-info/PKG-INFO +850 -0
  22. orbitalsai-1.2.0/orbitalsai.egg-info/SOURCES.txt +42 -0
  23. orbitalsai-1.2.0/orbitalsai.egg-info/requires.txt +30 -0
  24. {orbitalsai-1.1.0 → orbitalsai-1.2.0}/pyproject.toml +23 -3
  25. {orbitalsai-1.1.0 → orbitalsai-1.2.0}/setup.py +1 -1
  26. orbitalsai-1.1.0/PKG-INFO +0 -491
  27. orbitalsai-1.1.0/README.md +0 -448
  28. orbitalsai-1.1.0/orbitalsai.egg-info/PKG-INFO +0 -491
  29. orbitalsai-1.1.0/orbitalsai.egg-info/SOURCES.txt +0 -25
  30. orbitalsai-1.1.0/orbitalsai.egg-info/requires.txt +0 -10
  31. {orbitalsai-1.1.0 → orbitalsai-1.2.0}/.gitignore +0 -0
  32. {orbitalsai-1.1.0 → orbitalsai-1.2.0}/LICENSE +0 -0
  33. {orbitalsai-1.1.0 → orbitalsai-1.2.0}/examples/async_transcribe.py +0 -0
  34. {orbitalsai-1.1.0 → orbitalsai-1.2.0}/examples/error_handling.py +0 -0
  35. {orbitalsai-1.1.0 → orbitalsai-1.2.0}/examples/manage_balance.py +0 -0
  36. {orbitalsai-1.1.0 → orbitalsai-1.2.0}/examples/model_selection.py +0 -0
  37. {orbitalsai-1.1.0 → orbitalsai-1.2.0}/examples/model_selection_async.py +0 -0
  38. {orbitalsai-1.1.0 → orbitalsai-1.2.0}/examples/simple_transcribe.py +0 -0
  39. {orbitalsai-1.1.0 → orbitalsai-1.2.0}/examples/with_srt.py +0 -0
  40. {orbitalsai-1.1.0 → orbitalsai-1.2.0}/orbitalsai/async_client.py +0 -0
  41. {orbitalsai-1.1.0 → orbitalsai-1.2.0}/orbitalsai/client.py +0 -0
  42. {orbitalsai-1.1.0 → orbitalsai-1.2.0}/orbitalsai/exceptions.py +0 -0
  43. {orbitalsai-1.1.0 → orbitalsai-1.2.0}/orbitalsai/models.py +0 -0
  44. {orbitalsai-1.1.0 → orbitalsai-1.2.0}/orbitalsai/utils.py +0 -0
  45. {orbitalsai-1.1.0 → orbitalsai-1.2.0}/orbitalsai.egg-info/dependency_links.txt +0 -0
  46. {orbitalsai-1.1.0 → orbitalsai-1.2.0}/orbitalsai.egg-info/top_level.txt +0 -0
  47. {orbitalsai-1.1.0 → orbitalsai-1.2.0}/setup.cfg +0 -0
  48. {orbitalsai-1.1.0 → orbitalsai-1.2.0}/test_model_update.py +0 -0
  49. {orbitalsai-1.1.0 → orbitalsai-1.2.0}/tests/test_client.py +0 -0
@@ -0,0 +1,850 @@
1
+ Metadata-Version: 2.4
2
+ Name: orbitalsai
3
+ Version: 1.2.0
4
+ Summary: A simple and powerful Python SDK for the OrbitalsAI API with real-time streaming support
5
+ Home-page: https://github.com/orbitalsai/orbitalsai-python-sdk
6
+ Author: OrbitalsAI
7
+ Author-email: OrbitalsAI <support@orbitalsai.com>
8
+ Maintainer-email: OrbitalsAI <support@orbitalsai.com>
9
+ License: MIT
10
+ Project-URL: Homepage, https://github.com/orbitalsai/orbitalsai-python-sdk
11
+ Project-URL: Documentation, https://docs.orbitalsai.com
12
+ Project-URL: Repository, https://github.com/orbitalsai/orbitalsai-python-sdk
13
+ Project-URL: Bug Tracker, https://github.com/orbitalsai/orbitalsai-python-sdk/issues
14
+ Keywords: ai,transcription,audio,speech,african languages,srt,subtitles,streaming,real-time,websocket
15
+ Classifier: Development Status :: 4 - Beta
16
+ Classifier: Intended Audience :: Developers
17
+ Classifier: License :: OSI Approved :: MIT License
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.8
21
+ Classifier: Programming Language :: Python :: 3.9
22
+ Classifier: Programming Language :: Python :: 3.10
23
+ Classifier: Programming Language :: Python :: 3.11
24
+ Classifier: Programming Language :: Python :: 3.12
25
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
26
+ Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
27
+ Requires-Python: >=3.8
28
+ Description-Content-Type: text/markdown
29
+ License-File: LICENSE
30
+ Requires-Dist: requests>=2.25.0
31
+ Requires-Dist: aiohttp>=3.8.0
32
+ Requires-Dist: python-dateutil>=2.8.0
33
+ Requires-Dist: websockets>=11.0.0
34
+ Requires-Dist: numpy>=1.19.0
35
+ Provides-Extra: streaming
36
+ Requires-Dist: websockets>=11.0.0; extra == "streaming"
37
+ Requires-Dist: numpy>=1.19.0; extra == "streaming"
38
+ Provides-Extra: audio
39
+ Requires-Dist: sounddevice>=0.4.0; extra == "audio"
40
+ Requires-Dist: soundfile>=0.12.0; extra == "audio"
41
+ Requires-Dist: librosa>=0.10.0; extra == "audio"
42
+ Provides-Extra: all
43
+ Requires-Dist: websockets>=11.0.0; extra == "all"
44
+ Requires-Dist: numpy>=1.19.0; extra == "all"
45
+ Requires-Dist: sounddevice>=0.4.0; extra == "all"
46
+ Requires-Dist: soundfile>=0.12.0; extra == "all"
47
+ Requires-Dist: librosa>=0.10.0; extra == "all"
48
+ Provides-Extra: dev
49
+ Requires-Dist: pytest>=6.0; extra == "dev"
50
+ Requires-Dist: pytest-asyncio>=0.18.0; extra == "dev"
51
+ Requires-Dist: black>=21.0; extra == "dev"
52
+ Requires-Dist: flake8>=3.9; extra == "dev"
53
+ Requires-Dist: mypy>=0.910; extra == "dev"
54
+ Requires-Dist: websockets>=11.0.0; extra == "dev"
55
+ Requires-Dist: numpy>=1.19.0; extra == "dev"
56
+ Dynamic: author
57
+ Dynamic: home-page
58
+ Dynamic: license-file
59
+ Dynamic: requires-python
60
+
61
+ # OrbitalsAI Python SDK
62
+
63
+ [![PyPI version](https://badge.fury.io/py/orbitalsai.svg)](https://badge.fury.io/py/orbitalsai)
64
+ [![Python Support](https://img.shields.io/pypi/pyversions/orbitalsai.svg)](https://pypi.org/project/orbitalsai/)
65
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
66
+
67
+ Python SDK for the OrbitalsAI API. Transcribe audio files in African languages with SRT subtitle generation and real-time streaming via WebSocket.
68
+
69
+ ## Features
70
+
71
+ - **Batch Transcription** - Upload files and get transcripts
72
+ - **Real-time Streaming** - Live transcription via WebSocket
73
+ - **Sync & Async** - Works synchronously or asynchronously
74
+ - **African Languages** - Hausa, Igbo, Yoruba, Swahili, Pidgin, Kinyarwanda, English
75
+ - **SRT Subtitles** - Generate subtitle files
76
+ - **Microphone Input** - Stream from microphone
77
+ - **Usage Tracking** - Check balance and usage history
78
+ - **Auto-Reconnect** - Automatic reconnection on connection loss
79
+
80
+ ## Quick Start
81
+
82
+ ### Installation
83
+
84
+ ```bash
85
+ pip install orbitalsai
86
+ ```
87
+
88
+ For streaming with audio file support:
89
+ ```bash
90
+ pip install orbitalsai[audio]
91
+ ```
92
+
93
+ ### Basic Usage (Batch)
94
+
95
+ ```python
96
+ import orbitalsai
97
+
98
+ # Initialize client
99
+ client = orbitalsai.Client(api_key="your_api_key_here")
100
+
101
+ # Transcribe audio (waits automatically)
102
+ transcript = client.transcribe("audio.mp3")
103
+ print(transcript.text)
104
+ ```
105
+
106
+ ### Real-time Streaming
107
+
108
+ ```python
109
+ import asyncio
110
+ from orbitalsai.streaming import AsyncStreamingClient, PrintingEventHandlers
111
+
112
+ async def main():
113
+ async with AsyncStreamingClient(api_key="your_api_key") as client:
114
+ await client.connect(PrintingEventHandlers())
115
+
116
+ with open("audio.pcm", "rb") as f:
117
+ while chunk := f.read(16000):
118
+ await client.send_audio(chunk)
119
+
120
+ await client.flush()
121
+
122
+ asyncio.run(main())
123
+ ```
124
+
125
+ That's it.
126
+
127
+ ## Table of Contents
128
+
129
+ - [Installation](#installation)
130
+ - [Quick Start](#quick-start)
131
+ - [Authentication](#authentication)
132
+ - [Basic Transcription](#basic-transcription)
133
+ - [Real-time Streaming](#real-time-streaming)
134
+ - [Model Selection](#model-selection)
135
+ - [Async Usage](#async-usage)
136
+ - [Balance Management](#balance-management)
137
+ - [Error Handling](#error-handling)
138
+ - [API Reference](#api-reference)
139
+ - [Supported Languages](#supported-languages)
140
+ - [Supported Formats](#supported-formats)
141
+ - [Troubleshooting](#troubleshooting)
142
+
143
+ ## Authentication
144
+
145
+ Get your API key from the [OrbitalsAI Dashboard](https://dashboard.orbitalsai.com).
146
+
147
+ ```python
148
+ import orbitalsai
149
+
150
+ client = orbitalsai.Client(api_key="your_api_key_here")
151
+ ```
152
+
153
+ ## Basic Transcription
154
+
155
+ ### Simple Transcription
156
+
157
+ ```python
158
+ import orbitalsai
159
+
160
+ client = orbitalsai.Client(api_key="your_api_key_here")
161
+
162
+ # Transcribe audio file
163
+ transcript = client.transcribe("audio.mp3")
164
+ print(transcript.text)
165
+ ```
166
+
167
+ ### With Language and SRT
168
+
169
+ ```python
170
+ import orbitalsai
171
+
172
+ client = orbitalsai.Client(api_key="your_api_key_here")
173
+
174
+ # Transcribe in Hausa with SRT subtitles
175
+ transcript = client.transcribe(
176
+ "audio.mp3",
177
+ language="hausa",
178
+ generate_srt=True
179
+ )
180
+
181
+ print(transcript.text)
182
+ print(transcript.srt_content) # SRT subtitle content
183
+ ```
184
+
185
+ ---
186
+
187
+ ## Real-time Streaming
188
+
189
+ Stream audio and receive transcriptions in real-time via WebSocket.
190
+
191
+ ### Installation
192
+
193
+ Streaming requires additional dependencies:
194
+
195
+ ```bash
196
+ # Basic streaming
197
+ pip install orbitalsai
198
+
199
+ # With audio file conversion (MP3, WAV, etc.)
200
+ pip install orbitalsai[audio]
201
+
202
+ # With microphone support
203
+ pip install sounddevice
204
+ ```
205
+
206
+ ### Async Streaming (Recommended)
207
+
208
+ ```python
209
+ import asyncio
210
+ from orbitalsai.streaming import (
211
+ AsyncStreamingClient,
212
+ StreamingConfig,
213
+ PrintingEventHandlers,
214
+ )
215
+
216
+ async def main():
217
+ # Configure streaming
218
+ config = StreamingConfig(
219
+ language="english",
220
+ sample_rate=16000,
221
+ interim_results=True, # Get partial transcripts
222
+ )
223
+
224
+ async with AsyncStreamingClient(api_key="your_key", config=config) as client:
225
+ await client.connect(PrintingEventHandlers())
226
+
227
+ # Stream raw PCM audio
228
+ with open("audio.pcm", "rb") as f:
229
+ while chunk := f.read(16000): # 500ms chunks
230
+ await client.send_audio(chunk)
231
+ await asyncio.sleep(0.5) # Real-time pacing
232
+
233
+ await client.flush()
234
+
235
+ asyncio.run(main())
236
+ ```
237
+
238
+ ### Synchronous Streaming
239
+
240
+ ```python
241
+ import time
242
+ from orbitalsai.streaming import StreamingClient, StreamingEventHandlers
243
+
244
+ class MyHandlers(StreamingEventHandlers):
245
+ def on_transcript_partial(self, text):
246
+ print(f"Partial: {text}")
247
+
248
+ def on_transcript_final(self, text, metadata):
249
+ print(f"Final: {text}")
250
+ print(f"Cost: ${metadata['cost']:.4f}")
251
+
252
+ with StreamingClient(api_key="your_key") as client:
253
+ client.connect(MyHandlers())
254
+
255
+ with open("audio.pcm", "rb") as f:
256
+ while chunk := f.read(16000):
257
+ client.send_audio(chunk)
258
+ time.sleep(0.5)
259
+
260
+ client.flush()
261
+ ```
262
+
263
+ ### Stream from Audio Files (MP3, WAV, etc.)
264
+
265
+ ```python
266
+ import asyncio
267
+ from orbitalsai.streaming import (
268
+ AsyncStreamingClient,
269
+ PrintingEventHandlers,
270
+ AudioConverter,
271
+ )
272
+
273
+ async def stream_file(file_path: str):
274
+ # Convert any audio format to PCM16
275
+ audio_bytes, sample_rate = AudioConverter.from_file(
276
+ file_path,
277
+ target_sample_rate=16000
278
+ )
279
+
280
+ # Split into chunks
281
+ chunks = AudioConverter.split_chunks(audio_bytes, chunk_size=8000)
282
+
283
+ async with AsyncStreamingClient(api_key="your_key") as client:
284
+ await client.connect(PrintingEventHandlers())
285
+
286
+ for chunk in chunks:
287
+ await client.send_audio(chunk)
288
+ await asyncio.sleep(0.5)
289
+
290
+ await client.flush()
291
+
292
+ asyncio.run(stream_file("speech.mp3"))
293
+ ```
294
+
295
+ ### Stream from Microphone
296
+
297
+ ```python
298
+ import asyncio
299
+ import numpy as np
300
+ import sounddevice as sd
301
+ from orbitalsai.streaming import AsyncStreamingClient, PrintingEventHandlers
302
+
303
+ async def stream_microphone(duration: int = 30):
304
+ audio_queue = asyncio.Queue()
305
+
306
+ def callback(indata, frames, time_info, status):
307
+ audio_queue.put_nowait(indata.tobytes())
308
+
309
+ async with AsyncStreamingClient(api_key="your_key") as client:
310
+ await client.connect(PrintingEventHandlers())
311
+
312
+ with sd.InputStream(
313
+ samplerate=16000,
314
+ channels=1,
315
+ dtype="int16",
316
+ blocksize=8000,
317
+ callback=callback
318
+ ):
319
+ end_time = asyncio.get_event_loop().time() + duration
320
+
321
+ while asyncio.get_event_loop().time() < end_time:
322
+ audio = await asyncio.wait_for(audio_queue.get(), timeout=1.0)
323
+ await client.send_audio(audio)
324
+
325
+ await client.flush()
326
+
327
+ asyncio.run(stream_microphone(30))
328
+ ```
329
+
330
+ ### Custom Event Handlers
331
+
332
+ ```python
333
+ from orbitalsai.streaming import StreamingEventHandlers
334
+
335
+ class MyHandlers(StreamingEventHandlers):
336
+ def __init__(self):
337
+ self.transcripts = []
338
+ self.total_cost = 0.0
339
+
340
+ def on_open(self, session_info):
341
+ print(f"Connected: {session_info['session_id']}")
342
+
343
+ def on_transcript_partial(self, text):
344
+ # Partial transcripts may change
345
+ print(f"[Partial] {text}")
346
+
347
+ def on_transcript_final(self, text, metadata):
348
+ # Final transcripts are stable
349
+ self.transcripts.append(text)
350
+ self.total_cost += metadata["cost"]
351
+ print(f"[Final] {text}")
352
+ print(f" Cost: ${metadata['cost']:.4f}")
353
+ print(f" Duration: {metadata['audio_seconds']:.1f}s")
354
+
355
+ def on_speech_start(self):
356
+ print("🎤 Speech detected")
357
+
358
+ def on_speech_end(self):
359
+ print("🔇 Silence detected")
360
+
361
+ def on_credits_warning(self, remaining_percent):
362
+ print(f"⚠️ Credits low: {remaining_percent}% remaining")
363
+
364
+ def on_credits_exhausted(self):
365
+ print("❌ Credits exhausted!")
366
+
367
+ def on_error(self, error):
368
+ print(f"Error: {error}")
369
+
370
+ def on_close(self, code, reason):
371
+ print(f"Disconnected: {reason}")
372
+ ```
373
+
374
+ ### Callback-style Handlers
375
+
376
+ For simpler use cases, use `CallbackEventHandlers`:
377
+
378
+ ```python
379
+ from orbitalsai.streaming import AsyncStreamingClient, CallbackEventHandlers
380
+
381
+ handlers = CallbackEventHandlers(
382
+ on_final=lambda text, meta: print(f"Transcript: {text}"),
383
+ on_error=lambda e: print(f"Error: {e}"),
384
+ )
385
+
386
+ async with AsyncStreamingClient(api_key="your_key") as client:
387
+ await client.connect(handlers)
388
+ # ... stream audio ...
389
+ ```
390
+
391
+ ### Accumulate Transcripts
392
+
393
+ Use `StreamingTranscriptAccumulator` to collect all transcripts:
394
+
395
+ ```python
396
+ from orbitalsai.streaming import StreamingClient, StreamingTranscriptAccumulator
397
+
398
+ accumulator = StreamingTranscriptAccumulator()
399
+
400
+ with StreamingClient(api_key="your_key") as client:
401
+ client.connect(accumulator)
402
+ # ... stream audio ...
403
+ client.flush()
404
+
405
+ # Get results
406
+ print(accumulator.get_full_transcript())
407
+ print(f"Total cost: ${accumulator.total_cost:.4f}")
408
+ print(f"Total duration: {accumulator.total_seconds:.1f}s")
409
+ ```
410
+
411
+ ### Streaming Configuration
412
+
413
+ ```python
414
+ from orbitalsai.streaming import StreamingConfig
415
+
416
+ config = StreamingConfig(
417
+ # Audio settings
418
+ sample_rate=16000, # 8000-48000 Hz (16kHz recommended)
419
+ chunk_size=8000, # Samples per chunk (500ms at 16kHz)
420
+
421
+ # Language
422
+ language="english", # english, hausa, igbo, yoruba
423
+
424
+ # Connection settings
425
+ max_retries=5, # Reconnection attempts
426
+ retry_delay=1.0, # Initial retry delay (exponential backoff)
427
+ connection_timeout=30.0, # Connection timeout in seconds
428
+
429
+ # Processing
430
+ interim_results=True, # Receive partial transcripts
431
+ )
432
+ ```
433
+
434
+ ### Dynamic Configuration
435
+
436
+ Change language or sample rate during streaming:
437
+
438
+ ```python
439
+ await client.configure(language="hausa")
440
+ await client.configure(sample_rate=8000)
441
+ ```
442
+
443
+ ---
444
+
445
+ ## Model Selection
446
+
447
+ Choose which model to use for transcription. Different models have different pricing.
448
+
449
+ ### List Available Models
450
+
451
+ ```python
452
+ import orbitalsai
453
+
454
+ client = orbitalsai.Client(api_key="your_api_key_here")
455
+
456
+ # Get all available models
457
+ models = client.get_models()
458
+
459
+ for model in models:
460
+ print(f"{model.model_name}: ${model.transcription_rate_per_hour:.2f}/hour")
461
+ ```
462
+
463
+ ### Transcribe with Specific Model
464
+
465
+ ```python
466
+ import orbitalsai
467
+
468
+ client = orbitalsai.Client(api_key="your_api_key_here")
469
+
470
+ # Transcribe with Perigee-1 model
471
+ transcript = client.transcribe(
472
+ "audio.mp3",
473
+ language="hausa",
474
+ model_name="Perigee-1" # Specify the model
475
+ )
476
+
477
+ print(transcript.text)
478
+ ```
479
+
480
+ ### Choose Model Based on Budget
481
+
482
+ ```python
483
+ import orbitalsai
484
+
485
+ client = orbitalsai.Client(api_key="your_api_key_here")
486
+
487
+ # Get the cheapest available model
488
+ models = client.get_models()
489
+ cheapest_model = min(models, key=lambda m: m.transcription_rate_per_hour)
490
+
491
+ print(f"Using {cheapest_model.model_name} at ${cheapest_model.transcription_rate_per_hour:.2f}/hour")
492
+
493
+ transcript = client.transcribe(
494
+ "audio.mp3",
495
+ language="english",
496
+ model_name=cheapest_model.model_name
497
+ )
498
+ ```
499
+
500
+ ## Async Usage
501
+
502
+ For processing multiple files or use in async applications.
503
+
504
+ ```python
505
+ import asyncio
506
+ import orbitalsai
507
+
508
+ async def main():
509
+ async with orbitalsai.AsyncClient(api_key="your_api_key_here") as client:
510
+ # List available models
511
+ models = await client.get_models()
512
+ print(f"Available models: {[m.model_name for m in models]}")
513
+
514
+ # Transcribe multiple files concurrently
515
+ tasks = await asyncio.gather(
516
+ client.transcribe("audio1.mp3", model_name="Perigee-1"),
517
+ client.transcribe("audio2.wav", model_name="Perigee-1"),
518
+ client.transcribe("audio3.m4a", model_name="Perigee-1")
519
+ )
520
+
521
+ for transcript in tasks:
522
+ print(transcript.text)
523
+
524
+ asyncio.run(main())
525
+ ```
526
+
527
+ ## Balance Management
528
+
529
+ ### Check Balance
530
+
531
+ ```python
532
+ import orbitalsai
533
+
534
+ client = orbitalsai.Client(api_key="your_api_key_here")
535
+
536
+ balance = client.get_balance()
537
+ print(f"Current balance: ${balance.balance:.2f}")
538
+ print(f"Last updated: {balance.last_updated}")
539
+ ```
540
+
541
+ ### Usage History
542
+
543
+ ```python
544
+ import orbitalsai
545
+ from datetime import date, timedelta
546
+
547
+ client = orbitalsai.Client(api_key="your_api_key_here")
548
+
549
+ # Get last 7 days of usage
550
+ end_date = date.today()
551
+ start_date = end_date - timedelta(days=7)
552
+
553
+ usage = client.get_daily_usage(start_date=start_date, end_date=end_date)
554
+ print(f"Total cost: ${usage.total_cost:.2f}")
555
+ print(f"Total audio processed: {usage.total_audio_seconds:.1f} seconds")
556
+
557
+ for day in usage.daily_records:
558
+ print(f"{day.date}: ${day.total_cost:.4f} ({day.transcription_usage:.1f}s transcription)")
559
+ ```
560
+
561
+ ## Other Features
562
+
563
+ ### List All Tasks
564
+
565
+ ```python
566
+ import orbitalsai
567
+
568
+ client = orbitalsai.Client(api_key="your_api_key_here")
569
+
570
+ tasks = client.list_tasks()
571
+ for task in tasks:
572
+ print(f"Task {task.task_id}: {task.status} - {task.original_filename}")
573
+ ```
574
+
575
+ ### Get User Information
576
+
577
+ ```python
578
+ import orbitalsai
579
+
580
+ client = orbitalsai.Client(api_key="your_api_key_here")
581
+
582
+ user = client.get_user()
583
+ print(f"User: {user.first_name} {user.last_name} ({user.email})")
584
+ print(f"Verified: {user.is_verified}")
585
+ ```
586
+
587
+ ## Error Handling
588
+
589
+ ### Batch Transcription Errors
590
+
591
+ ```python
592
+ import orbitalsai
593
+ from orbitalsai.exceptions import (
594
+ AuthenticationError, InsufficientBalanceError,
595
+ UnsupportedFileError, UnsupportedLanguageError,
596
+ TranscriptionError, TimeoutError
597
+ )
598
+
599
+ client = orbitalsai.Client(api_key="your_api_key_here")
600
+
601
+ try:
602
+ transcript = client.transcribe("audio.mp3", language="hausa")
603
+ print(transcript.text)
604
+
605
+ except UnsupportedFileError:
606
+ print("File format not supported")
607
+ except UnsupportedLanguageError:
608
+ print("Language not supported")
609
+ except InsufficientBalanceError:
610
+ print("Not enough credits")
611
+ except AuthenticationError:
612
+ print("Invalid API key")
613
+ except TranscriptionError as e:
614
+ print(f"Transcription failed: {e}")
615
+ except TimeoutError:
616
+ print("Transcription timed out")
617
+ ```
618
+
619
+ ### Streaming Errors
620
+
621
+ ```python
622
+ from orbitalsai.streaming import AsyncStreamingClient, StreamingEventHandlers
623
+ from orbitalsai.streaming.exceptions import (
624
+ ConnectionError,
625
+ AuthenticationError,
626
+ InsufficientCreditsError,
627
+ ReconnectionFailedError,
628
+ SessionClosedError,
629
+ )
630
+
631
+ class MyHandlers(StreamingEventHandlers):
632
+ def on_error(self, error):
633
+ if isinstance(error, AuthenticationError):
634
+ print("Invalid API key")
635
+ elif isinstance(error, InsufficientCreditsError):
636
+ print("Credits exhausted - please top up")
637
+ elif isinstance(error, ReconnectionFailedError):
638
+ print(f"Failed to reconnect after {error.attempts} attempts")
639
+ else:
640
+ print(f"Error: {error}")
641
+
642
+ try:
643
+ async with AsyncStreamingClient(api_key="your_key") as client:
644
+ await client.connect(MyHandlers())
645
+ # ... stream audio ...
646
+ except ConnectionError as e:
647
+ print(f"Connection failed: {e}")
648
+ except SessionClosedError:
649
+ print("Session was closed")
650
+ ```
651
+
652
+ ## API Reference
653
+
654
+ ### Batch Client Methods
655
+
656
+ #### `get_models()`
657
+ Get all available AI models with their pricing information.
658
+
659
+ **Returns:** List of `Model` objects
660
+
661
+ #### `transcribe(file_path, language="english", generate_srt=False, model_name="Perigee-1", wait=True, timeout=300, poll_interval=5)`
662
+ Transcribe an audio file.
663
+
664
+ **Parameters:**
665
+ - `file_path` (str): Path to the audio file
666
+ - `language` (str): Language code (default: "english")
667
+ - `generate_srt` (bool): Generate SRT subtitles (default: False)
668
+ - `model_name` (str): AI model to use (default: "Perigee-1")
669
+ - `wait` (bool): Wait for completion (default: True)
670
+ - `timeout` (int): Maximum wait time in seconds (default: 300)
671
+ - `poll_interval` (int): Seconds between status checks (default: 5)
672
+
673
+ **Returns:** `Transcript` object (if wait=True) or `TranscriptTask` object (if wait=False)
674
+
675
+ #### `get_task(task_id)`
676
+ Get the status of a transcription task.
677
+
678
+ **Returns:** `TranscriptTask` object
679
+
680
+ #### `wait_for_task(task_id, timeout=300, poll_interval=5)`
681
+ Wait for a task to complete.
682
+
683
+ **Returns:** `Transcript` object
684
+
685
+ #### `list_tasks()`
686
+ Get all transcription tasks for the current user.
687
+
688
+ **Returns:** List of `TranscriptTask` objects
689
+
690
+ #### `get_balance()`
691
+ Get the current user's balance.
692
+
693
+ **Returns:** `Balance` object
694
+
695
+ #### `get_daily_usage(start_date=None, end_date=None, page=1, page_size=30)`
696
+ Get daily usage history for the current user.
697
+
698
+ **Returns:** `DailyUsage` object
699
+
700
+ #### `get_user()`
701
+ Get current user details.
702
+
703
+ **Returns:** `User` object
704
+
705
+ ### Streaming Client Methods
706
+
707
+ #### `connect(handlers)`
708
+ Establish WebSocket connection and start receiving events.
709
+
710
+ **Parameters:**
711
+ - `handlers` (StreamingEventHandlers): Event handler instance
712
+
713
+ #### `send_audio(audio_data)`
714
+ Send PCM16 audio chunk.
715
+
716
+ **Parameters:**
717
+ - `audio_data` (bytes): Raw PCM16 mono little-endian bytes
718
+
719
+ #### `configure(language=None, sample_rate=None)`
720
+ Update session configuration dynamically.
721
+
722
+ #### `flush()`
723
+ Force transcription of remaining audio buffer.
724
+
725
+ #### `disconnect()`
726
+ Close connection gracefully.
727
+
728
+ ### Data Models
729
+
730
+ #### `Transcript`
731
+ - `text` (str): Transcribed text
732
+ - `srt_content` (str, optional): SRT subtitle content
733
+ - `task_id` (int): Task ID
734
+ - `original_filename` (str): Original filename
735
+ - `audio_url` (str, optional): URL to processed audio
736
+
737
+ #### `TranscriptTask`
738
+ - `task_id` (int): Task ID
739
+ - `status` (str): Task status ("pending", "processing", "completed", "failed")
740
+ - `original_filename` (str): Original filename
741
+ - `audio_url` (str, optional): URL to processed audio
742
+ - `srt_requested` (bool): Whether SRT was requested
743
+ - `result_text` (str, optional): Transcribed text
744
+ - `srt_content` (str, optional): SRT subtitle content
745
+ - `error` (str, optional): Error message if failed
746
+
747
+ #### `Balance`
748
+ - `balance` (float): Current balance in credits
749
+ - `last_updated` (datetime): Last update timestamp
750
+
751
+ #### `Model`
752
+ - `id` (int): Model ID
753
+ - `model_name` (str): Name of the model (e.g., "Perigee-1")
754
+ - `transcription_rate_per_second` (float): Cost per second of audio
755
+ - `transcription_rate_per_hour` (float): Cost per hour of audio
756
+ - `is_active` (bool): Whether the model is currently available
757
+
758
+ #### `StreamingConfig`
759
+ - `sample_rate` (int): Audio sample rate (8000-48000 Hz)
760
+ - `chunk_size` (int): Samples per chunk
761
+ - `language` (str): Transcription language
762
+ - `max_retries` (int): Maximum reconnection attempts
763
+ - `retry_delay` (float): Initial retry delay
764
+ - `connection_timeout` (float): Connection timeout
765
+ - `interim_results` (bool): Whether to receive partial transcripts
766
+
767
+ ## Supported Languages
768
+
769
+ | Language | Code |
770
+ |----------|------|
771
+ | English | `english` |
772
+ | Hausa | `hausa` |
773
+ | Igbo | `igbo` |
774
+ | Yoruba | `yoruba` |
775
+ | Swahili | `swahili` |
776
+ | Pidgin | `pidgin` |
777
+ | Kinyarwanda | `kinyarwanda` |
778
+
779
+ ## Supported Formats
780
+
781
+ ### Batch Transcription
782
+ - WAV (`.wav`, `.wave`)
783
+ - MP3 (`.mp3`, `.mpeg`)
784
+ - OGG (`.ogg`, `.oga`)
785
+ - FLAC (`.flac`)
786
+ - AAC (`.aac`)
787
+ - M4A (`.m4a`)
788
+ - WMA (`.wma`)
789
+ - AMR (`.amr`)
790
+ - 3GP (`.3gp`)
791
+
792
+ ### Streaming
793
+ - **Input:** PCM16 mono little-endian (raw bytes)
794
+ - **Conversion supported:** All batch formats via `AudioConverter`
795
+
796
+ ### Maximum File Size (Batch)
797
+ - **200 MB** per file
798
+
799
+ ## Troubleshooting
800
+
801
+ ### Common Issues
802
+
803
+ **Q: I get "Invalid API key" error**
804
+ A: Make sure your API key is correct. Get it from the [OrbitalsAI Dashboard](https://dashboard.orbitalsai.com).
805
+
806
+ **Q: I get "Insufficient balance" error**
807
+ A: Add credits to your account through the dashboard.
808
+
809
+ **Q: I get "Unsupported file format" error**
810
+ A: Make sure your audio file is in a supported format (see [Supported Formats](#supported-formats)).
811
+
812
+ **Q: Transcription takes too long**
813
+ A: Large files take longer to process. You can increase the timeout:
814
+ ```python
815
+ transcript = client.transcribe("large_file.mp3", timeout=600) # 10 minutes
816
+ ```
817
+
818
+ **Q: Streaming connection keeps dropping**
819
+ A: The SDK auto-reconnects with exponential backoff. You can configure this:
820
+ ```python
821
+ config = StreamingConfig(max_retries=10, retry_delay=2.0)
822
+ ```
823
+
824
+ **Q: How do I convert audio files for streaming?**
825
+ A: Use the `AudioConverter` utility:
826
+ ```python
827
+ from orbitalsai.streaming import AudioConverter
828
+ audio_bytes, sample_rate = AudioConverter.from_file("speech.mp3")
829
+ ```
830
+
831
+ **Q: Streaming shows "Credits exhausted"**
832
+ A: Your account ran out of credits during streaming. The connection will close automatically. Top up your credits and reconnect.
833
+
834
+ ### Getting Help
835
+
836
+ - 📧 Email: support@orbitalsai.com
837
+ - 🐛 Issues: [GitHub Issues](https://github.com/orbitalsai/orbitalsai-python-sdk/issues)
838
+ - 📖 Docs: [Documentation](https://docs.orbitalsai.com)
839
+
840
+ ## License
841
+
842
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
843
+
844
+ ## Contributing
845
+
846
+ Contributions are welcome! Please feel free to submit a Pull Request.
847
+
848
+ ---
849
+
850
+ Made by OrbitalsAI