talking-snake 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.
- talking_snake-0.1.0/.github/workflows/ci.yml +118 -0
- talking_snake-0.1.0/.github/workflows/publish.yml +74 -0
- talking_snake-0.1.0/.gitignore +61 -0
- talking_snake-0.1.0/.htmlhintrc +25 -0
- talking_snake-0.1.0/.pre-commit-config.yaml +51 -0
- talking_snake-0.1.0/.stylelintrc.json +10 -0
- talking_snake-0.1.0/Dockerfile +31 -0
- talking_snake-0.1.0/LICENSE +21 -0
- talking_snake-0.1.0/PKG-INFO +71 -0
- talking_snake-0.1.0/README.md +34 -0
- talking_snake-0.1.0/README_HF.md +17 -0
- talking_snake-0.1.0/eslint.config.js +34 -0
- talking_snake-0.1.0/favicon.png +0 -0
- talking_snake-0.1.0/landing.png +0 -0
- talking_snake-0.1.0/package-lock.json +2509 -0
- talking_snake-0.1.0/package.json +20 -0
- talking_snake-0.1.0/pyproject.toml +111 -0
- talking_snake-0.1.0/rendering.png +0 -0
- talking_snake-0.1.0/scripts/generate_sample.py +33 -0
- talking_snake-0.1.0/src/talking_snake/__init__.py +3 -0
- talking_snake-0.1.0/src/talking_snake/__main__.py +119 -0
- talking_snake-0.1.0/src/talking_snake/app.py +935 -0
- talking_snake-0.1.0/src/talking_snake/extract.py +489 -0
- talking_snake-0.1.0/src/talking_snake/static/app.js +773 -0
- talking_snake-0.1.0/src/talking_snake/static/apple-touch-icon.png +0 -0
- talking_snake-0.1.0/src/talking_snake/static/favicon.png +0 -0
- talking_snake-0.1.0/src/talking_snake/static/icon-192.png +0 -0
- talking_snake-0.1.0/src/talking_snake/static/icon-512.png +0 -0
- talking_snake-0.1.0/src/talking_snake/static/index.html +142 -0
- talking_snake-0.1.0/src/talking_snake/static/manifest.json +36 -0
- talking_snake-0.1.0/src/talking_snake/static/sample.wav +0 -0
- talking_snake-0.1.0/src/talking_snake/static/styles.css +848 -0
- talking_snake-0.1.0/src/talking_snake/static/talking_snake.png +0 -0
- talking_snake-0.1.0/src/talking_snake/tts.py +486 -0
- talking_snake-0.1.0/talking_snake.png +0 -0
- talking_snake-0.1.0/tests/conftest.py +205 -0
- talking_snake-0.1.0/tests/test_app.py +200 -0
- talking_snake-0.1.0/tests/test_app_streaming.py +266 -0
- talking_snake-0.1.0/tests/test_extract.py +227 -0
- talking_snake-0.1.0/tests/test_tts.py +250 -0
- talking_snake-0.1.0/uv.lock +3381 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
lint:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
|
|
15
|
+
- name: Install uv
|
|
16
|
+
uses: astral-sh/setup-uv@v5
|
|
17
|
+
with:
|
|
18
|
+
version: "latest"
|
|
19
|
+
|
|
20
|
+
- name: Set up Python
|
|
21
|
+
run: uv python install 3.12
|
|
22
|
+
|
|
23
|
+
- name: Install dependencies
|
|
24
|
+
run: uv sync --extra dev
|
|
25
|
+
|
|
26
|
+
- name: Run ruff check
|
|
27
|
+
run: uv run ruff check src tests
|
|
28
|
+
|
|
29
|
+
- name: Run ruff format check
|
|
30
|
+
run: uv run ruff format --check src tests
|
|
31
|
+
|
|
32
|
+
lint-frontend:
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v4
|
|
36
|
+
|
|
37
|
+
- name: Set up Node.js
|
|
38
|
+
uses: actions/setup-node@v4
|
|
39
|
+
with:
|
|
40
|
+
node-version: "20"
|
|
41
|
+
cache: "npm"
|
|
42
|
+
|
|
43
|
+
- name: Install dependencies
|
|
44
|
+
run: npm ci
|
|
45
|
+
|
|
46
|
+
- name: Lint HTML
|
|
47
|
+
run: npm run lint:html
|
|
48
|
+
|
|
49
|
+
- name: Lint CSS
|
|
50
|
+
run: npm run lint:css
|
|
51
|
+
|
|
52
|
+
- name: Lint JavaScript
|
|
53
|
+
run: npm run lint:js
|
|
54
|
+
|
|
55
|
+
test:
|
|
56
|
+
runs-on: ubuntu-latest
|
|
57
|
+
strategy:
|
|
58
|
+
matrix:
|
|
59
|
+
python-version: ["3.11", "3.12"]
|
|
60
|
+
steps:
|
|
61
|
+
- uses: actions/checkout@v4
|
|
62
|
+
|
|
63
|
+
- name: Install uv
|
|
64
|
+
uses: astral-sh/setup-uv@v5
|
|
65
|
+
with:
|
|
66
|
+
version: "latest"
|
|
67
|
+
|
|
68
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
69
|
+
run: uv python install ${{ matrix.python-version }}
|
|
70
|
+
|
|
71
|
+
- name: Install dependencies
|
|
72
|
+
run: uv sync --extra dev
|
|
73
|
+
|
|
74
|
+
- name: Run tests with coverage
|
|
75
|
+
run: |
|
|
76
|
+
uv run pytest \
|
|
77
|
+
--cov=talking_snake \
|
|
78
|
+
--cov-report=xml \
|
|
79
|
+
--cov-report=term-missing \
|
|
80
|
+
--cov-fail-under=50
|
|
81
|
+
|
|
82
|
+
- name: Upload coverage to Codecov
|
|
83
|
+
if: matrix.python-version == '3.12'
|
|
84
|
+
uses: codecov/codecov-action@v5
|
|
85
|
+
with:
|
|
86
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
87
|
+
files: ./coverage.xml
|
|
88
|
+
fail_ci_if_error: false
|
|
89
|
+
|
|
90
|
+
typecheck:
|
|
91
|
+
runs-on: ubuntu-latest
|
|
92
|
+
steps:
|
|
93
|
+
- uses: actions/checkout@v4
|
|
94
|
+
|
|
95
|
+
- name: Install uv
|
|
96
|
+
uses: astral-sh/setup-uv@v5
|
|
97
|
+
with:
|
|
98
|
+
version: "latest"
|
|
99
|
+
|
|
100
|
+
- name: Set up Python
|
|
101
|
+
run: uv python install 3.12
|
|
102
|
+
|
|
103
|
+
- name: Install dependencies
|
|
104
|
+
run: uv sync --extra dev
|
|
105
|
+
|
|
106
|
+
- name: Run mypy
|
|
107
|
+
run: uv run mypy src --ignore-missing-imports
|
|
108
|
+
|
|
109
|
+
links:
|
|
110
|
+
runs-on: ubuntu-latest
|
|
111
|
+
steps:
|
|
112
|
+
- uses: actions/checkout@v4
|
|
113
|
+
|
|
114
|
+
- name: Check links in markdown files
|
|
115
|
+
uses: lycheeverse/lychee-action@v2
|
|
116
|
+
with:
|
|
117
|
+
args: --verbose --no-progress '**/*.md'
|
|
118
|
+
fail: true
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
inputs:
|
|
8
|
+
publish_target:
|
|
9
|
+
description: 'Publish target'
|
|
10
|
+
required: true
|
|
11
|
+
default: 'testpypi'
|
|
12
|
+
type: choice
|
|
13
|
+
options:
|
|
14
|
+
- testpypi
|
|
15
|
+
- pypi
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
build:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
|
|
23
|
+
- name: Install uv
|
|
24
|
+
uses: astral-sh/setup-uv@v5
|
|
25
|
+
with:
|
|
26
|
+
version: "latest"
|
|
27
|
+
|
|
28
|
+
- name: Set up Python
|
|
29
|
+
run: uv python install 3.12
|
|
30
|
+
|
|
31
|
+
- name: Build package
|
|
32
|
+
run: uv build
|
|
33
|
+
|
|
34
|
+
- name: Upload artifacts
|
|
35
|
+
uses: actions/upload-artifact@v4
|
|
36
|
+
with:
|
|
37
|
+
name: dist
|
|
38
|
+
path: dist/
|
|
39
|
+
|
|
40
|
+
publish-testpypi:
|
|
41
|
+
needs: build
|
|
42
|
+
if: github.event_name == 'workflow_dispatch' && github.event.inputs.publish_target == 'testpypi'
|
|
43
|
+
runs-on: ubuntu-latest
|
|
44
|
+
environment: testpypi
|
|
45
|
+
permissions:
|
|
46
|
+
id-token: write
|
|
47
|
+
steps:
|
|
48
|
+
- name: Download artifacts
|
|
49
|
+
uses: actions/download-artifact@v4
|
|
50
|
+
with:
|
|
51
|
+
name: dist
|
|
52
|
+
path: dist/
|
|
53
|
+
|
|
54
|
+
- name: Publish to TestPyPI
|
|
55
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
56
|
+
with:
|
|
57
|
+
repository-url: https://test.pypi.org/legacy/
|
|
58
|
+
|
|
59
|
+
publish-pypi:
|
|
60
|
+
needs: build
|
|
61
|
+
if: github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.publish_target == 'pypi')
|
|
62
|
+
runs-on: ubuntu-latest
|
|
63
|
+
environment: pypi
|
|
64
|
+
permissions:
|
|
65
|
+
id-token: write
|
|
66
|
+
steps:
|
|
67
|
+
- name: Download artifacts
|
|
68
|
+
uses: actions/download-artifact@v4
|
|
69
|
+
with:
|
|
70
|
+
name: dist
|
|
71
|
+
path: dist/
|
|
72
|
+
|
|
73
|
+
- name: Publish to PyPI
|
|
74
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
develop-eggs/
|
|
9
|
+
dist/
|
|
10
|
+
downloads/
|
|
11
|
+
eggs/
|
|
12
|
+
.eggs/
|
|
13
|
+
lib/
|
|
14
|
+
lib64/
|
|
15
|
+
parts/
|
|
16
|
+
sdist/
|
|
17
|
+
var/
|
|
18
|
+
wheels/
|
|
19
|
+
*.egg-info/
|
|
20
|
+
.installed.cfg
|
|
21
|
+
*.egg
|
|
22
|
+
|
|
23
|
+
# Virtual environments
|
|
24
|
+
.venv/
|
|
25
|
+
venv/
|
|
26
|
+
ENV/
|
|
27
|
+
|
|
28
|
+
# IDE
|
|
29
|
+
.idea/
|
|
30
|
+
.vscode/
|
|
31
|
+
*.swp
|
|
32
|
+
*.swo
|
|
33
|
+
*~
|
|
34
|
+
|
|
35
|
+
# Testing
|
|
36
|
+
.pytest_cache/
|
|
37
|
+
.coverage
|
|
38
|
+
htmlcov/
|
|
39
|
+
.tox/
|
|
40
|
+
.nox/
|
|
41
|
+
coverage.xml
|
|
42
|
+
*.cover
|
|
43
|
+
|
|
44
|
+
# mypy
|
|
45
|
+
.mypy_cache/
|
|
46
|
+
.dmypy.json
|
|
47
|
+
dmypy.json
|
|
48
|
+
|
|
49
|
+
# ruff
|
|
50
|
+
.ruff_cache/
|
|
51
|
+
|
|
52
|
+
# Node.js (frontend linting)
|
|
53
|
+
node_modules/
|
|
54
|
+
|
|
55
|
+
# OS
|
|
56
|
+
.DS_Store
|
|
57
|
+
Thumbs.db
|
|
58
|
+
|
|
59
|
+
# Project specific
|
|
60
|
+
*.wav
|
|
61
|
+
!src/talking_snake/static/sample.wav
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"tagname-lowercase": true,
|
|
3
|
+
"attr-lowercase": true,
|
|
4
|
+
"attr-value-double-quotes": true,
|
|
5
|
+
"attr-value-not-empty": false,
|
|
6
|
+
"attr-no-duplication": true,
|
|
7
|
+
"doctype-first": true,
|
|
8
|
+
"tag-pair": true,
|
|
9
|
+
"empty-tag-not-self-closed": true,
|
|
10
|
+
"spec-char-escape": true,
|
|
11
|
+
"id-unique": true,
|
|
12
|
+
"src-not-empty": true,
|
|
13
|
+
"title-require": true,
|
|
14
|
+
"alt-require": true,
|
|
15
|
+
"doctype-html5": true,
|
|
16
|
+
"id-class-value": false,
|
|
17
|
+
"style-disabled": true,
|
|
18
|
+
"inline-style-disabled": true,
|
|
19
|
+
"inline-script-disabled": true,
|
|
20
|
+
"space-tab-mixed-disabled": "space",
|
|
21
|
+
"id-class-ad-disabled": true,
|
|
22
|
+
"href-abs-or-rel": false,
|
|
23
|
+
"attr-unsafe-chars": true,
|
|
24
|
+
"head-script-disabled": false
|
|
25
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
3
|
+
rev: v5.0.0
|
|
4
|
+
hooks:
|
|
5
|
+
- id: trailing-whitespace
|
|
6
|
+
- id: end-of-file-fixer
|
|
7
|
+
- id: check-yaml
|
|
8
|
+
- id: check-toml
|
|
9
|
+
- id: check-added-large-files
|
|
10
|
+
args: ['--maxkb=1000']
|
|
11
|
+
- id: check-merge-conflict
|
|
12
|
+
|
|
13
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
14
|
+
rev: v0.8.6
|
|
15
|
+
hooks:
|
|
16
|
+
- id: ruff
|
|
17
|
+
args: [--fix, --exit-non-zero-on-fix]
|
|
18
|
+
- id: ruff-format
|
|
19
|
+
|
|
20
|
+
- repo: https://github.com/pre-commit/mirrors-mypy
|
|
21
|
+
rev: v1.14.1
|
|
22
|
+
hooks:
|
|
23
|
+
- id: mypy
|
|
24
|
+
additional_dependencies:
|
|
25
|
+
- types-requests
|
|
26
|
+
- pydantic
|
|
27
|
+
args: [--ignore-missing-imports]
|
|
28
|
+
files: ^src/
|
|
29
|
+
|
|
30
|
+
- repo: local
|
|
31
|
+
hooks:
|
|
32
|
+
- id: htmlhint
|
|
33
|
+
name: htmlhint
|
|
34
|
+
entry: npx htmlhint
|
|
35
|
+
language: system
|
|
36
|
+
files: \.html$
|
|
37
|
+
types: [file]
|
|
38
|
+
|
|
39
|
+
- id: stylelint
|
|
40
|
+
name: stylelint
|
|
41
|
+
entry: npx stylelint
|
|
42
|
+
language: system
|
|
43
|
+
files: \.css$
|
|
44
|
+
types: [file]
|
|
45
|
+
|
|
46
|
+
- id: eslint
|
|
47
|
+
name: eslint
|
|
48
|
+
entry: npx eslint
|
|
49
|
+
language: system
|
|
50
|
+
files: \.js$
|
|
51
|
+
types: [file]
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
FROM python:3.12-slim
|
|
2
|
+
|
|
3
|
+
# Install system dependencies
|
|
4
|
+
RUN apt-get update && apt-get install -y \
|
|
5
|
+
sox \
|
|
6
|
+
libsox-dev \
|
|
7
|
+
git \
|
|
8
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
9
|
+
|
|
10
|
+
# Install uv
|
|
11
|
+
RUN pip install uv
|
|
12
|
+
|
|
13
|
+
# Create non-root user for HF Spaces
|
|
14
|
+
RUN useradd -m -u 1000 user
|
|
15
|
+
USER user
|
|
16
|
+
ENV HOME=/home/user \
|
|
17
|
+
PATH=/home/user/.local/bin:$PATH
|
|
18
|
+
|
|
19
|
+
WORKDIR $HOME/app
|
|
20
|
+
|
|
21
|
+
# Copy project files
|
|
22
|
+
COPY --chown=user . .
|
|
23
|
+
|
|
24
|
+
# Install dependencies
|
|
25
|
+
RUN uv sync --no-dev
|
|
26
|
+
|
|
27
|
+
# Expose port 7860 (HF Spaces default)
|
|
28
|
+
EXPOSE 7860
|
|
29
|
+
|
|
30
|
+
# Run the app
|
|
31
|
+
CMD ["uv", "run", "talking-snake", "--host", "0.0.0.0", "--port", "7860"]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Luca Cappelletti
|
|
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.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: talking-snake
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Just a talking snake that reads PDFs and web pages aloud.
|
|
5
|
+
Author: Luca
|
|
6
|
+
License: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Keywords: audiobook,listening,pdf,speech,text-to-speech,tts
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
|
|
16
|
+
Requires-Python: >=3.11
|
|
17
|
+
Requires-Dist: fastapi>=0.115.0
|
|
18
|
+
Requires-Dist: httpx>=0.27.0
|
|
19
|
+
Requires-Dist: jinja2>=3.1.4
|
|
20
|
+
Requires-Dist: pdfminer-six>=20260107
|
|
21
|
+
Requires-Dist: python-multipart>=0.0.12
|
|
22
|
+
Requires-Dist: qwen-tts>=0.1.1
|
|
23
|
+
Requires-Dist: torch>=2.5.0
|
|
24
|
+
Requires-Dist: trafilatura>=2.0.0
|
|
25
|
+
Requires-Dist: uvicorn[standard]>=0.32.0
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: httpx>=0.27.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: mypy>=1.14.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: pre-commit>=4.0.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest-cov>=6.0.0; extra == 'dev'
|
|
32
|
+
Requires-Dist: pytest>=8.3.0; extra == 'dev'
|
|
33
|
+
Requires-Dist: ruff>=0.8.0; extra == 'dev'
|
|
34
|
+
Provides-Extra: fast
|
|
35
|
+
Requires-Dist: flash-attn>=2.5.0; extra == 'fast'
|
|
36
|
+
Description-Content-Type: text/markdown
|
|
37
|
+
|
|
38
|
+
# Talking Snake
|
|
39
|
+
|
|
40
|
+
<img src="https://raw.githubusercontent.com/LucaCappelletti94/talking-snake/main/talking_snake.png" alt="Talking Snake" width="400">
|
|
41
|
+
|
|
42
|
+
[](https://github.com/LucaCappelletti94/talking-snake/actions/workflows/ci.yml)
|
|
43
|
+
[](https://codecov.io/gh/LucaCappelletti94/talking-snake)
|
|
44
|
+
|
|
45
|
+
PDF and web page to speech using [Qwen3-TTS](https://huggingface.co/Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice). Upload a document or URL, get it read aloud with 9 natural voices across English, Chinese, Japanese, and Korean. Audio streams progressively while generation continues.
|
|
46
|
+
|
|
47
|
+
## Deploy Your Own
|
|
48
|
+
|
|
49
|
+
[](https://huggingface.co/spaces/LucaCappelletti94/talking-snake?duplicate=true)
|
|
50
|
+
|
|
51
|
+
Click the button above to deploy your own GPU-powered instance. You'll be prompted to create a Hugging Face account and select hardware (L4 or A100 recommended for speed, ~$0.80-$4/hr).
|
|
52
|
+
|
|
53
|
+
## Run Locally
|
|
54
|
+
|
|
55
|
+
Requires Python 3.11+, NVIDIA GPU (~6GB VRAM), and [SoX](https://sourceforge.net/projects/sox/) (`apt install sox libsox-dev`).
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
uv sync && uv run talking-snake --port 8888 # Open http://localhost:8888
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
[▶️ Listen to a sample](https://github.com/LucaCappelletti94/talking-snake/raw/main/src/talking_snake/static/sample.wav)
|
|
63
|
+
|
|
64
|
+
The website looks like this:
|
|
65
|
+
|
|
66
|
+
<img src="https://raw.githubusercontent.com/LucaCappelletti94/talking-snake/main/landing.png" alt="Upload interface" width="400">
|
|
67
|
+
<img src="https://raw.githubusercontent.com/LucaCappelletti94/talking-snake/main/rendering.png" alt="Audio playback with progress" width="400">
|
|
68
|
+
|
|
69
|
+
## License
|
|
70
|
+
|
|
71
|
+
This project is licensed under the [MIT License](LICENSE). Dependencies and third-party components (e.g., Qwen3-TTS, SoX) are subject to their own licenses.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Talking Snake
|
|
2
|
+
|
|
3
|
+
<img src="https://raw.githubusercontent.com/LucaCappelletti94/talking-snake/main/talking_snake.png" alt="Talking Snake" width="400">
|
|
4
|
+
|
|
5
|
+
[](https://github.com/LucaCappelletti94/talking-snake/actions/workflows/ci.yml)
|
|
6
|
+
[](https://codecov.io/gh/LucaCappelletti94/talking-snake)
|
|
7
|
+
|
|
8
|
+
PDF and web page to speech using [Qwen3-TTS](https://huggingface.co/Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice). Upload a document or URL, get it read aloud with 9 natural voices across English, Chinese, Japanese, and Korean. Audio streams progressively while generation continues.
|
|
9
|
+
|
|
10
|
+
## Deploy Your Own
|
|
11
|
+
|
|
12
|
+
[](https://huggingface.co/spaces/LucaCappelletti94/talking-snake?duplicate=true)
|
|
13
|
+
|
|
14
|
+
Click the button above to deploy your own GPU-powered instance. You'll be prompted to create a Hugging Face account and select hardware (L4 or A100 recommended for speed, ~$0.80-$4/hr).
|
|
15
|
+
|
|
16
|
+
## Run Locally
|
|
17
|
+
|
|
18
|
+
Requires Python 3.11+, NVIDIA GPU (~6GB VRAM), and [SoX](https://sourceforge.net/projects/sox/) (`apt install sox libsox-dev`).
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
uv sync && uv run talking-snake --port 8888 # Open http://localhost:8888
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
[▶️ Listen to a sample](https://github.com/LucaCappelletti94/talking-snake/raw/main/src/talking_snake/static/sample.wav)
|
|
26
|
+
|
|
27
|
+
The website looks like this:
|
|
28
|
+
|
|
29
|
+
<img src="https://raw.githubusercontent.com/LucaCappelletti94/talking-snake/main/landing.png" alt="Upload interface" width="400">
|
|
30
|
+
<img src="https://raw.githubusercontent.com/LucaCappelletti94/talking-snake/main/rendering.png" alt="Audio playback with progress" width="400">
|
|
31
|
+
|
|
32
|
+
## License
|
|
33
|
+
|
|
34
|
+
This project is licensed under the [MIT License](LICENSE). Dependencies and third-party components (e.g., Qwen3-TTS, SoX) are subject to their own licenses.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Talking Snake
|
|
3
|
+
emoji: 🐍
|
|
4
|
+
colorFrom: green
|
|
5
|
+
colorTo: purple
|
|
6
|
+
sdk: docker
|
|
7
|
+
pinned: false
|
|
8
|
+
license: mit
|
|
9
|
+
app_port: 7860
|
|
10
|
+
suggested_hardware: l4x1
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Talking Snake
|
|
14
|
+
|
|
15
|
+
PDF and web page to speech using Qwen3-TTS.
|
|
16
|
+
|
|
17
|
+
Click "Duplicate this Space" to deploy your own instance (L4 or A100 recommended for speed).
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import js from "@eslint/js";
|
|
2
|
+
|
|
3
|
+
export default [
|
|
4
|
+
js.configs.recommended,
|
|
5
|
+
{
|
|
6
|
+
files: ["**/*.js"],
|
|
7
|
+
ignores: ["eslint.config.js"],
|
|
8
|
+
languageOptions: {
|
|
9
|
+
ecmaVersion: 2022,
|
|
10
|
+
sourceType: "script",
|
|
11
|
+
globals: {
|
|
12
|
+
document: "readonly",
|
|
13
|
+
window: "readonly",
|
|
14
|
+
console: "readonly",
|
|
15
|
+
fetch: "readonly",
|
|
16
|
+
URL: "readonly",
|
|
17
|
+
Blob: "readonly",
|
|
18
|
+
FormData: "readonly",
|
|
19
|
+
TextDecoder: "readonly",
|
|
20
|
+
AbortController: "readonly",
|
|
21
|
+
EventSource: "readonly",
|
|
22
|
+
setTimeout: "readonly",
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
rules: {
|
|
26
|
+
"no-unused-vars": ["error", { argsIgnorePattern: "^_" }],
|
|
27
|
+
"no-console": "off",
|
|
28
|
+
"prefer-const": "error",
|
|
29
|
+
"no-var": "error",
|
|
30
|
+
eqeqeq: ["error", "always"],
|
|
31
|
+
curly: ["error", "all"],
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
];
|
|
Binary file
|
|
Binary file
|