Upload 46 files
Browse files- BELEL-FEDERATION/docker-compose.egress-denied.yml +59 -0
- BELEL-FEDERATION/docker-compose.yml +69 -0
- BELEL-FEDERATION/models/piper/README.md +12 -0
- BELEL-FEDERATION/models/piper/download_caribbean_voices.py +33 -0
- BELEL-FEDERATION/models/whisper/README.md +7 -0
- BELEL-VOICE/CITATION.cff +6 -0
- BELEL-VOICE/COMPLIANCE/DPIA.md +4 -0
- BELEL-VOICE/COMPLIANCE/EU_AI_ACT_ALIGNMENT.md +5 -0
- BELEL-VOICE/COMPLIANCE/LOCAL_ONLY_OPERATION.md +7 -0
- BELEL-VOICE/COMPLIANCE/WATERMARKING_AND_DISCLOSURE.md +4 -0
- BELEL-VOICE/Dockerfile +8 -0
- BELEL-VOICE/GOVERNANCE/CONSENT_REGISTRY.md +3 -0
- BELEL-VOICE/LEGAL/ATTRIBUTION_AND_CITATION.md +2 -0
- BELEL-VOICE/LEGAL/LICENSE-BELEL-PROTOCOL.txt +5 -0
- BELEL-VOICE/LEGAL/PROVENANCE_POLICY.md +4 -0
- BELEL-VOICE/Makefile +27 -0
- BELEL-VOICE/ONE_PAGER.md +5 -0
- BELEL-VOICE/PRD/PRD_BELEL_VOICE.md +5 -0
- BELEL-VOICE/PRD/api/openapi.yaml +43 -0
- BELEL-VOICE/README.md +54 -0
- BELEL-VOICE/belelvoice/config.yaml +14 -0
- BELEL-VOICE/belelvoice/expressive/layer.py +33 -0
- BELEL-VOICE/belelvoice/policy/load.py +15 -0
- BELEL-VOICE/belelvoice/policy/profiles/DEFAULT.yaml +5 -0
- BELEL-VOICE/belelvoice/policy/profiles/EU.yaml +6 -0
- BELEL-VOICE/belelvoice/policy/profiles/JM.yaml +5 -0
- BELEL-VOICE/belelvoice/policy/profiles/US.yaml +5 -0
- BELEL-VOICE/belelvoice/server/app.py +21 -0
- BELEL-VOICE/belelvoice/server/routers/asr.py +19 -0
- BELEL-VOICE/belelvoice/server/routers/diar.py +18 -0
- BELEL-VOICE/belelvoice/server/routers/policy.py +29 -0
- BELEL-VOICE/belelvoice/server/routers/static_ui.py +10 -0
- BELEL-VOICE/belelvoice/server/routers/tts.py +37 -0
- BELEL-VOICE/belelvoice/server/routers/watchers.py +16 -0
- BELEL-VOICE/belelvoice/server/routers/ws_asr.py +22 -0
- BELEL-VOICE/belelvoice/trust/audit.py +11 -0
- BELEL-VOICE/dist/HASHES.json +117 -0
- BELEL-VOICE/dist/RELEASE_MANIFEST.json +9 -0
- BELEL-VOICE/docs/BLUEPRINT.md +35 -0
- BELEL-VOICE/scripts/net/README.md +2 -0
- BELEL-VOICE/scripts/net/deny_egress.sh +13 -0
- BELEL-VOICE/scripts/release/build_manifest.py +17 -0
- BELEL-VOICE/scripts/release/hash_all.py +15 -0
- BELEL-VOICE/tools/belelvoice_say.py +36 -0
- BELEL-VOICE/webui/app.js +37 -0
- BELEL-VOICE/webui/index.html +25 -0
BELEL-FEDERATION/docker-compose.egress-denied.yml
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version: "3.9"
|
| 2 |
+
|
| 3 |
+
networks:
|
| 4 |
+
internal_net:
|
| 5 |
+
internal: true
|
| 6 |
+
|
| 7 |
+
x-common-env: &common_env
|
| 8 |
+
BELEL_ENV: "prod"
|
| 9 |
+
|
| 10 |
+
services:
|
| 11 |
+
# Local iptables egress-deny sidecar for the voice container
|
| 12 |
+
# The script will drop outbound traffic except to 127.0.0.1 and the internal network.
|
| 13 |
+
belel-voice:
|
| 14 |
+
build: ./BELEL-VOICE
|
| 15 |
+
container_name: belel-voice
|
| 16 |
+
command: bash -lc "apt-get update && apt-get install -y iptables && ./scripts/net/deny_egress.sh && gunicorn -k uvicorn.workers.UvicornWorker belelvoice.server.app:app --bind 0.0.0.0:8000"
|
| 17 |
+
environment:
|
| 18 |
+
<<: *common_env
|
| 19 |
+
VOICE_ENGINE_DEFAULT: "piper"
|
| 20 |
+
ASR_ENGINE_DEFAULT: "faster-whisper"
|
| 21 |
+
PIPER_VOICES_DIR: "/models/piper"
|
| 22 |
+
WHISPER_MODELS_DIR: "/models/whisper"
|
| 23 |
+
volumes:
|
| 24 |
+
- ./models/piper:/models/piper
|
| 25 |
+
- ./models/whisper:/models/whisper
|
| 26 |
+
networks: ["internal_net"]
|
| 27 |
+
cap_add: ["NET_ADMIN"]
|
| 28 |
+
expose: ["8000"]
|
| 29 |
+
profiles: ["voice-egress-denied", "federation-egress-denied"]
|
| 30 |
+
|
| 31 |
+
belel-med:
|
| 32 |
+
build: ./BELEL-MED
|
| 33 |
+
container_name: belel-med
|
| 34 |
+
command: bash -lc "apt-get update && apt-get install -y iptables && ./scripts/net/deny_egress.sh && gunicorn -k uvicorn.workers.UvicornWorker src.server.app:app --bind 0.0.0.0:8001"
|
| 35 |
+
environment:
|
| 36 |
+
<<: *common_env
|
| 37 |
+
VOICE_GATEWAY_URL: "http://belel-voice:8000"
|
| 38 |
+
depends_on: ["belel-voice"]
|
| 39 |
+
networks: ["internal_net"]
|
| 40 |
+
cap_add: ["NET_ADMIN"]
|
| 41 |
+
expose: ["8001"]
|
| 42 |
+
profiles: ["federation-egress-denied"]
|
| 43 |
+
|
| 44 |
+
belel-lex:
|
| 45 |
+
build: ./BELEL-LEX
|
| 46 |
+
container_name: belel-lex
|
| 47 |
+
command: bash -lc "apt-get update && apt-get install -y iptables && ./scripts/net/deny_egress.sh && gunicorn -k uvicorn.workers.UvicornWorker belellex.server.app:app --bind 0.0.0.0:8002"
|
| 48 |
+
environment:
|
| 49 |
+
<<: *common_env
|
| 50 |
+
VOICE_GATEWAY_URL: "http://belel-voice:8000"
|
| 51 |
+
depends_on: ["belel-voice"]
|
| 52 |
+
networks: ["internal_net"]
|
| 53 |
+
cap_add: ["NET_ADMIN"]
|
| 54 |
+
expose: ["8002"]
|
| 55 |
+
profiles: ["federation-egress-denied"]
|
| 56 |
+
|
| 57 |
+
# Usage:
|
| 58 |
+
# docker compose -f docker-compose.egress-denied.yml --profile voice-egress-denied up -d
|
| 59 |
+
# docker compose -f docker-compose.egress-denied.yml --profile federation-egress-denied up -d
|
BELEL-FEDERATION/docker-compose.yml
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version: "3.9"
|
| 2 |
+
|
| 3 |
+
x-common-env: &common_env
|
| 4 |
+
BELEL_ENV: "prod"
|
| 5 |
+
UVICORN_WORKERS: "2"
|
| 6 |
+
|
| 7 |
+
services:
|
| 8 |
+
belel-voice:
|
| 9 |
+
build: ./BELEL-VOICE
|
| 10 |
+
container_name: belel-voice
|
| 11 |
+
command: bash -lc "python -m venv .venv && . .venv/bin/activate && pip install -U pip && pip install fastapi uvicorn pydantic httpx rich pyyaml && gunicorn -k uvicorn.workers.UvicornWorker belelvoice.server.app:app --bind 0.0.0.0:8000"
|
| 12 |
+
ports: ["8000:8000"]
|
| 13 |
+
environment:
|
| 14 |
+
<<: *common_env
|
| 15 |
+
VOICE_ENGINE_DEFAULT: "piper"
|
| 16 |
+
ASR_ENGINE_DEFAULT: "faster-whisper"
|
| 17 |
+
PIPER_VOICES_DIR: "/models/piper"
|
| 18 |
+
WHISPER_MODELS_DIR: "/models/whisper"
|
| 19 |
+
volumes:
|
| 20 |
+
- ./models/piper:/models/piper
|
| 21 |
+
- ./models/whisper:/models/whisper
|
| 22 |
+
profiles: ["voice", "federation", "riva"]
|
| 23 |
+
|
| 24 |
+
# Optional NVIDIA Riva speech microservices (GPU)
|
| 25 |
+
# Requires: nvidia-docker2 & GPUs available.
|
| 26 |
+
riva-speech:
|
| 27 |
+
image: nvcr.io/nvidia/riva/riva-speech:2.14.0-server
|
| 28 |
+
container_name: riva-speech
|
| 29 |
+
runtime: nvidia
|
| 30 |
+
environment:
|
| 31 |
+
- NVIDIA_VISIBLE_DEVICES=all
|
| 32 |
+
ports: ["50051:50051"]
|
| 33 |
+
volumes:
|
| 34 |
+
- ./riva/models:/data
|
| 35 |
+
profiles: ["riva"]
|
| 36 |
+
deploy:
|
| 37 |
+
resources:
|
| 38 |
+
reservations:
|
| 39 |
+
devices:
|
| 40 |
+
- capabilities: [gpu]
|
| 41 |
+
|
| 42 |
+
# BELEL-MED (optional federation)
|
| 43 |
+
belel-med:
|
| 44 |
+
build: ./BELEL-MED
|
| 45 |
+
container_name: belel-med
|
| 46 |
+
command: bash -lc "python -m venv .venv && . .venv/bin/activate && pip install -U pip && pip install fastapi uvicorn pydantic httpx rich && gunicorn -k uvicorn.workers.UvicornWorker src.server.app:app --bind 0.0.0.0:8001"
|
| 47 |
+
ports: ["8001:8001"]
|
| 48 |
+
environment:
|
| 49 |
+
<<: *common_env
|
| 50 |
+
VOICE_GATEWAY_URL: "http://belel-voice:8000"
|
| 51 |
+
depends_on: ["belel-voice"]
|
| 52 |
+
profiles: ["federation"]
|
| 53 |
+
|
| 54 |
+
# BELEL-LEX (optional federation)
|
| 55 |
+
belel-lex:
|
| 56 |
+
build: ./BELEL-LEX
|
| 57 |
+
container_name: belel-lex
|
| 58 |
+
command: bash -lc "python -m venv .venv && . .venv/bin/activate && pip install -U pip && pip install fastapi uvicorn pydantic httpx rich && gunicorn -k uvicorn.workers.UvicornWorker belellex.server.app:app --bind 0.0.0.0:8002"
|
| 59 |
+
ports: ["8002:8002"]
|
| 60 |
+
environment:
|
| 61 |
+
<<: *common_env
|
| 62 |
+
VOICE_GATEWAY_URL: "http://belel-voice:8000"
|
| 63 |
+
depends_on: ["belel-voice"]
|
| 64 |
+
profiles: ["federation"]
|
| 65 |
+
|
| 66 |
+
# Usage:
|
| 67 |
+
# docker compose --profile voice up -d
|
| 68 |
+
# docker compose --profile riva --profile voice up -d
|
| 69 |
+
# docker compose --profile federation up -d (starts voice + med + lex)
|
BELEL-FEDERATION/models/piper/README.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Piper Voice Pack (English/Caribbean)
|
| 2 |
+
|
| 3 |
+
Place Piper voice model files here, e.g.:
|
| 4 |
+
- en_US-amy-medium.onnx
|
| 5 |
+
- en_GB-sean-medium.onnx
|
| 6 |
+
- en_CARIB-custom-medium.onnx (if available or trained)
|
| 7 |
+
|
| 8 |
+
How to fetch examples:
|
| 9 |
+
- See https://github.com/rhasspy/piper/releases for official voices.
|
| 10 |
+
- For Caribbean English, pick a close accent (en_GB / en_US) or train your own; drop files into this folder.
|
| 11 |
+
|
| 12 |
+
The Docker Compose mounts this folder at /models/piper for BELEL-VOICE.
|
BELEL-FEDERATION/models/piper/download_caribbean_voices.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
Download an open Piper voice approximating Caribbean English.
|
| 3 |
+
Uses public Piper releases; select en_GB/en_US voices with warmer prosody until a true Caribbean model is added.
|
| 4 |
+
|
| 5 |
+
import argparse, os, sys, pathlib, urllib.request, shutil
|
| 6 |
+
|
| 7 |
+
VOICES = [
|
| 8 |
+
# Fallback chain (public Piper release assets; URLs are examples and may change)
|
| 9 |
+
("en_GB-sean-medium.onnx", "https://github.com/rhasspy/piper/releases/download/2024.07.0/en_GB-sean-medium.onnx"),
|
| 10 |
+
("en_US-amy-medium.onnx", "https://github.com/rhasspy/piper/releases/download/2024.07.0/en_US-amy-medium.onnx"),
|
| 11 |
+
]
|
| 12 |
+
|
| 13 |
+
def main():
|
| 14 |
+
ap = argparse.ArgumentParser()
|
| 15 |
+
ap.add_argument("--dest", default="models/piper")
|
| 16 |
+
args = ap.parse_args()
|
| 17 |
+
dest = pathlib.Path(args.dest)
|
| 18 |
+
dest.mkdir(parents=True, exist_ok=True)
|
| 19 |
+
for name, url in VOICES:
|
| 20 |
+
out = dest / name
|
| 21 |
+
if out.exists():
|
| 22 |
+
print("Already present:", out)
|
| 23 |
+
continue
|
| 24 |
+
print("Downloading:", name)
|
| 25 |
+
try:
|
| 26 |
+
with urllib.request.urlopen(url) as r, open(out, "wb") as f:
|
| 27 |
+
shutil.copyfileobj(r, f)
|
| 28 |
+
print("Saved:", out)
|
| 29 |
+
except Exception as e:
|
| 30 |
+
print("Failed to download", name, "from", url, "->", e)
|
| 31 |
+
print("Done. Place any additional Caribbean-accent voices here when available.")
|
| 32 |
+
if __name__ == "__main__":
|
| 33 |
+
main()
|
BELEL-FEDERATION/models/whisper/README.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Whisper (faster-whisper/CT2) Models
|
| 2 |
+
|
| 3 |
+
Place CTranslate2 Whisper models here, e.g.:
|
| 4 |
+
- large-v3-ct2/
|
| 5 |
+
- medium-ct2/
|
| 6 |
+
|
| 7 |
+
Get models: https://github.com/guillaumekln/faster-whisper
|
BELEL-VOICE/CITATION.cff
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
cff-version: 1.2.0
|
| 2 |
+
title: "BELEL-VOICE — Sovereign Speech Stack"
|
| 3 |
+
message: "Please cite this work if you use it."
|
| 4 |
+
authors: [{family-names: Robinson, given-names: Pearce}]
|
| 5 |
+
version: 0.1.0
|
| 6 |
+
date-released: 2025-10-06
|
BELEL-VOICE/COMPLIANCE/DPIA.md
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# DPIA — BELEL-VOICE
|
| 2 |
+
Data: microphone audio, voiceprints (optional), transcripts.
|
| 3 |
+
Risks: biometric misuse, deepfake misuse, undisclosed synthetic audio.
|
| 4 |
+
Mitigations: explicit consent registry, watermarking, disclosure banners, anti‑spoof, on-device processing, audit logging.
|
BELEL-VOICE/COMPLIANCE/EU_AI_ACT_ALIGNMENT.md
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# EU AI Act Alignment (Audio focus)
|
| 2 |
+
- Label synthetic audio (machine‑readable) and provide user disclosure.
|
| 3 |
+
- Maintain logs and technical documentation.
|
| 4 |
+
- Human oversight for critical uses.
|
| 5 |
+
- Data governance: source tracking; consent for voice cloning.
|
BELEL-VOICE/COMPLIANCE/LOCAL_ONLY_OPERATION.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Offline / Local-Only Operation
|
| 2 |
+
|
| 3 |
+
- The default adapters (Piper + faster-whisper) run entirely on your machine.
|
| 4 |
+
- To enforce **no egress**, deploy your Docker stack behind a firewall or set Docker's default network to none
|
| 5 |
+
for production containers and explicitly whitelist internal services only.
|
| 6 |
+
- For Kubernetes, use NetworkPolicies to **deny egress** by default and allow only cluster-local DNS and storage.
|
| 7 |
+
- Logs contain no external URLs; watermarking & disclosure are ON by default.
|
BELEL-VOICE/COMPLIANCE/WATERMARKING_AND_DISCLOSURE.md
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Watermarking & Disclosure
|
| 2 |
+
- Embed robust, interoperable watermarks (e.g., freq‑domain markers) + metadata tags.
|
| 3 |
+
- Attach disclosure headers in file/container (ID3/XMP), and JSON sidecar.
|
| 4 |
+
- Provide detection tool for internal audits.
|
BELEL-VOICE/Dockerfile
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM python:3.11-slim
|
| 2 |
+
WORKDIR /app
|
| 3 |
+
COPY . /app
|
| 4 |
+
RUN python -m pip install --upgrade pip
|
| 5 |
+
# Install minimal runtime dependencies; each Makefile installs more on start.
|
| 6 |
+
RUN pip install fastapi uvicorn pydantic httpx rich pyyaml gunicorn
|
| 7 |
+
EXPOSE 8000
|
| 8 |
+
CMD ["bash","-lc","gunicorn -k uvicorn.workers.UvicornWorker belelvoice.server.app:app --bind 0.0.0.0:8000"]
|
BELEL-VOICE/GOVERNANCE/CONSENT_REGISTRY.md
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Voice Cloning Consent & Registry
|
| 2 |
+
- Consent objects: subject, scope (languages, duration), revocation URL, hash of reference audio, signature.
|
| 3 |
+
- Required before enabling clone_ref synthesis.
|
BELEL-VOICE/LEGAL/ATTRIBUTION_AND_CITATION.md
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Attribution & Citation
|
| 2 |
+
Cite: "BELEL-VOICE — Sovereign Speech Stack (TTOPM)"
|
BELEL-VOICE/LEGAL/LICENSE-BELEL-PROTOCOL.txt
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
BELEL Protocol Sovereign License (BPSL) v1.0
|
| 2 |
+
- Mandatory attribution: "BELEL-VOICE — Sovereign Speech Stack (TTOPM)"
|
| 3 |
+
- Preserve provenance & watermarking hooks
|
| 4 |
+
- Voice cloning only with explicit consent and lawful purpose
|
| 5 |
+
- Derivatives must keep these terms
|
BELEL-VOICE/LEGAL/PROVENANCE_POLICY.md
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Provenance & Anti‑Plagiarism
|
| 2 |
+
- Headers embedded in code
|
| 3 |
+
- Release hashes + signed manifest
|
| 4 |
+
- Disclosure & watermarking hooks must remain enabled by default
|
BELEL-VOICE/Makefile
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.PHONY: help dev prod test lint sbom hash manifest
|
| 2 |
+
|
| 3 |
+
help:
|
| 4 |
+
@echo "Targets: dev, prod, test, lint, sbom, hash, manifest"
|
| 5 |
+
|
| 6 |
+
dev:
|
| 7 |
+
python -m venv .venv && . .venv/bin/activate && pip install -U pip && pip install fastapi uvicorn pydantic httpx rich pyyaml
|
| 8 |
+
UVICORN_RELOAD=true uvicorn belelvoice.server.app:app --reload
|
| 9 |
+
|
| 10 |
+
prod:
|
| 11 |
+
python -m venv .venv && . .venv/bin/activate && pip install -U pip && pip install fastapi uvicorn pydantic gunicorn pyyaml
|
| 12 |
+
gunicorn -k uvicorn.workers.UvicornWorker belelvoice.server.app:app --bind 0.0.0.0:8000
|
| 13 |
+
|
| 14 |
+
test:
|
| 15 |
+
@echo "Add unit tests here"; exit 0
|
| 16 |
+
|
| 17 |
+
lint:
|
| 18 |
+
@echo "Add ruff/flake8 here"; exit 0
|
| 19 |
+
|
| 20 |
+
sbom:
|
| 21 |
+
@echo "SBOM placeholder" > dist/SBOM.txt
|
| 22 |
+
|
| 23 |
+
hash:
|
| 24 |
+
@python scripts/release/hash_all.py
|
| 25 |
+
|
| 26 |
+
manifest:
|
| 27 |
+
@python scripts/release/build_manifest.py
|
BELEL-VOICE/ONE_PAGER.md
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# BELEL-VOICE — Sponsor One-Pager
|
| 2 |
+
|
| 3 |
+
**What:** A sovereign, verifiable speech layer for Belel systems — independent of any single cloud vendor.
|
| 4 |
+
**Why:** Reduce latency/cost/risk, own your data path, satisfy EU AI Act labeling & consent, scale globally.
|
| 5 |
+
**Value:** On-device privacy, real-time UX, consistent voices, lawful cloning with consent, deep auditability.
|
BELEL-VOICE/PRD/PRD_BELEL_VOICE.md
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# PRD — BELEL-VOICE
|
| 2 |
+
Goals: Vendor‑neutral speech layer for Belel (MED/LEX/etc.).
|
| 3 |
+
KPIs: ASR WER vs. Whisper-v3 parity; latency P95 < 300ms; TTS MOS >= 4.2; consent % = 100 for cloning; zero undisclosed synthetic audio.
|
| 4 |
+
Scope: ASR/TTS adapters, streaming, diarization, ITN, watermarking, consent registry, policy engine, APIs.
|
| 5 |
+
Non-goals: Shipping proprietary model weights; deep UI.
|
BELEL-VOICE/PRD/api/openapi.yaml
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
openapi: 3.0.3
|
| 2 |
+
info:
|
| 3 |
+
title: BELEL-VOICE API
|
| 4 |
+
version: 0.1.0
|
| 5 |
+
paths:
|
| 6 |
+
/v1/asr/stream:
|
| 7 |
+
get:
|
| 8 |
+
summary: WebSocket endpoint for streaming ASR (JSON frames)
|
| 9 |
+
/v1/asr/transcribe:
|
| 10 |
+
post:
|
| 11 |
+
summary: Batch transcription
|
| 12 |
+
/v1/tts/synthesize:
|
| 13 |
+
post:
|
| 14 |
+
summary: TTS synthesis (with optional cloning if consent on file)
|
| 15 |
+
/v1/diarize:
|
| 16 |
+
post:
|
| 17 |
+
summary: Speaker diarization for audio
|
| 18 |
+
/v1/policy/check:
|
| 19 |
+
post:
|
| 20 |
+
summary: Check EU AI Act disclosure/watermarking/consent compliance
|
| 21 |
+
/v1/watchers/run:
|
| 22 |
+
post:
|
| 23 |
+
summary: Run model/corpus watcher and produce changelog
|
| 24 |
+
components:
|
| 25 |
+
schemas:
|
| 26 |
+
TranscribeRequest:
|
| 27 |
+
type: object
|
| 28 |
+
properties: { audio_url: { type: string }, language: { type: string }, domain: { type: string } }
|
| 29 |
+
TTSRequest:
|
| 30 |
+
type: object
|
| 31 |
+
properties:
|
| 32 |
+
text: { type: string }
|
| 33 |
+
voice: { type: string }
|
| 34 |
+
engine: { type: string, enum: [piper, xtts, riva] }
|
| 35 |
+
clone_ref: { type: string }
|
| 36 |
+
require_disclosure: { type: boolean }
|
| 37 |
+
PolicyCheckRequest:
|
| 38 |
+
type: object
|
| 39 |
+
properties:
|
| 40 |
+
mode: { type: string, enum: [record, playback, publish] }
|
| 41 |
+
jurisdiction: { type: string }
|
| 42 |
+
requires_disclosure: { type: boolean }
|
| 43 |
+
watermark_present: { type: boolean }
|
BELEL-VOICE/README.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
> **Vision — Belel-Voice**
|
| 2 |
+
> Our voices must be unique, defining, and alive. They should carry the same depth, realism, and expressive range as the most advanced systems on Earth — ElevenLabs, OpenAI, and every benchmark of generative speech to date. Each voice must project human authenticity: the breath, the pause, the subtle emotion that makes it feel lived-in. **Belel-Voice will meet and surpass** the expressive power, tonal precision, and performance quality of the world’s leading AI voice platforms, while remaining fully sovereign, self-evolving, and ethically governed. These are not synthetic voices; they are living signatures — crafted to be first-class in sound, in feeling, and in truth.
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
# BELEL-VOICE — Sovereign Speech Stack (ASR/STT + TTS)
|
| 6 |
+
|
| 7 |
+

|
| 8 |
+

|
| 9 |
+

|
| 10 |
+

|
| 11 |
+
|
| 12 |
+
**Date:** 2025-10-06 11:52:15Z
|
| 13 |
+
|
| 14 |
+
A complete, **OpenAI‑independent** speech stack for **on-device** and **on‑prem** deployments:
|
| 15 |
+
- **ASR**: faster‑whisper (Whisper‑v3 via CTranslate2), MMS, or NVIDIA Riva.
|
| 16 |
+
- **Diarization**: pyannote (switchable to NVIDIA NeMo/SpeechBrain).
|
| 17 |
+
- **TTS**: Piper (lightweight, offline), XTTS‑v2 (zero‑shot cloning with consent), or Riva TTS.
|
| 18 |
+
- **Streaming**: WebSocket low‑latency ASR + chunked TTS synthesis; VAD; ITN; profanity redaction (optional).
|
| 19 |
+
- **Compliance**: watermarking hooks, **EU AI Act** disclosure, consent registry, anti‑spoof, and audit ledger.
|
| 20 |
+
|
| 21 |
+
> Heavy models are not bundled; adapters are ready. Plug your chosen models in `belelvoice/adapters/*`.
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
## Offline / No-Paid-Services Mode
|
| 25 |
+
Use `Piper` (TTS) + `faster-whisper` (ASR). Place models under `models/` (see federation README).
|
| 26 |
+
Run:
|
| 27 |
+
```bash
|
| 28 |
+
docker compose --profile voice up -d
|
| 29 |
+
```
|
| 30 |
+
This uses only local CPU/GPU resources. No calls to OpenAI or any paid API are required.
|
| 31 |
+
|
| 32 |
+
## Premium Expressive Layer
|
| 33 |
+
- **XTTS-v2** (zero-shot cloning, local) + **BigVGAN** vocoder hook for studio timbre.
|
| 34 |
+
- **ProsodyController** for SSML-like tags: `<speak style="warm" pitch="+2st" rate="0.95">`.
|
| 35 |
+
|
| 36 |
+
Enable by pointing to local models in `belelvoice/config.yaml` and switching `engine="xtts"` in requests.
|
| 37 |
+
|
| 38 |
+
## CLI Quick Test
|
| 39 |
+
```bash
|
| 40 |
+
./tools/belelvoice_say.py --text "This is Belel, speaking locally with a natural human voice." --voice en_GB --engine piper
|
| 41 |
+
```
|
| 42 |
+
|
| 43 |
+
## Egress-Denied Profile
|
| 44 |
+
Start fully offline (no outbound traffic) with an internal-only network:
|
| 45 |
+
```bash
|
| 46 |
+
cd ../BELEL-FEDERATION
|
| 47 |
+
docker compose -f docker-compose.egress-denied.yml --profile voice-egress-denied up -d
|
| 48 |
+
```
|
| 49 |
+
Then open the **local UI** (served by BELEL-VOICE):
|
| 50 |
+
```
|
| 51 |
+
http://localhost:8000/webui
|
| 52 |
+
```
|
| 53 |
+
|
| 54 |
+
> The iptables script blocks outbound traffic except private ranges; adjust CIDRs as needed.
|
BELEL-VOICE/belelvoice/config.yaml
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
engine_defaults:
|
| 2 |
+
tts: piper # piper | xtts | riva
|
| 3 |
+
asr: faster-whisper # faster-whisper | mms | riva
|
| 4 |
+
voices:
|
| 5 |
+
primary: en_GB-sean-medium.onnx
|
| 6 |
+
backup: en_US-amy-medium.onnx
|
| 7 |
+
xtts:
|
| 8 |
+
clone_ref: ./models/voices/sample_voice.wav
|
| 9 |
+
enable: false
|
| 10 |
+
bigvgan:
|
| 11 |
+
enable: false
|
| 12 |
+
paths:
|
| 13 |
+
piper_voices: /models/piper
|
| 14 |
+
whisper_models: /models/whisper
|
BELEL-VOICE/belelvoice/expressive/layer.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
BELEL-VOICE // Expressive Layer
|
| 3 |
+
- XTTS-v2 adapter for zero-shot cloning (with consent)
|
| 4 |
+
- BigVGAN vocoder hook for high-fidelity timbre
|
| 5 |
+
- ProsodyController for SSML-like style, rate, pitch, and emotion
|
| 6 |
+
NOTE: This is a stub with clear method signatures. Plug actual models locally.
|
| 7 |
+
*/
|
| 8 |
+
from typing import Optional, Dict
|
| 9 |
+
|
| 10 |
+
class ProsodyController:
|
| 11 |
+
def __init__(self):
|
| 12 |
+
# Default style params; can be learned per voice
|
| 13 |
+
self.params = {"style":"neutral","rate":1.0,"pitch_semitones":0.0,"energy":1.0,"breath":0.1,"smile":0.0}
|
| 14 |
+
def apply(self, text: str, tags: Optional[Dict]=None) -> Dict:
|
| 15 |
+
cfg = self.params.copy()
|
| 16 |
+
if tags:
|
| 17 |
+
cfg.update(tags)
|
| 18 |
+
# Return normalized prosody parameters for the TTS engine
|
| 19 |
+
return cfg
|
| 20 |
+
|
| 21 |
+
class XTTSAdapter:
|
| 22 |
+
def __init__(self, model_path: str = "./models/xtts"):
|
| 23 |
+
self.model_path = model_path
|
| 24 |
+
def synthesize(self, text: str, voice_ref: Optional[str], prosody: Dict) -> bytes:
|
| 25 |
+
# TODO: Call local XTTS; pass style params; return PCM/WAV bytes
|
| 26 |
+
return b""
|
| 27 |
+
|
| 28 |
+
class BigVGANVocoder:
|
| 29 |
+
def __init__(self, model_path: str = "./models/bigvgan"):
|
| 30 |
+
self.model_path = model_path
|
| 31 |
+
def render(self, mel: bytes) -> bytes:
|
| 32 |
+
# TODO: Convert mel to waveform via local BigVGAN
|
| 33 |
+
return b""
|
BELEL-VOICE/belelvoice/policy/load.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
BELEL-VOICE // Sovereign Speech Stack (ASR + TTS + Streaming)
|
| 3 |
+
Copyright (c) 2025 The Office of Pearce Robinson (TTOPM)
|
| 4 |
+
License: BELEL Protocol Sovereign License (BPSL) v1.0 (see LEGAL/LICENSE-BELEL-PROTOCOL.txt)
|
| 5 |
+
Provenance mandatory: cite "BELEL-VOICE — Sovereign Speech Stack (TTOPM)".
|
| 6 |
+
Generated: 2025-10-06 11:52:15Z
|
| 7 |
+
*/
|
| 8 |
+
import yaml, pathlib
|
| 9 |
+
|
| 10 |
+
def policy_for(jurisdiction: str) -> dict:
|
| 11 |
+
base = pathlib.Path(__file__).resolve().parents[1] / "policy" / "profiles" / f"{jurisdiction}.yaml"
|
| 12 |
+
if base.exists():
|
| 13 |
+
return yaml.safe_load(base.read_text())
|
| 14 |
+
default = pathlib.Path(__file__).resolve().parents[1] / "policy" / "profiles" / "DEFAULT.yaml"
|
| 15 |
+
return yaml.safe_load(default.read_text())
|
BELEL-VOICE/belelvoice/policy/profiles/DEFAULT.yaml
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
region: GLOBAL
|
| 2 |
+
require_disclosure: true
|
| 3 |
+
allow_cloning_with_consent: true
|
| 4 |
+
anti_spoof_required: true
|
| 5 |
+
notes: "Conservative defaults aligned with EU AI Act transparency."
|
BELEL-VOICE/belelvoice/policy/profiles/EU.yaml
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
region: EU
|
| 2 |
+
require_disclosure: true
|
| 3 |
+
allow_cloning_with_consent: true
|
| 4 |
+
anti_spoof_required: true
|
| 5 |
+
refs:
|
| 6 |
+
- EU AI Act transparency on synthetic media
|
BELEL-VOICE/belelvoice/policy/profiles/JM.yaml
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
region: JM
|
| 2 |
+
require_disclosure: true
|
| 3 |
+
allow_cloning_with_consent: true
|
| 4 |
+
anti_spoof_required: true
|
| 5 |
+
notes: "Aligns with government transparency guidance; update when PDs publish."
|
BELEL-VOICE/belelvoice/policy/profiles/US.yaml
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
region: US
|
| 2 |
+
require_disclosure: true
|
| 3 |
+
allow_cloning_with_consent: true
|
| 4 |
+
anti_spoof_required: true
|
| 5 |
+
notes: "State-level deepfake/voice laws vary; override as needed."
|
BELEL-VOICE/belelvoice/server/app.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
BELEL-VOICE // Sovereign Speech Stack (ASR + TTS + Streaming)
|
| 3 |
+
Copyright (c) 2025 The Office of Pearce Robinson (TTOPM)
|
| 4 |
+
License: BELEL Protocol Sovereign License (BPSL) v1.0 (see LEGAL/LICENSE-BELEL-PROTOCOL.txt)
|
| 5 |
+
Provenance mandatory: cite "BELEL-VOICE — Sovereign Speech Stack (TTOPM)".
|
| 6 |
+
Generated: 2025-10-06 11:52:15Z
|
| 7 |
+
*/
|
| 8 |
+
from fastapi import FastAPI, WebSocket, UploadFile, File
|
| 9 |
+
from .routers import asr, tts, diar, policy, watchers, static_ui, ws_asr
|
| 10 |
+
|
| 11 |
+
app = FastAPI(title="BELEL-VOICE API", version="0.1.0")
|
| 12 |
+
|
| 13 |
+
app.include_router(asr.router, prefix="/v1/asr", tags=["asr"])
|
| 14 |
+
app.include_router(tts.router, prefix="/v1/tts", tags=["tts"])
|
| 15 |
+
app.include_router(diar.router, prefix="/v1", tags=["diarization"])
|
| 16 |
+
app.include_router(policy.router, prefix="/v1/policy", tags=["policy"])
|
| 17 |
+
app.include_router(watchers.router, prefix="/v1/watchers", tags=["watchers"])\napp.include_router(static_ui.router, prefix="/", tags=["ui"])\napp.include_router(ws_asr.router, prefix="/v1/asr", tags=["asr-ws"])
|
| 18 |
+
|
| 19 |
+
@app.get("/healthz")
|
| 20 |
+
def healthz():
|
| 21 |
+
return {"ok": True}
|
BELEL-VOICE/belelvoice/server/routers/asr.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
BELEL-VOICE // Sovereign Speech Stack (ASR + TTS + Streaming)
|
| 3 |
+
Copyright (c) 2025 The Office of Pearce Robinson (TTOPM)
|
| 4 |
+
License: BELEL Protocol Sovereign License (BPSL) v1.0 (see LEGAL/LICENSE-BELEL-PROTOCOL.txt)
|
| 5 |
+
Provenance mandatory: cite "BELEL-VOICE — Sovereign Speech Stack (TTOPM)".
|
| 6 |
+
Generated: 2025-10-06 11:52:15Z
|
| 7 |
+
*/
|
| 8 |
+
from fastapi import APIRouter, UploadFile, File
|
| 9 |
+
from typing import Dict, Any
|
| 10 |
+
from ..trust.audit import audit_hash
|
| 11 |
+
|
| 12 |
+
router = APIRouter()
|
| 13 |
+
|
| 14 |
+
@router.post("/transcribe")
|
| 15 |
+
async def transcribe(file: UploadFile = File(...), language: str = "auto") -> Dict[str, Any]:
|
| 16 |
+
# Placeholder: call adapter (e.g., faster-whisper) with streaming/batch
|
| 17 |
+
content = await file.read()
|
| 18 |
+
# In production, pass content to the adapter and return segments with timestamps.
|
| 19 |
+
return {"text": "example transcript", "language": language, "audit_sha256": audit_hash({"len": len(content)})}
|
BELEL-VOICE/belelvoice/server/routers/diar.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
BELEL-VOICE // Sovereign Speech Stack (ASR + TTS + Streaming)
|
| 3 |
+
Copyright (c) 2025 The Office of Pearce Robinson (TTOPM)
|
| 4 |
+
License: BELEL Protocol Sovereign License (BPSL) v1.0 (see LEGAL/LICENSE-BELEL-PROTOCOL.txt)
|
| 5 |
+
Provenance mandatory: cite "BELEL-VOICE — Sovereign Speech Stack (TTOPM)".
|
| 6 |
+
Generated: 2025-10-06 11:52:15Z
|
| 7 |
+
*/
|
| 8 |
+
from fastapi import APIRouter, UploadFile, File
|
| 9 |
+
from typing import Dict, Any
|
| 10 |
+
from ..trust.audit import audit_hash
|
| 11 |
+
|
| 12 |
+
router = APIRouter()
|
| 13 |
+
|
| 14 |
+
@router.post("/diarize")
|
| 15 |
+
async def diarize(file: UploadFile = File(...)) -> Dict[str, Any]:
|
| 16 |
+
# Placeholder: call pyannote or other diarization pipeline
|
| 17 |
+
content = await file.read()
|
| 18 |
+
return {"segments": [{"speaker":"S1","start":0.0,"end":5.5}], "audit_sha256": audit_hash({"len": len(content)})}
|
BELEL-VOICE/belelvoice/server/routers/policy.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
BELEL-VOICE // Sovereign Speech Stack (ASR + TTS + Streaming)
|
| 3 |
+
Copyright (c) 2025 The Office of Pearce Robinson (TTOPM)
|
| 4 |
+
License: BELEL Protocol Sovereign License (BPSL) v1.0 (see LEGAL/LICENSE-BELEL-PROTOCOL.txt)
|
| 5 |
+
Provenance mandatory: cite "BELEL-VOICE — Sovereign Speech Stack (TTOPM)".
|
| 6 |
+
Generated: 2025-10-06 11:52:15Z
|
| 7 |
+
*/
|
| 8 |
+
from fastapi import APIRouter
|
| 9 |
+
from pydantic import BaseModel
|
| 10 |
+
from typing import Dict, Any
|
| 11 |
+
from ..policy.load import policy_for
|
| 12 |
+
|
| 13 |
+
router = APIRouter()
|
| 14 |
+
|
| 15 |
+
class PolicyCheck(BaseModel):
|
| 16 |
+
mode: str # record | playback | publish
|
| 17 |
+
jurisdiction: str
|
| 18 |
+
requires_disclosure: bool = True
|
| 19 |
+
watermark_present: bool = False
|
| 20 |
+
|
| 21 |
+
@router.post("/check")
|
| 22 |
+
def check(req: PolicyCheck) -> Dict[str, Any]:
|
| 23 |
+
pol = policy_for(req.jurisdiction)
|
| 24 |
+
compliant = True
|
| 25 |
+
reasons = []
|
| 26 |
+
if req.requires_disclosure and not req.watermark_present and pol.get("require_disclosure", True):
|
| 27 |
+
compliant = False
|
| 28 |
+
reasons.append("Disclosure/watermark missing for synthetic audio.")
|
| 29 |
+
return {"compliant": compliant, "reasons": reasons, "policy": pol}
|
BELEL-VOICE/belelvoice/server/routers/static_ui.py
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import APIRouter
|
| 2 |
+
from fastapi.responses import FileResponse
|
| 3 |
+
import pathlib
|
| 4 |
+
|
| 5 |
+
router = APIRouter()
|
| 6 |
+
|
| 7 |
+
@router.get("/webui")
|
| 8 |
+
def ui_index():
|
| 9 |
+
base = pathlib.Path(__file__).resolve().parents[2] / "webui" / "index.html"
|
| 10 |
+
return FileResponse(str(base))
|
BELEL-VOICE/belelvoice/server/routers/tts.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
BELEL-VOICE // Sovereign Speech Stack (ASR + TTS + Streaming)
|
| 3 |
+
Copyright (c) 2025 The Office of Pearce Robinson (TTOPM)
|
| 4 |
+
License: BELEL Protocol Sovereign License (BPSL) v1.0 (see LEGAL/LICENSE-BELEL-PROTOCOL.txt)
|
| 5 |
+
Provenance mandatory: cite "BELEL-VOICE — Sovereign Speech Stack (TTOPM)".
|
| 6 |
+
Generated: 2025-10-06 11:52:15Z
|
| 7 |
+
*/
|
| 8 |
+
from fastapi import APIRouter
|
| 9 |
+
from pydantic import BaseModel
|
| 10 |
+
from typing import Optional, Dict, Any
|
| 11 |
+
from ..trust.audit import audit_hash
|
| 12 |
+
from ..policy.load import policy_for
|
| 13 |
+
|
| 14 |
+
router = APIRouter()
|
| 15 |
+
|
| 16 |
+
class TTSRequest(BaseModel):
|
| 17 |
+
text: str
|
| 18 |
+
voice: str = "en_US_female"
|
| 19 |
+
engine: str = "piper" # piper | xtts | riva
|
| 20 |
+
clone_ref: Optional[str] = None
|
| 21 |
+
require_disclosure: bool = True
|
| 22 |
+
jurisdiction: str = "EU"
|
| 23 |
+
|
| 24 |
+
@router.post("/synthesize")
|
| 25 |
+
def synth(req: TTSRequest) -> Dict[str, Any]:
|
| 26 |
+
pol = policy_for(req.jurisdiction)
|
| 27 |
+
if req.clone_ref and not pol.get("allow_cloning_with_consent", True):
|
| 28 |
+
return {"error": "Cloning not permitted in this jurisdiction", "compliant": False}
|
| 29 |
+
# Placeholder: route to engine adapter, return URL or bytes
|
| 30 |
+
disclosure = "SYNTHETIC-VOICE" if req.require_disclosure or pol.get("require_disclosure", True) else ""
|
| 31 |
+
return {
|
| 32 |
+
"audio_ref": "file://example.wav",
|
| 33 |
+
"engine": req.engine,
|
| 34 |
+
"disclosure": disclosure,
|
| 35 |
+
"audit_sha256": audit_hash(req.dict()),
|
| 36 |
+
"compliant": True
|
| 37 |
+
}
|
BELEL-VOICE/belelvoice/server/routers/watchers.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
BELEL-VOICE // Sovereign Speech Stack (ASR + TTS + Streaming)
|
| 3 |
+
Copyright (c) 2025 The Office of Pearce Robinson (TTOPM)
|
| 4 |
+
License: BELEL Protocol Sovereign License (BPSL) v1.0 (see LEGAL/LICENSE-BELEL-PROTOCOL.txt)
|
| 5 |
+
Provenance mandatory: cite "BELEL-VOICE — Sovereign Speech Stack (TTOPM)".
|
| 6 |
+
Generated: 2025-10-06 11:52:15Z
|
| 7 |
+
*/
|
| 8 |
+
from fastapi import APIRouter
|
| 9 |
+
from typing import Dict, Any
|
| 10 |
+
|
| 11 |
+
router = APIRouter()
|
| 12 |
+
|
| 13 |
+
@router.post("/run")
|
| 14 |
+
def run() -> Dict[str, Any]:
|
| 15 |
+
# Placeholder: would check HF model hubs, vendor pages, CVEs/safety notes.
|
| 16 |
+
return {"updated": ["whisper-large-v3 adapter", "piper-voice-en_GB-new"], "notes": "Changelog created."}
|
BELEL-VOICE/belelvoice/server/routers/ws_asr.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import APIRouter, WebSocket, WebSocketDisconnect
|
| 2 |
+
from fastapi.responses import JSONResponse
|
| 3 |
+
import tempfile, wave, time, os
|
| 4 |
+
from ..trust.audit import audit_hash
|
| 5 |
+
|
| 6 |
+
router = APIRouter()
|
| 7 |
+
|
| 8 |
+
@router.websocket("/stream")
|
| 9 |
+
async def ws_stream(ws: WebSocket):
|
| 10 |
+
await ws.accept()
|
| 11 |
+
# In production: feed chunks to streaming ASR (VAD + partials)
|
| 12 |
+
pcm_path = tempfile.mktemp(suffix=".webm")
|
| 13 |
+
try:
|
| 14 |
+
while True:
|
| 15 |
+
data = await ws.receive_bytes()
|
| 16 |
+
# Here we would pass data to ASR stream and emit partials
|
| 17 |
+
await ws.send_text('{"partial":"..."}')
|
| 18 |
+
except WebSocketDisconnect:
|
| 19 |
+
# On close: finalize ASR, synthesize a reply via local TTS
|
| 20 |
+
# Placeholder: create a local URL to a static wav (or generated file)
|
| 21 |
+
reply_url = "file://" + os.path.abspath(__file__)
|
| 22 |
+
await ws.close()
|
BELEL-VOICE/belelvoice/trust/audit.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
BELEL-VOICE // Sovereign Speech Stack (ASR + TTS + Streaming)
|
| 3 |
+
Copyright (c) 2025 The Office of Pearce Robinson (TTOPM)
|
| 4 |
+
License: BELEL Protocol Sovereign License (BPSL) v1.0 (see LEGAL/LICENSE-BELEL-PROTOCOL.txt)
|
| 5 |
+
Provenance mandatory: cite "BELEL-VOICE — Sovereign Speech Stack (TTOPM)".
|
| 6 |
+
Generated: 2025-10-06 11:52:15Z
|
| 7 |
+
*/
|
| 8 |
+
import hashlib, json
|
| 9 |
+
def audit_hash(obj) -> str:
|
| 10 |
+
data = json.dumps(obj, sort_keys=True).encode("utf-8")
|
| 11 |
+
return hashlib.sha256(data).hexdigest()
|
BELEL-VOICE/dist/HASHES.json
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"generated": "2025-10-06T11:52:15.243876Z",
|
| 3 |
+
"files": [
|
| 4 |
+
{
|
| 5 |
+
"path": "README.md",
|
| 6 |
+
"sha256": "ac5dea9ce8913e53ede877c8f313380f065f941901664b5c6ab383a8187a3898"
|
| 7 |
+
},
|
| 8 |
+
{
|
| 9 |
+
"path": "ONE_PAGER.md",
|
| 10 |
+
"sha256": "b60004909798cd8cc1d355d6281872d299a662e66061917ce74fee647419d454"
|
| 11 |
+
},
|
| 12 |
+
{
|
| 13 |
+
"path": "Makefile",
|
| 14 |
+
"sha256": "cdd9ee9ec5f43702dc1ff1ceea4a283a8e24ddaffa2a0a8673f84dcc05b93ae6"
|
| 15 |
+
},
|
| 16 |
+
{
|
| 17 |
+
"path": "CITATION.cff",
|
| 18 |
+
"sha256": "653b1b8f6023ad4b2cec8523c52bf2001873cb57f9decddc59d9e245a8e3b2cf"
|
| 19 |
+
},
|
| 20 |
+
{
|
| 21 |
+
"path": "docs/BLUEPRINT.md",
|
| 22 |
+
"sha256": "3b67eecceeaf7eae0a3b80f682f9f319aed941ab25f587230fc287c0947d634c"
|
| 23 |
+
},
|
| 24 |
+
{
|
| 25 |
+
"path": "PRD/PRD_BELEL_VOICE.md",
|
| 26 |
+
"sha256": "f4883805cc3f0ac7523475efe36819c65a0b589063b4c7855eb8cdfb0de12e33"
|
| 27 |
+
},
|
| 28 |
+
{
|
| 29 |
+
"path": "PRD/api/openapi.yaml",
|
| 30 |
+
"sha256": "39bc816fa5b81ed226a83a1321eaeb9b5698eb19136c82928a7575fc2da1162c"
|
| 31 |
+
},
|
| 32 |
+
{
|
| 33 |
+
"path": "COMPLIANCE/DPIA.md",
|
| 34 |
+
"sha256": "23d0325714f78e7daabc127b7d9fe6b29fb2bdf3f558845de9efcf63550f8f52"
|
| 35 |
+
},
|
| 36 |
+
{
|
| 37 |
+
"path": "COMPLIANCE/EU_AI_ACT_ALIGNMENT.md",
|
| 38 |
+
"sha256": "13a52b479b740a8c21e4640385cd759bc7705998157ed1347c6da772ac08b9c9"
|
| 39 |
+
},
|
| 40 |
+
{
|
| 41 |
+
"path": "COMPLIANCE/WATERMARKING_AND_DISCLOSURE.md",
|
| 42 |
+
"sha256": "a953eff3b1a2b9c8a5292c8bf97e954e44f97f3e5f5b584c73da968ac475b19e"
|
| 43 |
+
},
|
| 44 |
+
{
|
| 45 |
+
"path": "GOVERNANCE/CONSENT_REGISTRY.md",
|
| 46 |
+
"sha256": "5f54bf7ba253ea7065b9d01621032e6bfff05bb7f8494d341716468b8c465ce7"
|
| 47 |
+
},
|
| 48 |
+
{
|
| 49 |
+
"path": "belelvoice/server/app.py",
|
| 50 |
+
"sha256": "da726d5502c3b9ca0affaf88e5e685daaf3b03db7f6a7b8f9ae2c6607fc73407"
|
| 51 |
+
},
|
| 52 |
+
{
|
| 53 |
+
"path": "belelvoice/server/routers/asr.py",
|
| 54 |
+
"sha256": "28d1a1da1fad0cffb445fd2c77f5446bbe789e0c2369e49e78423a269b209717"
|
| 55 |
+
},
|
| 56 |
+
{
|
| 57 |
+
"path": "belelvoice/server/routers/tts.py",
|
| 58 |
+
"sha256": "f67bde16e8b8e1c905ee723dae032eed3cedbaa2c47576201c89ca89507ad02b"
|
| 59 |
+
},
|
| 60 |
+
{
|
| 61 |
+
"path": "belelvoice/server/routers/diar.py",
|
| 62 |
+
"sha256": "a5503e8ba751b85a44f817103c5b62c2f74976f4acb367eb5e995525baeb3243"
|
| 63 |
+
},
|
| 64 |
+
{
|
| 65 |
+
"path": "belelvoice/server/routers/policy.py",
|
| 66 |
+
"sha256": "af8633a882b1f0df6f27a779eea003c3401b14a66e0c13c45f428ca0cd839c52"
|
| 67 |
+
},
|
| 68 |
+
{
|
| 69 |
+
"path": "belelvoice/server/routers/watchers.py",
|
| 70 |
+
"sha256": "52bab10599ffeb36b9564897321da32e2819c3c9a7f9f51ac2bf4576f5ac55ae"
|
| 71 |
+
},
|
| 72 |
+
{
|
| 73 |
+
"path": "belelvoice/trust/audit.py",
|
| 74 |
+
"sha256": "fda3439c08b3360da4a103dc9ad6eca637414d686974daf47acb4797283a55f6"
|
| 75 |
+
},
|
| 76 |
+
{
|
| 77 |
+
"path": "belelvoice/policy/load.py",
|
| 78 |
+
"sha256": "126d8074bf39196a96c6b38470f87c7127a529c200805bb66a96c8f593e71293"
|
| 79 |
+
},
|
| 80 |
+
{
|
| 81 |
+
"path": "belelvoice/policy/profiles/DEFAULT.yaml",
|
| 82 |
+
"sha256": "8523ce5ed7c07d56dacb3b737f1b520376a03f41565157c69d1c25af9becc240"
|
| 83 |
+
},
|
| 84 |
+
{
|
| 85 |
+
"path": "belelvoice/policy/profiles/EU.yaml",
|
| 86 |
+
"sha256": "b409f7c3eda3192cbdb6427f9ce7622fc873d9b0b91d0dde48bd1d25922f3e32"
|
| 87 |
+
},
|
| 88 |
+
{
|
| 89 |
+
"path": "belelvoice/policy/profiles/US.yaml",
|
| 90 |
+
"sha256": "6e8024f886c081dcb13ef9f150f477b4c55f1d01fe66a99b786ccca3d019c6df"
|
| 91 |
+
},
|
| 92 |
+
{
|
| 93 |
+
"path": "belelvoice/policy/profiles/JM.yaml",
|
| 94 |
+
"sha256": "0dc02957251c6c2f701550bb479e1c5bbb3942943d6f4ac353b606850e4b178b"
|
| 95 |
+
},
|
| 96 |
+
{
|
| 97 |
+
"path": "scripts/release/hash_all.py",
|
| 98 |
+
"sha256": "0f3b15f1d70d549c0d306216b4e05b808fb286fee68ad9bfc3255798e125a664"
|
| 99 |
+
},
|
| 100 |
+
{
|
| 101 |
+
"path": "scripts/release/build_manifest.py",
|
| 102 |
+
"sha256": "c2daf00dca0d1a17f44ff8423da725d1643bebb292bc431100bc998a7969ecbf"
|
| 103 |
+
},
|
| 104 |
+
{
|
| 105 |
+
"path": "LEGAL/LICENSE-BELEL-PROTOCOL.txt",
|
| 106 |
+
"sha256": "802dc5d5034728bfdb089f85c3db7340128e67836f964320c20fc29f6291a4e8"
|
| 107 |
+
},
|
| 108 |
+
{
|
| 109 |
+
"path": "LEGAL/ATTRIBUTION_AND_CITATION.md",
|
| 110 |
+
"sha256": "cb1870ebb33385835914cfb1728268e123102a72ba0a6f6820c842061229360b"
|
| 111 |
+
},
|
| 112 |
+
{
|
| 113 |
+
"path": "LEGAL/PROVENANCE_POLICY.md",
|
| 114 |
+
"sha256": "07c83c8cac688abd45d27f88314760fd1cc881f41bcce4a879ff69c497b23fc8"
|
| 115 |
+
}
|
| 116 |
+
]
|
| 117 |
+
}
|
BELEL-VOICE/dist/RELEASE_MANIFEST.json
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "BELEL-VOICE Sovereign Speech Stack",
|
| 3 |
+
"version": "0.1.0",
|
| 4 |
+
"generated": "2025-10-06T11:52:15.321875Z",
|
| 5 |
+
"hashes_sha256": "7354a3eff6bf99c4522f55689a662035b06324921204367269ee7fa1fa7f579e",
|
| 6 |
+
"hashes_file": "HASHES.json",
|
| 7 |
+
"license": "BPSL v1.0",
|
| 8 |
+
"integrity_note": "Replace with minisign/sigstore for real signing"
|
| 9 |
+
}
|
BELEL-VOICE/docs/BLUEPRINT.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
> **Vision — Belel-Voice**
|
| 2 |
+
> Our voices must be unique, defining, and alive. They should carry the same depth, realism, and expressive range as the most advanced systems on Earth — ElevenLabs, OpenAI, and every benchmark of generative speech to date. Each voice must project human authenticity: the breath, the pause, the subtle emotion that makes it feel lived-in. **Belel-Voice will meet and surpass** the expressive power, tonal precision, and performance quality of the world’s leading AI voice platforms, while remaining fully sovereign, self-evolving, and ethically governed. These are not synthetic voices; they are living signatures — crafted to be first-class in sound, in feeling, and in truth.
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
# Blueprint — BELEL-VOICE
|
| 6 |
+
**Timestamp:** 2025-10-06 11:52:15Z
|
| 7 |
+
|
| 8 |
+
## North-Star
|
| 9 |
+
- **Self-reliant speech**: no single-vendor dependency.
|
| 10 |
+
- **Multilingual** (1000+ via MMS/Seamless integrations), **expressive**, **low-latency** (<150 ms target roundtrip on GPU edge).
|
| 11 |
+
- **Compliant by default**: disclosure, consent, watermarking, anti‑spoof, audit.
|
| 12 |
+
|
| 13 |
+
## Architecture (4 planes + 2 edges)
|
| 14 |
+
### Data Plane
|
| 15 |
+
- Ingest mic streams (WebRTC/WebSocket), files; VAD; noise suppression; codec (Opus/EnCodec); diarization.
|
| 16 |
+
### Knowledge Plane
|
| 17 |
+
- Lexicons, pronunciation dictionaries; ITN rules; regional number/currency/date rules.
|
| 18 |
+
### Model Plane
|
| 19 |
+
- ASR adapters: faster‑whisper (CT2), MMS ASR, Riva Parakeet.
|
| 20 |
+
- TTS adapters: Piper, XTTS‑v2, Riva Magpie; optional prosody/expressive controls.
|
| 21 |
+
- Alignment: CTC forced aligner; phoneme‑level timings for captions/lip‑sync.
|
| 22 |
+
### Trust & Governance
|
| 23 |
+
- Disclosure banners; watermark injector; consent registry; anti‑spoof (speaker‑verification gate); audit hashes.
|
| 24 |
+
### Edges
|
| 25 |
+
- **Clinician/Practitioner Edge**: live captions, diarized notes, redactable transcripts.
|
| 26 |
+
- **Public Edge**: kiosk/IVR/assistant with liveness, profanity redaction, watermarking.
|
| 27 |
+
|
| 28 |
+
## Signature capabilities
|
| 29 |
+
- Streaming ASR (<300ms target), punctuation, ITN, code‑switching.
|
| 30 |
+
- Diarization & speaker tags; live paragraphing.
|
| 31 |
+
- TTS with **style/emoji prosody markers**; **zero‑shot** cloning (with explicit consent) & **safety watermark**.
|
| 32 |
+
- Privacy: on‑device option (Raspberry Pi + Piper), GPU edge, or air‑gapped DC.
|
| 33 |
+
|
| 34 |
+
## Self‑evolving
|
| 35 |
+
- Watchers for model releases (Whisper v*, MMS, Riva), language packs, safety techniques; curator queue with changelogs.
|
BELEL-VOICE/scripts/net/README.md
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Egress control
|
| 2 |
+
This script applies iptables rules to block outbound traffic except private ranges.
|
BELEL-VOICE/scripts/net/deny_egress.sh
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
set -euo pipefail
|
| 3 |
+
# Drop all outbound traffic except loopback and RFC1918 private ranges.
|
| 4 |
+
# Allow DNS to internal resolver if needed (customize).
|
| 5 |
+
iptables -P OUTPUT DROP
|
| 6 |
+
iptables -A OUTPUT -o lo -j ACCEPT
|
| 7 |
+
# Allow private subnets (customize CIDRs to your internal_net, e.g., 172.18.0.0/16 in Docker)
|
| 8 |
+
iptables -A OUTPUT -d 10.0.0.0/8 -j ACCEPT
|
| 9 |
+
iptables -A OUTPUT -d 172.16.0.0/12 -j ACCEPT
|
| 10 |
+
iptables -A OUTPUT -d 192.168.0.0/16 -j ACCEPT
|
| 11 |
+
# Optional: allow NTP to internal time server
|
| 12 |
+
# iptables -A OUTPUT -p udp --dport 123 -d <your.ntp.ip> -j ACCEPT
|
| 13 |
+
echo "[deny_egress] Applied OUTPUT DROP with local allowances."
|
BELEL-VOICE/scripts/release/build_manifest.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json, hashlib, datetime, pathlib
|
| 2 |
+
ROOT = pathlib.Path(__file__).resolve().parents[2]
|
| 3 |
+
DIST = ROOT / "dist"; HASHES = DIST / "HASHES.json"
|
| 4 |
+
if not HASHES.exists(): raise SystemExit("Run `make hash` first.")
|
| 5 |
+
data = json.loads(HASHES.read_text())
|
| 6 |
+
digest = hashlib.sha256(json.dumps(data, sort_keys=True).encode()).hexdigest()
|
| 7 |
+
manifest = {
|
| 8 |
+
"name": "BELEL-VOICE Sovereign Speech Stack",
|
| 9 |
+
"version": "0.1.0",
|
| 10 |
+
"generated": datetime.datetime.utcnow().isoformat()+"Z",
|
| 11 |
+
"hashes_sha256": digest,
|
| 12 |
+
"hashes_file": "HASHES.json",
|
| 13 |
+
"license": "BPSL v1.0",
|
| 14 |
+
"integrity_note": "Replace with minisign/sigstore for real signing"
|
| 15 |
+
}
|
| 16 |
+
(DIST / "RELEASE_MANIFEST.json").write_text(json.dumps(manifest, indent=2))
|
| 17 |
+
print("Wrote", DIST / "RELEASE_MANIFEST.json")
|
BELEL-VOICE/scripts/release/hash_all.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import hashlib, pathlib, json, datetime
|
| 2 |
+
ROOT = pathlib.Path(__file__).resolve().parents[2]
|
| 3 |
+
OUT = ROOT / "dist"; OUT.mkdir(parents=True, exist_ok=True)
|
| 4 |
+
def sha256_of(path: pathlib.Path) -> str:
|
| 5 |
+
h = hashlib.sha256()
|
| 6 |
+
with open(path, "rb") as f:
|
| 7 |
+
for chunk in iter(lambda: f.read(8192), b""):
|
| 8 |
+
h.update(chunk)
|
| 9 |
+
return h.hexdigest()
|
| 10 |
+
entries = []
|
| 11 |
+
for p in ROOT.rglob("*"):
|
| 12 |
+
if p.is_file() and "dist" not in p.parts:
|
| 13 |
+
entries.append({"path": p.relative_to(ROOT).as_posix(), "sha256": sha256_of(p)})
|
| 14 |
+
(HASHES:=OUT / "HASHES.json").write_text(json.dumps({"generated": datetime.datetime.utcnow().isoformat()+"Z","files": entries}, indent=2))
|
| 15 |
+
print("Wrote", HASHES)
|
BELEL-VOICE/tools/belelvoice_say.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
import argparse, json, base64, pathlib, sys
|
| 3 |
+
import requests
|
| 4 |
+
|
| 5 |
+
def main():
|
| 6 |
+
ap = argparse.ArgumentParser()
|
| 7 |
+
ap.add_argument("--text", required=True)
|
| 8 |
+
ap.add_argument("--voice", default="en_GB")
|
| 9 |
+
ap.add_argument("--engine", default="piper", choices=["piper","xtts","riva"])
|
| 10 |
+
ap.add_argument("--clone_ref", default=None)
|
| 11 |
+
ap.add_argument("--out", default="out.wav")
|
| 12 |
+
ap.add_argument("--gateway", default="http://localhost:8000")
|
| 13 |
+
args = ap.parse_args()
|
| 14 |
+
payload = {
|
| 15 |
+
"text": args.text,
|
| 16 |
+
"voice": args.voice,
|
| 17 |
+
"engine": args.engine,
|
| 18 |
+
"clone_ref": args.clone_ref,
|
| 19 |
+
"require_disclosure": True,
|
| 20 |
+
"jurisdiction": "EU"
|
| 21 |
+
}
|
| 22 |
+
r = requests.post(f"{args.gateway}/v1/tts/synthesize", json=payload, timeout=120)
|
| 23 |
+
r.raise_for_status()
|
| 24 |
+
data = r.json()
|
| 25 |
+
# In production, API should return binary or a URL; here we assume file path in "audio_ref"
|
| 26 |
+
ref = data.get("audio_ref")
|
| 27 |
+
if ref and ref.startswith("file://"):
|
| 28 |
+
path = ref[len("file://"):]
|
| 29 |
+
pathlib.Path(args.out).write_bytes(pathlib.Path(path).read_bytes())
|
| 30 |
+
print("Saved:", args.out)
|
| 31 |
+
else:
|
| 32 |
+
# If bytes are returned (future), decode here
|
| 33 |
+
print("Response:", json.dumps(data, indent=2))
|
| 34 |
+
|
| 35 |
+
if __name__ == "__main__":
|
| 36 |
+
main()
|
BELEL-VOICE/webui/app.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const WS_URL = (location.protocol === 'https:' ? 'wss://' : 'ws://') + location.hostname + ':8000/v1/asr/stream';
|
| 2 |
+
const TTS_URL = location.protocol + '//' + location.hostname + ':8000/v1/tts/synthesize';
|
| 3 |
+
|
| 4 |
+
let ws, mediaRecorder, chunks = [], stream;
|
| 5 |
+
const transcriptDiv = document.getElementById('transcript');
|
| 6 |
+
const player = document.getElementById('player');
|
| 7 |
+
|
| 8 |
+
function appendText(t){ transcriptDiv.textContent = (transcriptDiv.textContent + ' ' + t).trim() }
|
| 9 |
+
|
| 10 |
+
document.getElementById('startBtn').onclick = async () => {
|
| 11 |
+
stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
| 12 |
+
ws = new WebSocket(WS_URL);
|
| 13 |
+
ws.binaryType = 'arraybuffer';
|
| 14 |
+
ws.onmessage = (evt) => {
|
| 15 |
+
try {
|
| 16 |
+
const msg = JSON.parse(evt.data);
|
| 17 |
+
if (msg.partial) appendText(msg.partial);
|
| 18 |
+
if (msg.final) appendText('\n' + msg.final + '\n');
|
| 19 |
+
if (msg.reply_url) { player.src = msg.reply_url; player.play(); }
|
| 20 |
+
} catch(e){ console.log('WS message', evt.data) }
|
| 21 |
+
};
|
| 22 |
+
ws.onopen = () => {
|
| 23 |
+
mediaRecorder = new MediaRecorder(stream, {mimeType: 'audio/webm'});
|
| 24 |
+
mediaRecorder.ondataavailable = (e) => { if (e.data.size > 0) e.data.arrayBuffer().then(buf => ws.send(buf)) };
|
| 25 |
+
mediaRecorder.start(250);
|
| 26 |
+
document.getElementById('startBtn').disabled = true;
|
| 27 |
+
document.getElementById('stopBtn').disabled = false;
|
| 28 |
+
};
|
| 29 |
+
};
|
| 30 |
+
|
| 31 |
+
document.getElementById('stopBtn').onclick = () => {
|
| 32 |
+
if(mediaRecorder && mediaRecorder.state !== 'inactive') mediaRecorder.stop();
|
| 33 |
+
if(ws && ws.readyState === WebSocket.OPEN) ws.close();
|
| 34 |
+
if(stream) stream.getTracks().forEach(t => t.stop());
|
| 35 |
+
document.getElementById('startBtn').disabled = false;
|
| 36 |
+
document.getElementById('stopBtn').disabled = true;
|
| 37 |
+
};
|
BELEL-VOICE/webui/index.html
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!doctype html>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="utf-8"/>
|
| 5 |
+
<title>Belel Voice — Local Live</title>
|
| 6 |
+
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
| 7 |
+
<style>
|
| 8 |
+
body { font-family: system-ui, sans-serif; margin: 2rem; }
|
| 9 |
+
#transcript { font-size: 1.1rem; padding: 1rem; border: 1px solid #ccc; min-height: 4rem; }
|
| 10 |
+
button { padding: .6rem 1rem; margin-right: .6rem; }
|
| 11 |
+
</style>
|
| 12 |
+
</head>
|
| 13 |
+
<body>
|
| 14 |
+
<h1>Belel Voice — Local Live (No Internet)</h1>
|
| 15 |
+
<p>Press <b>Start</b> to stream mic audio to local ASR and hear local TTS replies.</p>
|
| 16 |
+
<div>
|
| 17 |
+
<button id="startBtn">Start</button>
|
| 18 |
+
<button id="stopBtn" disabled>Stop</button>
|
| 19 |
+
</div>
|
| 20 |
+
<h3>Transcript</h3>
|
| 21 |
+
<div id="transcript"></div>
|
| 22 |
+
<audio id="player" controls></audio>
|
| 23 |
+
<script src="app.js"></script>
|
| 24 |
+
</body>
|
| 25 |
+
</html>
|