edgespeak 0.6.4__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.
- edgespeak-0.6.4/MANIFEST.in +3 -0
- edgespeak-0.6.4/PKG-INFO +120 -0
- edgespeak-0.6.4/README.md +106 -0
- edgespeak-0.6.4/README.zh-CN.md +95 -0
- edgespeak-0.6.4/examples/_common.py +18 -0
- edgespeak-0.6.4/examples/align.py +48 -0
- edgespeak-0.6.4/examples/segment.py +31 -0
- edgespeak-0.6.4/examples/speakers.py +23 -0
- edgespeak-0.6.4/examples/transcribe.py +41 -0
- edgespeak-0.6.4/pyproject.toml +28 -0
- edgespeak-0.6.4/setup.cfg +4 -0
- edgespeak-0.6.4/src/edgespeak/__init__.py +10 -0
- edgespeak-0.6.4/src/edgespeak/_bootstrap.py +246 -0
- edgespeak-0.6.4/src/edgespeak/_client.py +568 -0
- edgespeak-0.6.4/src/edgespeak/_errors.py +65 -0
- edgespeak-0.6.4/src/edgespeak/_process.py +137 -0
- edgespeak-0.6.4/src/edgespeak/_reference.py +45 -0
- edgespeak-0.6.4/src/edgespeak/_streaming.py +115 -0
- edgespeak-0.6.4/src/edgespeak/_types.py +10 -0
- edgespeak-0.6.4/src/edgespeak/_version.py +3 -0
- edgespeak-0.6.4/src/edgespeak/py.typed +0 -0
- edgespeak-0.6.4/src/edgespeak.egg-info/PKG-INFO +120 -0
- edgespeak-0.6.4/src/edgespeak.egg-info/SOURCES.txt +32 -0
- edgespeak-0.6.4/src/edgespeak.egg-info/dependency_links.txt +1 -0
- edgespeak-0.6.4/src/edgespeak.egg-info/requires.txt +5 -0
- edgespeak-0.6.4/src/edgespeak.egg-info/top_level.txt +1 -0
- edgespeak-0.6.4/tests/test_bootstrap.py +216 -0
- edgespeak-0.6.4/tests/test_cli_integration.py +142 -0
- edgespeak-0.6.4/tests/test_client.py +272 -0
- edgespeak-0.6.4/tests/test_errors.py +42 -0
- edgespeak-0.6.4/tests/test_examples.py +61 -0
- edgespeak-0.6.4/tests/test_speech_features.py +432 -0
- edgespeak-0.6.4/tests/test_version.py +17 -0
- edgespeak-0.6.4/tests/typing/public_api.py +41 -0
edgespeak-0.6.4/PKG-INFO
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: edgespeak
|
|
3
|
+
Version: 0.6.4
|
|
4
|
+
Summary: Python client for the local EdgeSpeak CLI runtime
|
|
5
|
+
Project-URL: Documentation, https://edgespeak.com/docs/python-sdk
|
|
6
|
+
Project-URL: Source, https://github.com/lattifai/EdgeSpeak/tree/main/sdk/python
|
|
7
|
+
Project-URL: Issues, https://github.com/lattifai/EdgeSpeak/issues
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
Requires-Dist: httpx<1,>=0.27
|
|
11
|
+
Provides-Extra: dev
|
|
12
|
+
Requires-Dist: mypy==1.20.2; extra == "dev"
|
|
13
|
+
Requires-Dist: typing_extensions>=4.6; extra == "dev"
|
|
14
|
+
|
|
15
|
+
# EdgeSpeak Python SDK
|
|
16
|
+
|
|
17
|
+
Transcribe, align, segment text, identify speaker turns, and compare voice embeddings
|
|
18
|
+
through the local EdgeSpeak CLI. Audio is processed by the connected runtime;
|
|
19
|
+
the SDK does not bundle engines or models.
|
|
20
|
+
|
|
21
|
+
[简体中文](https://github.com/lattifai/EdgeSpeak/blob/main/sdk/python/README.zh-CN.md) · [Documentation](https://edgespeak.com/docs/python-sdk) · [Examples](https://github.com/lattifai/EdgeSpeak/tree/main/sdk/python/examples)
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
Requires Python 3.10+. One pure-Python wheel serves all supported Python versions
|
|
26
|
+
and platforms. Once published to PyPI, install with:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
python -m pip install edgespeak
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The first PyPI release is pending. Until then, run `python -m pip install ./sdk/python`
|
|
33
|
+
from the repository root. The SDK discovers an installed CLI and automatically
|
|
34
|
+
installs the latest official stable CLI if none meets its requirements.
|
|
35
|
+
Automatic installation supports macOS Apple Silicon, Linux x86_64, and Windows x64
|
|
36
|
+
and requires network access. Models load on demand; first use may download a model.
|
|
37
|
+
|
|
38
|
+
## Create and configure an API KEY
|
|
39
|
+
|
|
40
|
+
1. Sign in to [EdgeSpeak → API KEY](https://edgespeak.com/account/api-keys).
|
|
41
|
+
2. Create an API KEY, choose an expiry (including never expires) and usage limit,
|
|
42
|
+
and copy the full key shown at creation.
|
|
43
|
+
3. Set `EDGESPEAK_API_KEY` in the environment running Python:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
export EDGESPEAK_API_KEY="your API KEY"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
In Windows PowerShell, use `$env:EDGESPEAK_API_KEY="your API KEY"`.
|
|
50
|
+
`EdgeSpeak()` reads this variable automatically; you can also pass `EdgeSpeak(api_key=...)`.
|
|
51
|
+
An API KEY authorizes programmatic access and is different from a product activation
|
|
52
|
+
key. Keep it out of source control. An already activated local device can also
|
|
53
|
+
reuse its existing authorization.
|
|
54
|
+
|
|
55
|
+
API KEY access requires online authorization and shares the account subscription
|
|
56
|
+
allowance and billing period with desktop usage. Creating a key does not reset usage.
|
|
57
|
+
Never expires only removes the expiry date; entitlement, usage limits, and revocation
|
|
58
|
+
still apply.
|
|
59
|
+
|
|
60
|
+
## Quick start
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from edgespeak import EdgeSpeak
|
|
64
|
+
|
|
65
|
+
with EdgeSpeak() as client:
|
|
66
|
+
transcript = client.transcribe("meeting.wav", language="en", diarize=True)
|
|
67
|
+
print(transcript["text"])
|
|
68
|
+
aligned = client.align("speech.wav", text="The exact words spoken.")
|
|
69
|
+
speakers = client.diarize("meeting.wav", num_speakers=2)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Reuse a client and use `with` or `close()` to release its owned service.
|
|
73
|
+
Results are usually dictionaries with timestamps in seconds;
|
|
74
|
+
`response_format="text"` returns a string. Alignment needs the spoken words in
|
|
75
|
+
the original language. It also accepts `text_file="captions.srt"`, supporting
|
|
76
|
+
TXT, JSON, SRT, ASS, and SSA; existing subtitle timing is recomputed from the audio.
|
|
77
|
+
|
|
78
|
+
| Method | Purpose |
|
|
79
|
+
| --- | --- |
|
|
80
|
+
| `transcribe(audio, ...)` | Transcription, optional speaker labels and word timestamps |
|
|
81
|
+
| `align(audio, text=... / text_file=..., ...)` | Align a transcript or subtitles to audio |
|
|
82
|
+
| `segment(text, ...)` / `segment(segments=..., ...)` | Segment text or resegment timed captions |
|
|
83
|
+
| `diarize(audio, ...)` | Independent speaker diarization |
|
|
84
|
+
| `speaker_embedding(audio, ...)` | Single or batch voice embeddings |
|
|
85
|
+
| `speaker_similarity(a, b, ...)` | Compare two embeddings from the same model |
|
|
86
|
+
|
|
87
|
+
Typed options include `timestamp_granularities=["word", "segment"]` and
|
|
88
|
+
`search_effort="auto"`. Use `help(EdgeSpeak.transcribe)` or `help(EdgeSpeak.align)`
|
|
89
|
+
for parameter details. Alignment does not perform diarization; choose a speaker
|
|
90
|
+
count with the independent `diarize()` method.
|
|
91
|
+
|
|
92
|
+
## Progress and existing gateways
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
with EdgeSpeak() as client:
|
|
96
|
+
with client.align("speech.wav", text="The exact words spoken.", progress=True) as events:
|
|
97
|
+
for event in events:
|
|
98
|
+
print(event)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Progress events precede the final result. Close the stream when stopping early;
|
|
102
|
+
closing does not guarantee cancellation of inference already running.
|
|
103
|
+
`transcribe(stream=True)` currently requires an attached desktop gateway and
|
|
104
|
+
does not support diarization or timestamp granularities.
|
|
105
|
+
|
|
106
|
+
Attach with `EdgeSpeak(base_url="http://127.0.0.1:1118/v1", gateway_key=...)`.
|
|
107
|
+
`gateway_key` is a gateway token, not an account API KEY. Closing an attached client
|
|
108
|
+
does not stop the gateway. Remote URLs require HTTPS and audio is uploaded to that
|
|
109
|
+
server. Environment proxies are ignored. Create a separate client in each process;
|
|
110
|
+
do not reuse a client inherited across fork.
|
|
111
|
+
|
|
112
|
+
## Errors
|
|
113
|
+
|
|
114
|
+
`EdgeSpeakError` exposes `code`, `status_code`, `reason`, and `resets_at`.
|
|
115
|
+
Its `reason` distinguishes `api_key_expired`, `api_key_revoked`, and `usage_exhausted`.
|
|
116
|
+
Changing keys does not restore account allowance. Invalid arguments raise `ValueError`,
|
|
117
|
+
file errors raise `OSError`, and CLI startup failures raise `RuntimeStartError`.
|
|
118
|
+
|
|
119
|
+
`timeout` defaults to 600 seconds per HTTP I/O phase, not a total task deadline.
|
|
120
|
+
`startup_timeout` defaults to 30 seconds and excludes CLI installation time.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# EdgeSpeak Python SDK
|
|
2
|
+
|
|
3
|
+
Transcribe, align, segment text, identify speaker turns, and compare voice embeddings
|
|
4
|
+
through the local EdgeSpeak CLI. Audio is processed by the connected runtime;
|
|
5
|
+
the SDK does not bundle engines or models.
|
|
6
|
+
|
|
7
|
+
[简体中文](https://github.com/lattifai/EdgeSpeak/blob/main/sdk/python/README.zh-CN.md) · [Documentation](https://edgespeak.com/docs/python-sdk) · [Examples](https://github.com/lattifai/EdgeSpeak/tree/main/sdk/python/examples)
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
Requires Python 3.10+. One pure-Python wheel serves all supported Python versions
|
|
12
|
+
and platforms. Once published to PyPI, install with:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
python -m pip install edgespeak
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The first PyPI release is pending. Until then, run `python -m pip install ./sdk/python`
|
|
19
|
+
from the repository root. The SDK discovers an installed CLI and automatically
|
|
20
|
+
installs the latest official stable CLI if none meets its requirements.
|
|
21
|
+
Automatic installation supports macOS Apple Silicon, Linux x86_64, and Windows x64
|
|
22
|
+
and requires network access. Models load on demand; first use may download a model.
|
|
23
|
+
|
|
24
|
+
## Create and configure an API KEY
|
|
25
|
+
|
|
26
|
+
1. Sign in to [EdgeSpeak → API KEY](https://edgespeak.com/account/api-keys).
|
|
27
|
+
2. Create an API KEY, choose an expiry (including never expires) and usage limit,
|
|
28
|
+
and copy the full key shown at creation.
|
|
29
|
+
3. Set `EDGESPEAK_API_KEY` in the environment running Python:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
export EDGESPEAK_API_KEY="your API KEY"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
In Windows PowerShell, use `$env:EDGESPEAK_API_KEY="your API KEY"`.
|
|
36
|
+
`EdgeSpeak()` reads this variable automatically; you can also pass `EdgeSpeak(api_key=...)`.
|
|
37
|
+
An API KEY authorizes programmatic access and is different from a product activation
|
|
38
|
+
key. Keep it out of source control. An already activated local device can also
|
|
39
|
+
reuse its existing authorization.
|
|
40
|
+
|
|
41
|
+
API KEY access requires online authorization and shares the account subscription
|
|
42
|
+
allowance and billing period with desktop usage. Creating a key does not reset usage.
|
|
43
|
+
Never expires only removes the expiry date; entitlement, usage limits, and revocation
|
|
44
|
+
still apply.
|
|
45
|
+
|
|
46
|
+
## Quick start
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
from edgespeak import EdgeSpeak
|
|
50
|
+
|
|
51
|
+
with EdgeSpeak() as client:
|
|
52
|
+
transcript = client.transcribe("meeting.wav", language="en", diarize=True)
|
|
53
|
+
print(transcript["text"])
|
|
54
|
+
aligned = client.align("speech.wav", text="The exact words spoken.")
|
|
55
|
+
speakers = client.diarize("meeting.wav", num_speakers=2)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Reuse a client and use `with` or `close()` to release its owned service.
|
|
59
|
+
Results are usually dictionaries with timestamps in seconds;
|
|
60
|
+
`response_format="text"` returns a string. Alignment needs the spoken words in
|
|
61
|
+
the original language. It also accepts `text_file="captions.srt"`, supporting
|
|
62
|
+
TXT, JSON, SRT, ASS, and SSA; existing subtitle timing is recomputed from the audio.
|
|
63
|
+
|
|
64
|
+
| Method | Purpose |
|
|
65
|
+
| --- | --- |
|
|
66
|
+
| `transcribe(audio, ...)` | Transcription, optional speaker labels and word timestamps |
|
|
67
|
+
| `align(audio, text=... / text_file=..., ...)` | Align a transcript or subtitles to audio |
|
|
68
|
+
| `segment(text, ...)` / `segment(segments=..., ...)` | Segment text or resegment timed captions |
|
|
69
|
+
| `diarize(audio, ...)` | Independent speaker diarization |
|
|
70
|
+
| `speaker_embedding(audio, ...)` | Single or batch voice embeddings |
|
|
71
|
+
| `speaker_similarity(a, b, ...)` | Compare two embeddings from the same model |
|
|
72
|
+
|
|
73
|
+
Typed options include `timestamp_granularities=["word", "segment"]` and
|
|
74
|
+
`search_effort="auto"`. Use `help(EdgeSpeak.transcribe)` or `help(EdgeSpeak.align)`
|
|
75
|
+
for parameter details. Alignment does not perform diarization; choose a speaker
|
|
76
|
+
count with the independent `diarize()` method.
|
|
77
|
+
|
|
78
|
+
## Progress and existing gateways
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
with EdgeSpeak() as client:
|
|
82
|
+
with client.align("speech.wav", text="The exact words spoken.", progress=True) as events:
|
|
83
|
+
for event in events:
|
|
84
|
+
print(event)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Progress events precede the final result. Close the stream when stopping early;
|
|
88
|
+
closing does not guarantee cancellation of inference already running.
|
|
89
|
+
`transcribe(stream=True)` currently requires an attached desktop gateway and
|
|
90
|
+
does not support diarization or timestamp granularities.
|
|
91
|
+
|
|
92
|
+
Attach with `EdgeSpeak(base_url="http://127.0.0.1:1118/v1", gateway_key=...)`.
|
|
93
|
+
`gateway_key` is a gateway token, not an account API KEY. Closing an attached client
|
|
94
|
+
does not stop the gateway. Remote URLs require HTTPS and audio is uploaded to that
|
|
95
|
+
server. Environment proxies are ignored. Create a separate client in each process;
|
|
96
|
+
do not reuse a client inherited across fork.
|
|
97
|
+
|
|
98
|
+
## Errors
|
|
99
|
+
|
|
100
|
+
`EdgeSpeakError` exposes `code`, `status_code`, `reason`, and `resets_at`.
|
|
101
|
+
Its `reason` distinguishes `api_key_expired`, `api_key_revoked`, and `usage_exhausted`.
|
|
102
|
+
Changing keys does not restore account allowance. Invalid arguments raise `ValueError`,
|
|
103
|
+
file errors raise `OSError`, and CLI startup failures raise `RuntimeStartError`.
|
|
104
|
+
|
|
105
|
+
`timeout` defaults to 600 seconds per HTTP I/O phase, not a total task deadline.
|
|
106
|
+
`startup_timeout` defaults to 30 seconds and excludes CLI installation time.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# EdgeSpeak Python SDK
|
|
2
|
+
|
|
3
|
+
通过本机 EdgeSpeak CLI 完成转录、强制对齐、语义分句、说话人分离和声纹处理。
|
|
4
|
+
音频由所连接的运行时处理,SDK 不内置引擎或模型。
|
|
5
|
+
|
|
6
|
+
[English](https://github.com/lattifai/EdgeSpeak/blob/main/sdk/python/README.md) · [完整文档](https://edgespeak.com/zh/docs/python-sdk) · [示例](https://github.com/lattifai/EdgeSpeak/tree/main/sdk/python/examples)
|
|
7
|
+
|
|
8
|
+
## 安装
|
|
9
|
+
|
|
10
|
+
需要 Python 3.10+。所有支持的 Python 版本和平台共用一个纯 Python wheel。
|
|
11
|
+
正式发布到 PyPI 后,使用:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
python -m pip install edgespeak
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
首次 PyPI 发布尚未完成;当前可在仓库根目录运行 `python -m pip install ./sdk/python`。
|
|
18
|
+
SDK 自动查找本机 CLI;未安装或版本不满足要求时,自动安装官方最新稳定版。
|
|
19
|
+
自动安装支持 macOS Apple Silicon、Linux x86_64 和 Windows x64,需要联网。
|
|
20
|
+
模型按需加载,首次调用可能下载模型。
|
|
21
|
+
|
|
22
|
+
## 创建和配置 API KEY
|
|
23
|
+
|
|
24
|
+
1. 登录 [EdgeSpeak → API KEY](https://edgespeak.com/zh/account/api-keys)。
|
|
25
|
+
2. 创建 API KEY,设置有效期(可选永久有效)及用量限制,并复制创建时显示的完整密钥。
|
|
26
|
+
3. 在运行 Python 的环境中设置 `EDGESPEAK_API_KEY`:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
export EDGESPEAK_API_KEY="你的 API KEY"
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Windows PowerShell 使用 `$env:EDGESPEAK_API_KEY="你的 API KEY"`。
|
|
33
|
+
`EdgeSpeak()` 会自动读取该变量,也可显式传入 `EdgeSpeak(api_key=...)`。
|
|
34
|
+
API KEY 用于程序访问,与产品激活密钥不同;不要将它写入代码仓库。
|
|
35
|
+
已激活的本机设备也可沿用现有授权。
|
|
36
|
+
|
|
37
|
+
API KEY 需要在线授权,与桌面端共享账号订阅额度及计费周期;新建密钥不会重置额度。
|
|
38
|
+
永久有效仅表示没有到期日,账号授权、用量限制和撤销仍然生效。
|
|
39
|
+
|
|
40
|
+
## 快速开始
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from edgespeak import EdgeSpeak
|
|
44
|
+
|
|
45
|
+
with EdgeSpeak() as client:
|
|
46
|
+
transcript = client.transcribe("meeting.wav", language="zh", diarize=True)
|
|
47
|
+
print(transcript["text"])
|
|
48
|
+
aligned = client.align("speech.wav", text="音频中实际说出的原文。")
|
|
49
|
+
speakers = client.diarize("meeting.wav", num_speakers=2)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
建议复用客户端,使用 `with` 或 `close()` 释放 SDK 启动的服务。
|
|
53
|
+
结果通常为字典,时间戳单位为秒;`response_format="text"` 返回字符串。
|
|
54
|
+
对齐需要与音频对应的原语言文本,也支持 `text_file="captions.srt"`,可读取 TXT、JSON、SRT、ASS、SSA。
|
|
55
|
+
字幕原有时间会根据音频重新对齐。
|
|
56
|
+
|
|
57
|
+
| 方法 | 用途 |
|
|
58
|
+
| --- | --- |
|
|
59
|
+
| `transcribe(audio, ...)` | 音频转录,可附带说话人标注、词级时间戳 |
|
|
60
|
+
| `align(audio, text=... / text_file=..., ...)` | 将原文或字幕与音频对齐 |
|
|
61
|
+
| `segment(text, ...)` / `segment(segments=..., ...)` | 纯文本分句或带时间片段重新分句 |
|
|
62
|
+
| `diarize(audio, ...)` | 独立说话人分离 |
|
|
63
|
+
| `speaker_embedding(audio, ...)` | 提取单个或批量声纹 |
|
|
64
|
+
| `speaker_similarity(a, b, ...)` | 比较同一模型产生的两个声纹向量 |
|
|
65
|
+
|
|
66
|
+
参数有类型提示,例如 `timestamp_granularities=["word", "segment"]`、
|
|
67
|
+
`search_effort="auto"`。可用 `help(EdgeSpeak.transcribe)`、`help(EdgeSpeak.align)` 查看参数说明。
|
|
68
|
+
对齐不执行说话人分离;指定人数使用独立的 `diarize()`。
|
|
69
|
+
|
|
70
|
+
## 进度与现有网关
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
with EdgeSpeak() as client:
|
|
74
|
+
with client.align("speech.wav", text="音频原文。", progress=True) as events:
|
|
75
|
+
for event in events:
|
|
76
|
+
print(event)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
进度事件后还会返回最终结果;提前退出时应关闭流。关闭流不保证取消已开始的推理。
|
|
80
|
+
`transcribe(stream=True)` 目前需要连接桌面端网关,不支持说话人标注或时间粒度参数。
|
|
81
|
+
|
|
82
|
+
已有网关使用 `EdgeSpeak(base_url="http://127.0.0.1:1118/v1", gateway_key=...)`。
|
|
83
|
+
`gateway_key` 是网关令牌,不是账号 API KEY;关闭客户端不会关闭已有网关。
|
|
84
|
+
远程地址要求 HTTPS,音频会上传至该服务器;SDK 不读取环境代理配置。
|
|
85
|
+
多进程应各自创建客户端,不复用 fork 继承的客户端。
|
|
86
|
+
|
|
87
|
+
## 错误处理
|
|
88
|
+
|
|
89
|
+
`EdgeSpeakError` 提供 `code`、`status_code`、`reason` 和 `resets_at`。
|
|
90
|
+
通过 `reason` 区分 `api_key_expired`(已过期)、`api_key_revoked`(已撤销)、
|
|
91
|
+
`usage_exhausted`(本期额度耗尽);更换密钥不会恢复账号额度。
|
|
92
|
+
参数错误为 `ValueError`,文件错误为 `OSError`,CLI 启动错误为 `RuntimeStartError`。
|
|
93
|
+
|
|
94
|
+
`timeout` 默认为 600 秒,针对 HTTP I/O 阶段,不是任务总时限;
|
|
95
|
+
`startup_timeout` 默认为 30 秒,不包含 CLI 安装时间。
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Shared connection options; credentials stay in environment variables."""
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
from edgespeak import EdgeSpeak
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def connect(parser):
|
|
8
|
+
parser.add_argument('--base-url', help='Attach to an existing gateway; never stop it')
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def client(args):
|
|
12
|
+
if args.base_url:
|
|
13
|
+
return EdgeSpeak(base_url=args.base_url, gateway_key=os.environ.get('EDGESPEAK_GATEWAY_KEY'))
|
|
14
|
+
return EdgeSpeak()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def output(result):
|
|
18
|
+
print(result if isinstance(result, str) else json.dumps(result, ensure_ascii=False, indent=2))
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""Align text or TXT/JSON/SRT/ASS/SSA references; original cue timing is ignored."""
|
|
2
|
+
import argparse
|
|
3
|
+
import json
|
|
4
|
+
from _common import client, connect, output
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def main():
|
|
8
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
9
|
+
parser.add_argument('audio')
|
|
10
|
+
source = parser.add_mutually_exclusive_group(required=True)
|
|
11
|
+
source.add_argument('--text')
|
|
12
|
+
source.add_argument('--text-file')
|
|
13
|
+
parser.add_argument('--text-format', choices=['txt', 'json', 'srt', 'ass', 'ssa'])
|
|
14
|
+
parser.add_argument('--language')
|
|
15
|
+
parser.add_argument('--model')
|
|
16
|
+
parser.add_argument('--start', type=float)
|
|
17
|
+
parser.add_argument('--end', type=float)
|
|
18
|
+
parser.add_argument('--search-effort', choices=['standard', 'extended', 'auto'], default='standard')
|
|
19
|
+
parser.add_argument('--protected-term', action='append')
|
|
20
|
+
parser.add_argument('--text-normalization', type=json.loads, help='API normalization JSON object')
|
|
21
|
+
parser.add_argument('--audio-track', type=int)
|
|
22
|
+
parser.add_argument('--audio-channel')
|
|
23
|
+
parser.add_argument('--semantic', action=argparse.BooleanOptionalAction, default=None)
|
|
24
|
+
parser.add_argument('--threshold', type=float)
|
|
25
|
+
parser.add_argument('--min-chars', type=int)
|
|
26
|
+
parser.add_argument('--max-chars', type=int)
|
|
27
|
+
parser.add_argument('--start-margin', type=float)
|
|
28
|
+
parser.add_argument('--end-margin', type=float)
|
|
29
|
+
parser.add_argument('--progress', action='store_true')
|
|
30
|
+
connect(parser)
|
|
31
|
+
args = parser.parse_args()
|
|
32
|
+
with client(args) as sdk:
|
|
33
|
+
result = sdk.align(args.audio, text=args.text, text_file=args.text_file, text_format=args.text_format,
|
|
34
|
+
language=args.language, model=args.model, start=args.start, end=args.end,
|
|
35
|
+
search_effort=args.search_effort, protected_terms=args.protected_term,
|
|
36
|
+
text_normalization=args.text_normalization, audio_track=args.audio_track,
|
|
37
|
+
audio_channel=args.audio_channel, semantic_sentence_enabled=args.semantic,
|
|
38
|
+
threshold=args.threshold, min_chars=args.min_chars, max_chars=args.max_chars, start_margin=args.start_margin, end_margin=args.end_margin, progress=args.progress)
|
|
39
|
+
if args.progress:
|
|
40
|
+
with result as events:
|
|
41
|
+
for event in events:
|
|
42
|
+
output(event)
|
|
43
|
+
else:
|
|
44
|
+
output(result)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
if __name__ == '__main__':
|
|
48
|
+
main()
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""Semantic sentences/paragraphs, or resegment a timed transcript with speakers."""
|
|
2
|
+
import argparse
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from _common import client, connect, output
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def main():
|
|
9
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
10
|
+
source = parser.add_mutually_exclusive_group(required=True)
|
|
11
|
+
source.add_argument('--text')
|
|
12
|
+
source.add_argument('--text-file', help='UTF-8 plain text')
|
|
13
|
+
source.add_argument('--segments-file', help='Exported transcript JSON with segments')
|
|
14
|
+
parser.add_argument('--threshold', type=float)
|
|
15
|
+
parser.add_argument('--paragraph-threshold', type=float)
|
|
16
|
+
parser.add_argument('--min-chars', type=int)
|
|
17
|
+
parser.add_argument('--max-chars', type=int)
|
|
18
|
+
parser.add_argument('--start-margin', type=float)
|
|
19
|
+
parser.add_argument('--end-margin', type=float)
|
|
20
|
+
connect(parser)
|
|
21
|
+
args = parser.parse_args()
|
|
22
|
+
text = Path(args.text_file).read_text(encoding='utf-8-sig') if args.text_file else args.text
|
|
23
|
+
segments = json.loads(Path(args.segments_file).read_text(encoding='utf-8-sig'))['segments'] if args.segments_file else None
|
|
24
|
+
with client(args) as sdk:
|
|
25
|
+
output(sdk.segment(text, segments=segments, threshold=args.threshold,
|
|
26
|
+
paragraph_threshold=args.paragraph_threshold, min_chars=args.min_chars, max_chars=args.max_chars,
|
|
27
|
+
start_margin=args.start_margin, end_margin=args.end_margin))
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
if __name__ == '__main__':
|
|
31
|
+
main()
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Speaker timeline, batch embeddings and same-model voice similarity."""
|
|
2
|
+
import argparse
|
|
3
|
+
from _common import client, connect, output
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def main():
|
|
7
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
8
|
+
parser.add_argument('audio', help='Audio/video for the speaker timeline')
|
|
9
|
+
parser.add_argument('reference_a', help='First short voice sample')
|
|
10
|
+
parser.add_argument('reference_b', help='Second short voice sample')
|
|
11
|
+
parser.add_argument('--num-speakers', type=int)
|
|
12
|
+
parser.add_argument('--model', default='EdgeSpeak/Lattice-1')
|
|
13
|
+
connect(parser)
|
|
14
|
+
args = parser.parse_args()
|
|
15
|
+
with client(args) as sdk:
|
|
16
|
+
output(sdk.diarize(args.audio, num_speakers=args.num_speakers))
|
|
17
|
+
voices = sdk.speaker_embedding([args.reference_a, args.reference_b], model=args.model)
|
|
18
|
+
output(voices)
|
|
19
|
+
output(sdk.speaker_similarity(voices['data'][0]['embedding'], voices['data'][1]['embedding'], model=args.model))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
if __name__ == '__main__':
|
|
23
|
+
main()
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""Transcribe media with optional speaker labels, word timestamps and sentences."""
|
|
2
|
+
import argparse
|
|
3
|
+
from _common import client, connect, output
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def main():
|
|
7
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
8
|
+
parser.add_argument('audio')
|
|
9
|
+
parser.add_argument('--model')
|
|
10
|
+
parser.add_argument('--language')
|
|
11
|
+
parser.add_argument('--prompt')
|
|
12
|
+
parser.add_argument('--timestamp-granularity', action='append', choices=['word', 'segment'])
|
|
13
|
+
parser.add_argument('--diarize', action='store_true')
|
|
14
|
+
parser.add_argument('--response-format', choices=['json', 'verbose_json', 'diarized_json', 'text'])
|
|
15
|
+
parser.add_argument('--word-timestamps', action=argparse.BooleanOptionalAction, default=None)
|
|
16
|
+
parser.add_argument('--semantic', action=argparse.BooleanOptionalAction, default=None)
|
|
17
|
+
parser.add_argument('--min-chars', type=int)
|
|
18
|
+
parser.add_argument('--max-chars', type=int)
|
|
19
|
+
parser.add_argument('--start-margin', type=float)
|
|
20
|
+
parser.add_argument('--end-margin', type=float)
|
|
21
|
+
parser.add_argument('--candidates', type=int)
|
|
22
|
+
parser.add_argument('--stream', action='store_true', help='SSE; desktop gateway only')
|
|
23
|
+
connect(parser)
|
|
24
|
+
args = parser.parse_args()
|
|
25
|
+
with client(args) as sdk:
|
|
26
|
+
result = sdk.transcribe(args.audio, model=args.model, language=args.language,
|
|
27
|
+
diarize=args.diarize, response_format=args.response_format, stream=args.stream, prompt=args.prompt,
|
|
28
|
+
timestamp_granularities=args.timestamp_granularity,
|
|
29
|
+
word_timestamp_enabled=args.word_timestamps, candidates=args.candidates,
|
|
30
|
+
semantic_sentence_enabled=args.semantic, min_chars=args.min_chars, max_chars=args.max_chars,
|
|
31
|
+
start_margin=args.start_margin, end_margin=args.end_margin)
|
|
32
|
+
if args.stream:
|
|
33
|
+
with result as events:
|
|
34
|
+
for event in events:
|
|
35
|
+
output(event)
|
|
36
|
+
else:
|
|
37
|
+
output(result)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
if __name__ == '__main__':
|
|
41
|
+
main()
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "edgespeak"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Python client for the local EdgeSpeak CLI runtime"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
dependencies = ["httpx>=0.27,<1"]
|
|
12
|
+
|
|
13
|
+
[project.optional-dependencies]
|
|
14
|
+
dev = ["mypy==1.20.2", "typing_extensions>=4.6"]
|
|
15
|
+
|
|
16
|
+
[tool.setuptools.dynamic]
|
|
17
|
+
version = {attr = "edgespeak._version.__version__"}
|
|
18
|
+
|
|
19
|
+
[tool.setuptools.packages.find]
|
|
20
|
+
where = ["src"]
|
|
21
|
+
|
|
22
|
+
[tool.setuptools.package-data]
|
|
23
|
+
edgespeak = ["py.typed"]
|
|
24
|
+
|
|
25
|
+
[project.urls]
|
|
26
|
+
Documentation = "https://edgespeak.com/docs/python-sdk"
|
|
27
|
+
Source = "https://github.com/lattifai/EdgeSpeak/tree/main/sdk/python"
|
|
28
|
+
Issues = "https://github.com/lattifai/EdgeSpeak/issues"
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""EdgeSpeak's Python SDK for the local CLI runtime."""
|
|
2
|
+
from ._client import EdgeSpeak, EdgeSpeakError
|
|
3
|
+
from ._process import RuntimeStartError
|
|
4
|
+
from ._bootstrap import MIN_CLI_VERSION
|
|
5
|
+
from ._streaming import EventStream
|
|
6
|
+
from ._types import AudioChannel, ReferenceFormat, SearchEffort, TimestampGranularity, TranscriptionFormat
|
|
7
|
+
|
|
8
|
+
from ._version import __version__ as __version__
|
|
9
|
+
__all__ = ["EdgeSpeak", "EdgeSpeakError", "RuntimeStartError", "MIN_CLI_VERSION", "EventStream",
|
|
10
|
+
"AudioChannel", "ReferenceFormat", "SearchEffort", "TimestampGranularity", "TranscriptionFormat"]
|