s2t-py 0.1.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.
s2t_py-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Draxon
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
s2t_py-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,144 @@
1
+ Metadata-Version: 2.4
2
+ Name: s2t-py
3
+ Version: 0.1.0
4
+ Summary: Fast, multimodal speech-to-text CLI powered by DraxonLLMs
5
+ Author: Draxon
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/DraxonV1/Speech2Text
8
+ Project-URL: Repository, https://github.com/DraxonV1/Speech2Text
9
+ Project-URL: Issues, https://github.com/DraxonV1/Speech2Text/issues
10
+ Keywords: speech-to-text,audio,transcription,llm,draxonllms,cli,gemini,qwen
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.8
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
23
+ Requires-Python: >=3.8
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: requests>=2.28.0
27
+ Dynamic: license-file
28
+
29
+ # s2t (Speech-to-Text CLI)
30
+
31
+ A lightweight CLI tool for transcribing audio (`.mp3`, `.opus`, `.m4a`, `.wav`, `.flac`, `.ogg`, etc.) directly to plain text or clean multi-page PDF documents using [DraxonLLMs](https://ai.draxon.one).
32
+
33
+ ## Features
34
+
35
+ - **Multi-Format Support**: Handles `.mp3`, `.opus`, `.m4a`, `.wav`, `.flac`, `.ogg`, etc. Auto-normalizes inputs to 16kHz mono WAV via `ffmpeg` if available.
36
+ - **Multilingual LLM Audio Models**: Powered by audio-native models (`gemini-flash`, `gemini-pro`, `qwen3.8-omni-flash`, `mimo-v2.5-asr`).
37
+ - **Flexible Outputs**:
38
+ - Direct raw text to `stdout`
39
+ - Output to plain text file (`.txt`)
40
+ - Standalone multi-page PDF export (`.pdf`) with automatic page wrapping and zero external dependencies
41
+ - **Live Streaming**: Stream tokens directly to terminal in real-time (`--stream`).
42
+
43
+ ---
44
+
45
+ ## Installation
46
+
47
+ ### Via pip:
48
+
49
+ ```bash
50
+ pip install s2t-py
51
+ ```
52
+
53
+ ### From source:
54
+
55
+ ```bash
56
+ git clone https://github.com/DraxonV1/Speech2Text.git
57
+ cd Speech2Text
58
+ pip install -e .
59
+ ```
60
+
61
+ ---
62
+
63
+ ## Quickstart
64
+
65
+ ### 1. Set API Key
66
+
67
+ Set your DraxonLLMs API key via environment variable:
68
+
69
+ ```bash
70
+ # Linux / macOS
71
+ export DRAXON_API_KEY="drx_your_api_key_here"
72
+
73
+ # Windows PowerShell
74
+ $env:DRAXON_API_KEY="drx_your_api_key_here"
75
+
76
+ # Windows Command Prompt
77
+ set DRAXON_API_KEY=drx_your_api_key_here
78
+ ```
79
+
80
+ *(You can also pass it explicitly with `--api-key="drx_..."`)*
81
+
82
+ ### 2. Transcribe Audio
83
+
84
+ #### Print raw text directly to terminal:
85
+ ```bash
86
+ s2t --input=voice.opus
87
+ ```
88
+
89
+ #### Output to plain text file:
90
+ ```bash
91
+ s2t --input=meeting.mp3 --output=transcript.txt
92
+ ```
93
+
94
+ #### Output to formatted PDF document:
95
+ ```bash
96
+ s2t --input=interview.m4a --output=interview.pdf
97
+ ```
98
+
99
+ #### Real-time streaming transcription:
100
+ ```bash
101
+ s2t --input=speech.wav --stream
102
+ ```
103
+
104
+ ---
105
+
106
+ ## CLI Options
107
+
108
+ ```text
109
+ usage: s2t [-h] -i INPUT [-o OUTPUT] [--api-key API_KEY] [--api-base API_BASE]
110
+ [--model MODEL] [--stream]
111
+
112
+ options:
113
+ -h, --help show this help message and exit
114
+ -i INPUT, --input INPUT
115
+ Input audio file (.mp3, .opus, .m4a, .wav, etc.)
116
+ -o OUTPUT, --output OUTPUT
117
+ Output file (.txt or .pdf). If omitted, prints raw text to stdout.
118
+ --api-key API_KEY DraxonLLMs API key (default: env DRAXON_API_KEY)
119
+ --api-base API_BASE API base URL (default: https://ai.draxon.one/api/v1)
120
+ --model MODEL Model name (default: gemini-flash)
121
+ --stream Stream raw text from model in real time
122
+ ```
123
+
124
+ ---
125
+
126
+ ## Supported Models
127
+
128
+ Refer to `models.txt` for the current audio model roster:
129
+
130
+ - `gemini-flash` *(default)*: High accuracy, low latency, multilingual (English, Hindi, Spanish, etc.)
131
+ - `gemini-pro`: Maximum reasoning and contextual transcription
132
+ - `qwen3.8-omni-flash`: Omni-channel audio model
133
+ - `mimo-v2.5-asr`: Specialized Chinese speech recognition
134
+
135
+ To select a different model:
136
+ ```bash
137
+ s2t --input=audio.mp3 --model=gemini-pro
138
+ ```
139
+
140
+ ---
141
+
142
+ ## License
143
+
144
+ MIT
s2t_py-0.1.0/README.md ADDED
@@ -0,0 +1,116 @@
1
+ # s2t (Speech-to-Text CLI)
2
+
3
+ A lightweight CLI tool for transcribing audio (`.mp3`, `.opus`, `.m4a`, `.wav`, `.flac`, `.ogg`, etc.) directly to plain text or clean multi-page PDF documents using [DraxonLLMs](https://ai.draxon.one).
4
+
5
+ ## Features
6
+
7
+ - **Multi-Format Support**: Handles `.mp3`, `.opus`, `.m4a`, `.wav`, `.flac`, `.ogg`, etc. Auto-normalizes inputs to 16kHz mono WAV via `ffmpeg` if available.
8
+ - **Multilingual LLM Audio Models**: Powered by audio-native models (`gemini-flash`, `gemini-pro`, `qwen3.8-omni-flash`, `mimo-v2.5-asr`).
9
+ - **Flexible Outputs**:
10
+ - Direct raw text to `stdout`
11
+ - Output to plain text file (`.txt`)
12
+ - Standalone multi-page PDF export (`.pdf`) with automatic page wrapping and zero external dependencies
13
+ - **Live Streaming**: Stream tokens directly to terminal in real-time (`--stream`).
14
+
15
+ ---
16
+
17
+ ## Installation
18
+
19
+ ### Via pip:
20
+
21
+ ```bash
22
+ pip install s2t-py
23
+ ```
24
+
25
+ ### From source:
26
+
27
+ ```bash
28
+ git clone https://github.com/DraxonV1/Speech2Text.git
29
+ cd Speech2Text
30
+ pip install -e .
31
+ ```
32
+
33
+ ---
34
+
35
+ ## Quickstart
36
+
37
+ ### 1. Set API Key
38
+
39
+ Set your DraxonLLMs API key via environment variable:
40
+
41
+ ```bash
42
+ # Linux / macOS
43
+ export DRAXON_API_KEY="drx_your_api_key_here"
44
+
45
+ # Windows PowerShell
46
+ $env:DRAXON_API_KEY="drx_your_api_key_here"
47
+
48
+ # Windows Command Prompt
49
+ set DRAXON_API_KEY=drx_your_api_key_here
50
+ ```
51
+
52
+ *(You can also pass it explicitly with `--api-key="drx_..."`)*
53
+
54
+ ### 2. Transcribe Audio
55
+
56
+ #### Print raw text directly to terminal:
57
+ ```bash
58
+ s2t --input=voice.opus
59
+ ```
60
+
61
+ #### Output to plain text file:
62
+ ```bash
63
+ s2t --input=meeting.mp3 --output=transcript.txt
64
+ ```
65
+
66
+ #### Output to formatted PDF document:
67
+ ```bash
68
+ s2t --input=interview.m4a --output=interview.pdf
69
+ ```
70
+
71
+ #### Real-time streaming transcription:
72
+ ```bash
73
+ s2t --input=speech.wav --stream
74
+ ```
75
+
76
+ ---
77
+
78
+ ## CLI Options
79
+
80
+ ```text
81
+ usage: s2t [-h] -i INPUT [-o OUTPUT] [--api-key API_KEY] [--api-base API_BASE]
82
+ [--model MODEL] [--stream]
83
+
84
+ options:
85
+ -h, --help show this help message and exit
86
+ -i INPUT, --input INPUT
87
+ Input audio file (.mp3, .opus, .m4a, .wav, etc.)
88
+ -o OUTPUT, --output OUTPUT
89
+ Output file (.txt or .pdf). If omitted, prints raw text to stdout.
90
+ --api-key API_KEY DraxonLLMs API key (default: env DRAXON_API_KEY)
91
+ --api-base API_BASE API base URL (default: https://ai.draxon.one/api/v1)
92
+ --model MODEL Model name (default: gemini-flash)
93
+ --stream Stream raw text from model in real time
94
+ ```
95
+
96
+ ---
97
+
98
+ ## Supported Models
99
+
100
+ Refer to `models.txt` for the current audio model roster:
101
+
102
+ - `gemini-flash` *(default)*: High accuracy, low latency, multilingual (English, Hindi, Spanish, etc.)
103
+ - `gemini-pro`: Maximum reasoning and contextual transcription
104
+ - `qwen3.8-omni-flash`: Omni-channel audio model
105
+ - `mimo-v2.5-asr`: Specialized Chinese speech recognition
106
+
107
+ To select a different model:
108
+ ```bash
109
+ s2t --input=audio.mp3 --model=gemini-pro
110
+ ```
111
+
112
+ ---
113
+
114
+ ## License
115
+
116
+ MIT
@@ -0,0 +1,40 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "s2t-py"
7
+ version = "0.1.0"
8
+ description = "Fast, multimodal speech-to-text CLI powered by DraxonLLMs"
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ license = { text = "MIT" }
12
+ authors = [
13
+ { name = "Draxon" }
14
+ ]
15
+ keywords = ["speech-to-text", "audio", "transcription", "llm", "draxonllms", "cli", "gemini", "qwen"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Environment :: Console",
19
+ "Intended Audience :: Developers",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Operating System :: OS Independent",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3.8",
24
+ "Programming Language :: Python :: 3.9",
25
+ "Programming Language :: Python :: 3.10",
26
+ "Programming Language :: Python :: 3.11",
27
+ "Programming Language :: Python :: 3.12",
28
+ "Topic :: Multimedia :: Sound/Audio :: Speech",
29
+ ]
30
+ dependencies = [
31
+ "requests>=2.28.0",
32
+ ]
33
+
34
+ [project.scripts]
35
+ s2t = "s2t:cli"
36
+
37
+ [project.urls]
38
+ Homepage = "https://github.com/DraxonV1/Speech2Text"
39
+ Repository = "https://github.com/DraxonV1/Speech2Text"
40
+ Issues = "https://github.com/DraxonV1/Speech2Text/issues"
s2t_py-0.1.0/s2t.py ADDED
@@ -0,0 +1,333 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ s2t - Speech-to-Text CLI using DraxonLLMs and Qwen 3.8 Omni Flash
4
+ """
5
+ from __future__ import annotations
6
+
7
+ import argparse
8
+ import base64
9
+ import json
10
+ import os
11
+ import shutil
12
+ import subprocess
13
+ import sys
14
+ import tempfile
15
+ import textwrap
16
+ from pathlib import Path
17
+ from typing import Optional
18
+
19
+ import requests
20
+
21
+ DEFAULT_API_BASE = os.environ.get("DRAXON_API_BASE", "https://ai.draxon.one/api/v1")
22
+ DEFAULT_API_KEY = os.environ.get("DRAXON_API_KEY", "drx_e1O-gFJJSaLDp9Uv_l1grVDi97vMydQ0")
23
+ DEFAULT_MODEL = os.environ.get("DRAXON_MODEL", "gemini-flash")
24
+ PROMPT = "Output only raw text nothing else, make sure every single letter in audio is outputed"
25
+
26
+
27
+ def convert_audio_to_wav(input_path: Path) -> tuple[bytes, str]:
28
+ """
29
+ Read input audio file. If ffmpeg is available and file is not already wav,
30
+ normalize to 16kHz mono WAV for maximum model fidelity.
31
+ """
32
+ ext = input_path.suffix.lower().lstrip(".")
33
+ if not input_path.exists():
34
+ raise FileNotFoundError(f"Input file not found: {input_path}")
35
+
36
+ # If already wav, read directly
37
+ if ext == "wav":
38
+ return input_path.read_bytes(), "wav"
39
+
40
+ # Check for ffmpeg
41
+ ffmpeg_bin = shutil.which("ffmpeg")
42
+ if ffmpeg_bin:
43
+ with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp:
44
+ tmp_wav = tmp.name
45
+
46
+ try:
47
+ cmd = [
48
+ ffmpeg_bin,
49
+ "-y",
50
+ "-i",
51
+ str(input_path),
52
+ "-vn",
53
+ "-ar",
54
+ "16000",
55
+ "-ac",
56
+ "1",
57
+ "-c:a",
58
+ "pcm_s16le",
59
+ tmp_wav,
60
+ ]
61
+ res = subprocess.run(cmd, capture_output=True, text=True)
62
+ if res.returncode == 0 and os.path.exists(tmp_wav) and os.path.getsize(tmp_wav) > 0:
63
+ with open(tmp_wav, "rb") as f:
64
+ data = f.read()
65
+ return data, "wav"
66
+ finally:
67
+ if os.path.exists(tmp_wav):
68
+ try:
69
+ os.remove(tmp_wav)
70
+ except Exception:
71
+ pass
72
+
73
+ # Fallback to direct raw bytes
74
+ fmt = "mp3" if ext in {"mp3", "opus", "m4a", "aac", "flac", "ogg"} else ext
75
+ return input_path.read_bytes(), fmt
76
+
77
+
78
+ def transcribe_audio(
79
+ audio_bytes: bytes,
80
+ audio_format: str,
81
+ api_key: str,
82
+ api_base: str,
83
+ model: str = DEFAULT_MODEL,
84
+ stream: bool = False,
85
+ ) -> str:
86
+ """Send audio to DraxonLLMs OpenAI-compatible chat completions endpoint."""
87
+ b64_data = base64.b64encode(audio_bytes).decode("utf-8")
88
+
89
+ payload = {
90
+ "model": model,
91
+ "messages": [
92
+ {
93
+ "role": "user",
94
+ "content": [
95
+ {"type": "text", "text": PROMPT},
96
+ {
97
+ "type": "input_audio",
98
+ "input_audio": {
99
+ "data": b64_data,
100
+ "format": audio_format,
101
+ },
102
+ },
103
+ ],
104
+ }
105
+ ],
106
+ "temperature": 0.0,
107
+ "stream": stream,
108
+ }
109
+
110
+ url = f"{api_base.rstrip('/')}/chat/completions"
111
+ headers = {
112
+ "Authorization": f"Bearer {api_key}",
113
+ "Content-Type": "application/json",
114
+ }
115
+
116
+ if stream:
117
+ resp = requests.post(url, headers=headers, json=payload, stream=True, timeout=180)
118
+ resp.raise_for_status()
119
+ collected: list[str] = []
120
+ for line in resp.iter_lines(decode_unicode=True):
121
+ if not line:
122
+ continue
123
+ if line.startswith("data: "):
124
+ data_str = line[6:].strip()
125
+ if data_str == "[DONE]":
126
+ break
127
+ try:
128
+ chunk = json.loads(data_str)
129
+ delta = chunk.get("choices", [{}])[0].get("delta", {})
130
+ val = delta.get("content") or delta.get("reasoning_content") or ""
131
+ if val:
132
+ collected.append(val)
133
+ sys.stdout.write(val)
134
+ sys.stdout.flush()
135
+ except Exception:
136
+ pass
137
+ if collected:
138
+ sys.stdout.write("\n")
139
+ sys.stdout.flush()
140
+ for attempt in range(5):
141
+ resp = requests.post(url, headers=headers, json=payload, timeout=180)
142
+ if resp.status_code == 200:
143
+ break
144
+ if resp.status_code in {429, 500, 502, 503, 504} and attempt < 4:
145
+ import time
146
+ sleep_sec = 3.0 * (attempt + 1)
147
+ time.sleep(sleep_sec)
148
+ continue
149
+ raise RuntimeError(f"API Error ({resp.status_code}): {resp.text[:300]}")
150
+
151
+ data = resp.json()
152
+ msg = data.get("choices", [{}])[0].get("message", {})
153
+ content = msg.get("content") or msg.get("reasoning_content") or ""
154
+ return (content or "").strip()
155
+
156
+
157
+ def write_pdf(text: str, output_path: Path) -> None:
158
+ """Pure Python PDF generator supporting multiline text without third-party dependencies."""
159
+ max_chars_per_line = 85
160
+ lines_per_page = 48
161
+
162
+ all_lines: list[str] = []
163
+ for paragraph in text.splitlines():
164
+ if not paragraph.strip():
165
+ all_lines.append("")
166
+ else:
167
+ wrapped = textwrap.wrap(paragraph, width=max_chars_per_line)
168
+ all_lines.extend(wrapped)
169
+
170
+ if not all_lines:
171
+ all_lines = [""]
172
+
173
+ pages_lines = [all_lines[i : i + lines_per_page] for i in range(0, len(all_lines), lines_per_page)]
174
+ num_pages = len(pages_lines)
175
+
176
+ font_obj_idx = 3 + num_pages * 2
177
+ objects: dict[int, bytes] = {}
178
+ page_obj_ids = [3 + i for i in range(num_pages)]
179
+ content_obj_ids = [3 + num_pages + i for i in range(num_pages)]
180
+
181
+ objects[1] = b"<< /Type /Catalog /Pages 2 0 R >>"
182
+ kids_str = " ".join(f"{pid} 0 R" for pid in page_obj_ids)
183
+ objects[2] = f"<< /Type /Pages /Kids [{kids_str}] /Count {num_pages} >>".encode("ascii")
184
+
185
+ for i in range(num_pages):
186
+ pid = page_obj_ids[i]
187
+ cid = content_obj_ids[i]
188
+ objects[pid] = (
189
+ f"<< /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Contents {cid} 0 R "
190
+ f"/Resources << /Font << /F1 {font_obj_idx} 0 R >> >> >>"
191
+ ).encode("ascii")
192
+
193
+ page_content = ["BT", "/F1 11 Tf", "50 740 Td", "14 TL"]
194
+ first = True
195
+ for line in pages_lines[i]:
196
+ escaped = line.replace("\\", "\\\\").replace("(", "\\(").replace(")", "\\)")
197
+ escaped = "".join(c if ord(c) < 256 else "?" for c in escaped)
198
+ if first:
199
+ page_content.append(f"({escaped}) Tj")
200
+ first = False
201
+ else:
202
+ page_content.append(f"T* ({escaped}) Tj")
203
+ page_content.append("ET")
204
+
205
+ stream_bytes = "\n".join(page_content).encode("latin1", errors="replace")
206
+ objects[cid] = (
207
+ f"<< /Length {len(stream_bytes)} >>\nstream\n".encode("ascii")
208
+ + stream_bytes
209
+ + b"\nendstream"
210
+ )
211
+
212
+ objects[font_obj_idx] = b"<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica /Encoding /WinAnsiEncoding >>"
213
+
214
+ buf = bytearray()
215
+ buf += b"%PDF-1.4\n"
216
+ total_objs = font_obj_idx
217
+ xref_offsets = [0] * (total_objs + 1)
218
+
219
+ for idx in range(1, total_objs + 1):
220
+ xref_offsets[idx] = len(buf)
221
+ buf += f"{idx} 0 obj\n".encode("ascii")
222
+ buf += objects[idx]
223
+ buf += b"\nendobj\n"
224
+
225
+ startxref = len(buf)
226
+ buf += b"0000000000 65535 f \n"
227
+ for idx in range(1, total_objs + 1):
228
+ buf += f"{xref_offsets[idx]:010d} 00000 n \n".encode("ascii")
229
+ buf += f"trailer\n<< /Size {total_objs + 1} /Root 1 0 R >>\nstartxref\n{startxref}\n%%EOF\n".encode("ascii")
230
+
231
+ output_path.parent.mkdir(parents=True, exist_ok=True)
232
+ output_path.write_bytes(buf)
233
+
234
+
235
+ def main(argv: Optional[list[str]] = None) -> int:
236
+ parser = argparse.ArgumentParser(
237
+ prog="s2t",
238
+ description="Speech-to-Text CLI using DraxonLLMs and Qwen 3.8 Omni Flash",
239
+ )
240
+ parser.add_argument(
241
+ "-i",
242
+ "--input",
243
+ required=True,
244
+ help="Input audio file (.mp3, .opus, .m4a, .wav, .flac, .ogg, etc.)",
245
+ )
246
+ parser.add_argument(
247
+ "-o",
248
+ "--output",
249
+ required=False,
250
+ default=None,
251
+ help="Output file (.txt or .pdf). If omitted, prints raw text to stdout.",
252
+ )
253
+ parser.add_argument(
254
+ "--api-key",
255
+ default=DEFAULT_API_KEY,
256
+ help="DraxonLLMs API key (default: env DRAXON_API_KEY or built-in)",
257
+ )
258
+ parser.add_argument(
259
+ "--api-base",
260
+ default=DEFAULT_API_BASE,
261
+ help="DraxonLLMs API base URL (default: env DRAXON_API_BASE or https://ai.draxon.one/api/v1)",
262
+ )
263
+ parser.add_argument(
264
+ "--model",
265
+ default=DEFAULT_MODEL,
266
+ help=f"Model identifier (default: {DEFAULT_MODEL})",
267
+ )
268
+ parser.add_argument(
269
+ "--stream",
270
+ action="store_true",
271
+ help="Stream raw text from model in real time",
272
+ )
273
+
274
+ args = parser.parse_args(argv)
275
+
276
+ input_path = Path(args.input)
277
+ if not input_path.exists():
278
+ sys.stderr.write(f"Error: input file '{args.input}' does not exist.\n")
279
+ return 1
280
+
281
+ try:
282
+ audio_bytes, audio_format = convert_audio_to_wav(input_path)
283
+ except Exception as exc:
284
+ sys.stderr.write(f"Error reading audio file: {exc}\n")
285
+ return 1
286
+
287
+ # Transcribe via DraxonLLMs
288
+ try:
289
+ raw_text = transcribe_audio(
290
+ audio_bytes=audio_bytes,
291
+ audio_format=audio_format,
292
+ api_key=args.api_key,
293
+ api_base=args.api_base,
294
+ model=args.model,
295
+ stream=args.stream and not args.output,
296
+ )
297
+ except Exception as exc:
298
+ sys.stderr.write(f"Transcription error: {exc}\n")
299
+ return 1
300
+
301
+ # Output handling
302
+ if args.output:
303
+ out_path = Path(args.output)
304
+ ext = out_path.suffix.lower()
305
+ if ext == ".pdf":
306
+ try:
307
+ write_pdf(raw_text, out_path)
308
+ print(f"Saved PDF transcription to {out_path}")
309
+ except Exception as exc:
310
+ sys.stderr.write(f"Failed to write PDF: {exc}\n")
311
+ return 1
312
+ else:
313
+ try:
314
+ out_path.parent.mkdir(parents=True, exist_ok=True)
315
+ out_path.write_text(raw_text, encoding="utf-8")
316
+ print(f"Saved text transcription to {out_path}")
317
+ except Exception as exc:
318
+ sys.stderr.write(f"Failed to write output text: {exc}\n")
319
+ return 1
320
+ else:
321
+ if not args.stream:
322
+ print(raw_text)
323
+
324
+ return 0
325
+
326
+
327
+ def cli() -> None:
328
+ """Entrypoint for setuptools / console_scripts."""
329
+ sys.exit(main())
330
+
331
+
332
+ if __name__ == "__main__":
333
+ cli()
@@ -0,0 +1,144 @@
1
+ Metadata-Version: 2.4
2
+ Name: s2t-py
3
+ Version: 0.1.0
4
+ Summary: Fast, multimodal speech-to-text CLI powered by DraxonLLMs
5
+ Author: Draxon
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/DraxonV1/Speech2Text
8
+ Project-URL: Repository, https://github.com/DraxonV1/Speech2Text
9
+ Project-URL: Issues, https://github.com/DraxonV1/Speech2Text/issues
10
+ Keywords: speech-to-text,audio,transcription,llm,draxonllms,cli,gemini,qwen
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.8
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
23
+ Requires-Python: >=3.8
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: requests>=2.28.0
27
+ Dynamic: license-file
28
+
29
+ # s2t (Speech-to-Text CLI)
30
+
31
+ A lightweight CLI tool for transcribing audio (`.mp3`, `.opus`, `.m4a`, `.wav`, `.flac`, `.ogg`, etc.) directly to plain text or clean multi-page PDF documents using [DraxonLLMs](https://ai.draxon.one).
32
+
33
+ ## Features
34
+
35
+ - **Multi-Format Support**: Handles `.mp3`, `.opus`, `.m4a`, `.wav`, `.flac`, `.ogg`, etc. Auto-normalizes inputs to 16kHz mono WAV via `ffmpeg` if available.
36
+ - **Multilingual LLM Audio Models**: Powered by audio-native models (`gemini-flash`, `gemini-pro`, `qwen3.8-omni-flash`, `mimo-v2.5-asr`).
37
+ - **Flexible Outputs**:
38
+ - Direct raw text to `stdout`
39
+ - Output to plain text file (`.txt`)
40
+ - Standalone multi-page PDF export (`.pdf`) with automatic page wrapping and zero external dependencies
41
+ - **Live Streaming**: Stream tokens directly to terminal in real-time (`--stream`).
42
+
43
+ ---
44
+
45
+ ## Installation
46
+
47
+ ### Via pip:
48
+
49
+ ```bash
50
+ pip install s2t-py
51
+ ```
52
+
53
+ ### From source:
54
+
55
+ ```bash
56
+ git clone https://github.com/DraxonV1/Speech2Text.git
57
+ cd Speech2Text
58
+ pip install -e .
59
+ ```
60
+
61
+ ---
62
+
63
+ ## Quickstart
64
+
65
+ ### 1. Set API Key
66
+
67
+ Set your DraxonLLMs API key via environment variable:
68
+
69
+ ```bash
70
+ # Linux / macOS
71
+ export DRAXON_API_KEY="drx_your_api_key_here"
72
+
73
+ # Windows PowerShell
74
+ $env:DRAXON_API_KEY="drx_your_api_key_here"
75
+
76
+ # Windows Command Prompt
77
+ set DRAXON_API_KEY=drx_your_api_key_here
78
+ ```
79
+
80
+ *(You can also pass it explicitly with `--api-key="drx_..."`)*
81
+
82
+ ### 2. Transcribe Audio
83
+
84
+ #### Print raw text directly to terminal:
85
+ ```bash
86
+ s2t --input=voice.opus
87
+ ```
88
+
89
+ #### Output to plain text file:
90
+ ```bash
91
+ s2t --input=meeting.mp3 --output=transcript.txt
92
+ ```
93
+
94
+ #### Output to formatted PDF document:
95
+ ```bash
96
+ s2t --input=interview.m4a --output=interview.pdf
97
+ ```
98
+
99
+ #### Real-time streaming transcription:
100
+ ```bash
101
+ s2t --input=speech.wav --stream
102
+ ```
103
+
104
+ ---
105
+
106
+ ## CLI Options
107
+
108
+ ```text
109
+ usage: s2t [-h] -i INPUT [-o OUTPUT] [--api-key API_KEY] [--api-base API_BASE]
110
+ [--model MODEL] [--stream]
111
+
112
+ options:
113
+ -h, --help show this help message and exit
114
+ -i INPUT, --input INPUT
115
+ Input audio file (.mp3, .opus, .m4a, .wav, etc.)
116
+ -o OUTPUT, --output OUTPUT
117
+ Output file (.txt or .pdf). If omitted, prints raw text to stdout.
118
+ --api-key API_KEY DraxonLLMs API key (default: env DRAXON_API_KEY)
119
+ --api-base API_BASE API base URL (default: https://ai.draxon.one/api/v1)
120
+ --model MODEL Model name (default: gemini-flash)
121
+ --stream Stream raw text from model in real time
122
+ ```
123
+
124
+ ---
125
+
126
+ ## Supported Models
127
+
128
+ Refer to `models.txt` for the current audio model roster:
129
+
130
+ - `gemini-flash` *(default)*: High accuracy, low latency, multilingual (English, Hindi, Spanish, etc.)
131
+ - `gemini-pro`: Maximum reasoning and contextual transcription
132
+ - `qwen3.8-omni-flash`: Omni-channel audio model
133
+ - `mimo-v2.5-asr`: Specialized Chinese speech recognition
134
+
135
+ To select a different model:
136
+ ```bash
137
+ s2t --input=audio.mp3 --model=gemini-pro
138
+ ```
139
+
140
+ ---
141
+
142
+ ## License
143
+
144
+ MIT
@@ -0,0 +1,10 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ s2t.py
5
+ s2t_py.egg-info/PKG-INFO
6
+ s2t_py.egg-info/SOURCES.txt
7
+ s2t_py.egg-info/dependency_links.txt
8
+ s2t_py.egg-info/entry_points.txt
9
+ s2t_py.egg-info/requires.txt
10
+ s2t_py.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ s2t = s2t:cli
@@ -0,0 +1 @@
1
+ requests>=2.28.0
@@ -0,0 +1 @@
1
+ s2t
s2t_py-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+