Move all sensitive data to .env: API keys, IPs, URLs. Add example.env and .gitignore
This commit is contained in:
@@ -0,0 +1,4 @@
|
|||||||
|
.env
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
.dockerenv
|
||||||
@@ -3,6 +3,8 @@
|
|||||||
Smart STT Pipeline v3
|
Smart STT Pipeline v3
|
||||||
T-one (fast) + GigaAM (accurate) + Qwen3.5-4B (punctuation)
|
T-one (fast) + GigaAM (accurate) + Qwen3.5-4B (punctuation)
|
||||||
Auto-selects best STT based on confidence/silence detection.
|
Auto-selects best STT based on confidence/silence detection.
|
||||||
|
|
||||||
|
Configuration: all sensitive data loaded from .env file.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
@@ -10,22 +12,25 @@ import tempfile
|
|||||||
import time
|
import time
|
||||||
import subprocess
|
import subprocess
|
||||||
import re
|
import re
|
||||||
import json
|
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
from fastapi import FastAPI, File, UploadFile, HTTPException
|
from fastapi import FastAPI, File, UploadFile, HTTPException
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
# === Configuration ===
|
# Load .env (skip if not found)
|
||||||
TONE_URL = "http://localhost:8003/transcribe"
|
load_dotenv()
|
||||||
GIGAAM_URL = "http://localhost:8001/transcribe"
|
|
||||||
QWEN_URL = "http://178.17.143.46:8080/v1/chat/completions"
|
# === Configuration from .env ===
|
||||||
QWEN_URL_FALLBACK = "http://192.168.10.101:8888/v1/chat/completions"
|
TONE_URL = os.getenv("TONE_URL", "http://localhost:8003/transcribe")
|
||||||
QWEN_API_KEY = "f9LHodD0cOIaku1zu7i7vh9KZsb5EelGK4K85k1tJWgzablcQrFw-QNIJaEHHwMb3LZ5k1nd-CKYiYY0F5Yw"
|
GIGAAM_URL = os.getenv("GIGAAM_URL", "http://localhost:8001/transcribe")
|
||||||
QWEN_MODEL = "Qwen3.5-4B-Q5_K_M.gguf"
|
QWEN_URL = os.getenv("QWEN_URL", "http://178.17.143.46:8080/v1/chat/completions")
|
||||||
QWEN_MODEL_FALLBACK = "Qwen3.5-4B-MTP-GGUF"
|
QWEN_URL_FALLBACK = os.getenv("QWEN_URL_FALLBACK", "http://192.168.10.101:8888/v1/chat/completions")
|
||||||
MIN_TEXT_LENGTH = 5 # Minimum chars to consider T-one result valid
|
QWEN_API_KEY = os.getenv("QWEN_API_KEY", "")
|
||||||
SHORT_AUDIO_THRESHOLD = 10 # Seconds: if audio < this, always use GigaAM
|
QWEN_MODEL = os.getenv("QWEN_MODEL", "Qwen3.5-4B-Q5_K_M.gguf")
|
||||||
|
QWEN_MODEL_FALLBACK = os.getenv("QWEN_MODEL_FALLBACK", "Qwen3.5-4B-MTP-GGUF")
|
||||||
|
MIN_TEXT_LENGTH = int(os.getenv("MIN_TEXT_LENGTH", "5"))
|
||||||
|
SHORT_AUDIO_THRESHOLD = int(os.getenv("SHORT_AUDIO_THRESHOLD", "10"))
|
||||||
|
|
||||||
app = FastAPI(title="Smart STT Pipeline v3", version="3.0.0")
|
app = FastAPI(title="Smart STT Pipeline v3", version="3.0.0")
|
||||||
|
|
||||||
@@ -37,7 +42,7 @@ class STTResponse(BaseModel):
|
|||||||
stt_time_sec: float
|
stt_time_sec: float
|
||||||
punct_time_sec: float
|
punct_time_sec: float
|
||||||
server_used: str
|
server_used: str
|
||||||
stt_engine: str # "t-one", "gigaam", or "both"
|
stt_engine: str # "t-one" or "gigaam"
|
||||||
|
|
||||||
|
|
||||||
def convert_to_wav(audio_bytes: bytes) -> str:
|
def convert_to_wav(audio_bytes: bytes) -> str:
|
||||||
@@ -61,14 +66,14 @@ def transcribe_tone(wav_path: str) -> dict:
|
|||||||
data = resp.json()
|
data = resp.json()
|
||||||
if "detail" in data:
|
if "detail" in data:
|
||||||
return {"text": "", "valid": False, "error": data["detail"]}
|
return {"text": "", "valid": False, "error": data["detail"]}
|
||||||
|
|
||||||
text = data.get("text", "[]")
|
text = data.get("text", "[]")
|
||||||
phrases = re.findall(r"TextPhrase\(text='([^']*)'", text)
|
phrases = re.findall(r"TextPhrase\(text='([^']*)'", text)
|
||||||
result_text = " ".join(phrases)
|
result_text = " ".join(phrases)
|
||||||
|
|
||||||
# Check if result is meaningful
|
# Check if result is meaningful
|
||||||
valid = len(result_text.strip()) >= MIN_TEXT_LENGTH
|
valid = len(result_text.strip()) >= MIN_TEXT_LENGTH
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"text": result_text,
|
"text": result_text,
|
||||||
"valid": valid,
|
"valid": valid,
|
||||||
@@ -111,25 +116,25 @@ def add_punctuation(text: str, server_url: str, api_key: str, model: str) -> str
|
|||||||
async def transcribe(file: UploadFile = File(...)):
|
async def transcribe(file: UploadFile = File(...)):
|
||||||
"""Smart transcription: T-one first, fallback to GigaAM if needed"""
|
"""Smart transcription: T-one first, fallback to GigaAM if needed"""
|
||||||
audio_bytes = await file.read()
|
audio_bytes = await file.read()
|
||||||
|
|
||||||
# Get audio duration from file
|
# Get audio duration from file
|
||||||
ogg_path = tempfile.mktemp(suffix=".ogg")
|
ogg_path = tempfile.mktemp(suffix=".ogg")
|
||||||
with open(ogg_path, "wb") as f:
|
with open(ogg_path, "wb") as f:
|
||||||
f.write(audio_bytes)
|
f.write(audio_bytes)
|
||||||
|
|
||||||
cmd = ["ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", ogg_path]
|
cmd = ["ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", ogg_path]
|
||||||
proc = subprocess.run(cmd, capture_output=True, text=True)
|
proc = subprocess.run(cmd, capture_output=True, text=True)
|
||||||
duration = float(proc.stdout.strip())
|
duration = float(proc.stdout.strip())
|
||||||
|
|
||||||
# Convert to WAV for T-one
|
# Convert to WAV for T-one
|
||||||
wav_path = convert_to_wav(audio_bytes)
|
wav_path = convert_to_wav(audio_bytes)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Step 1: Choose STT engine based on duration
|
# Step 1: Choose STT engine based on duration
|
||||||
if duration < SHORT_AUDIO_THRESHOLD:
|
if duration < SHORT_AUDIO_THRESHOLD:
|
||||||
# Short audio: use GigaAM (more accurate)
|
# Short audio: use GigaAM (more accurate)
|
||||||
giga_result = transcribe_gigaam(ogg_path)
|
giga_result = transcribe_gigaam(ogg_path)
|
||||||
|
|
||||||
text = giga_result.get("original", "")
|
text = giga_result.get("original", "")
|
||||||
stt_engine = "gigaam"
|
stt_engine = "gigaam"
|
||||||
stt_time = giga_result.get("stt_time_sec", 0)
|
stt_time = giga_result.get("stt_time_sec", 0)
|
||||||
@@ -138,7 +143,7 @@ async def transcribe(file: UploadFile = File(...)):
|
|||||||
stt_start = time.time()
|
stt_start = time.time()
|
||||||
tone_result = transcribe_tone(wav_path)
|
tone_result = transcribe_tone(wav_path)
|
||||||
stt_time = time.time() - stt_start
|
stt_time = time.time() - stt_start
|
||||||
|
|
||||||
if tone_result["valid"]:
|
if tone_result["valid"]:
|
||||||
text = tone_result["text"]
|
text = tone_result["text"]
|
||||||
stt_engine = "t-one"
|
stt_engine = "t-one"
|
||||||
@@ -148,7 +153,7 @@ async def transcribe(file: UploadFile = File(...)):
|
|||||||
text = giga_result.get("original", "")
|
text = giga_result.get("original", "")
|
||||||
stt_engine = "gigaam"
|
stt_engine = "gigaam"
|
||||||
stt_time = giga_result.get("stt_time_sec", 0)
|
stt_time = giga_result.get("stt_time_sec", 0)
|
||||||
|
|
||||||
# Step 2: Punctuation
|
# Step 2: Punctuation
|
||||||
punct_start = time.time()
|
punct_start = time.time()
|
||||||
server_used = "178.17.143.46:8080"
|
server_used = "178.17.143.46:8080"
|
||||||
@@ -158,7 +163,7 @@ async def transcribe(file: UploadFile = File(...)):
|
|||||||
server_used = "192.168.10.101:8888"
|
server_used = "192.168.10.101:8888"
|
||||||
punctuated = add_punctuation(text, QWEN_URL_FALLBACK, QWEN_API_KEY, QWEN_MODEL_FALLBACK)
|
punctuated = add_punctuation(text, QWEN_URL_FALLBACK, QWEN_API_KEY, QWEN_MODEL_FALLBACK)
|
||||||
punct_time = time.time() - punct_start
|
punct_time = time.time() - punct_start
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"original": text,
|
"original": text,
|
||||||
"punctuated": punctuated,
|
"punctuated": punctuated,
|
||||||
|
|||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
# T-one STT Service
|
||||||
|
TONE_URL=http://localhost:8003/transcribe
|
||||||
|
|
||||||
|
# GigaAM STT Service
|
||||||
|
GIGAAM_URL=http://localhost:8001/transcribe
|
||||||
|
|
||||||
|
# Qwen3.5-4B Punctuation Service
|
||||||
|
QWEN_URL=http://178.17.143.46:8080/v1/chat/completions
|
||||||
|
QWEN_URL_FALLBACK=http://192.168.10.101:8888/v1/chat/completions
|
||||||
|
QWEN_API_KEY=your_qwen_api_key_here
|
||||||
|
QWEN_MODEL=Qwen3.5-4B-Q5_K_M.gguf
|
||||||
|
QWEN_MODEL_FALLBACK=Qwen3.5-4B-MTP-GGUF
|
||||||
|
|
||||||
|
# Smart Routing Configuration
|
||||||
|
MIN_TEXT_LENGTH=5
|
||||||
|
SHORT_AUDIO_THRESHOLD=10
|
||||||
@@ -2,3 +2,4 @@ fastapi==0.115.0
|
|||||||
uvicorn==0.32.0
|
uvicorn==0.32.0
|
||||||
python-multipart==0.0.12
|
python-multipart==0.0.12
|
||||||
requests==2.34.2
|
requests==2.34.2
|
||||||
|
python-dotenv==1.0.1
|
||||||
|
|||||||
Reference in New Issue
Block a user