commit 0255257a1ad41a2f7743709f82cfad07f9de19c7 Author: SFirouzi Date: Mon Nov 17 14:15:20 2025 +0330 add all diff --git a/.env b/.env new file mode 100644 index 0000000..b6baa37 --- /dev/null +++ b/.env @@ -0,0 +1 @@ +TRITON_URL=192.168.130.14:3089 \ No newline at end of file diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..0d73df4 --- /dev/null +++ b/.env.example @@ -0,0 +1 @@ +TRITON_URL=**** \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6eec66c --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/data +.venv +__pycache__ \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..6d8068a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,23 @@ +FROM python:3.12-slim + +# Set environment variables +ENV DEBIAN_FRONTEND=noninteractive \ + PYTHONUNBUFFERED=1 \ + PYTHONDONTWRITEBYTECODE=1 + +# Copy requirements file +COPY requirements.txt /app/requirements.txt + +# Install requirements +RUN pip install --no-deps git+https://git.d.aiengines.ir/bi/asr_triton_client.git@05c8f7a88d3ff41d82591b6beb41bab86d81d421 +RUN pip install --no-cache-dir -r /app/requirements.txt + +# Set working directory and copy app +WORKDIR /app +COPY . /app + +# Expose necessary ports +EXPOSE 8000 + +# Command to run the script +CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"] \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..c89f1d9 --- /dev/null +++ b/README.md @@ -0,0 +1,27 @@ +## ASR SERVICE + +### A FASTAPI client for receieving audio data from font and sending audio to a Triton ASR service using SSE or WebSocket streaming. It yields real-time transcription results as JSON-like events. + + +## How to run + +### SET ENVIRONMENT + + 1-create a file .env and set TRITON_URL + +### 1-DEVELOPMENT +#### Run the system : Uvicorn and Fastapi + .venv/bin/uvicorn src.main:app --host 0.0.0.0 --port 8000 + +### 2-DEPLOYMENT +#### Docker Build + docker build -t asr_client:latest --build-arg DEBIAN_FRONTEND=noninteractive . + + +#### Docker Run + docker run -d --gpus all --network host --restart unless-stopped asr_client:latest + + + +there was a problem in installing ast_client package : + pip couldnot find a versaion for perf-analyzer==2.59.1 : so i removed it \ No newline at end of file diff --git a/config/base.py b/config/base.py new file mode 100644 index 0000000..064e601 --- /dev/null +++ b/config/base.py @@ -0,0 +1,7 @@ +from dotenv import load_dotenv +import os + +load_dotenv() + +TRITON_URL = os.getenv("TRITON_URL") +MIN_CHUNK_SIZE = 90000 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..cf942c1 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,30 @@ +fastapi==0.116.1 +uvicorn==0.35.0 +aiohappyeyeballs==2.6.1 +aiohttp==3.13.0 +aiosignal==1.4.0 +async-timeout==5.0.1 +attrs==25.4.0 +Brotli==1.1.0 +certifi==2025.10.5 +frozenlist==1.8.0 +gevent==25.9.1 +geventhttpclient==2.3.4 +greenlet==3.2.4 +grpcio==1.67.1 +idna==3.11 +multidict==6.7.0 +numpy==2.2.6 +packaging==25.0 +propcache==0.4.1 +protobuf==5.29.5 +pydub==0.25.1 +python-dotenv==1.1.1 +python-rapidjson==1.21 +tritonclient==2.61.0 +typing_extensions==4.15.0 +urllib3==2.5.0 +websockets==15.0.1 +yarl==1.22.0 +zope.event==6.0 +zope.interface==8.0.1 \ No newline at end of file diff --git a/src/main.py b/src/main.py new file mode 100644 index 0000000..73285ef --- /dev/null +++ b/src/main.py @@ -0,0 +1,30 @@ +from fastapi import FastAPI, WebSocket +import asyncio +from asr.service import TritonGrpcClient +import json + +from config.base import TRITON_URL, MIN_CHUNK_SIZE + + +app = FastAPI() +client = TritonGrpcClient(TRITON_URL) + + +@app.websocket("/asr") +async def websocket_endpoint(ws: WebSocket): + print("Starting ASR service") + await ws.accept() + + audio_buffer = bytearray() + + try: + while True: + data = await ws.receive_bytes() + audio_buffer.extend(data) + + async for s in client.event_stream_from_bytes(raw=bytes(audio_buffer), filename="stream.webm"): + await ws.send_text(json.dumps(s, ensure_ascii=False)) + + except Exception as e: + print("WebSocket error:", e) + await ws.close() diff --git a/test/test.js b/test/test.js new file mode 100644 index 0000000..531cd08 --- /dev/null +++ b/test/test.js @@ -0,0 +1,16 @@ +const ws = new WebSocket("ws://localhost:8000/asr"); + +ws.onmessage = (event) => { + console.log("ASR Result:", event.data); +}; + +async function startStreaming() { + const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); + const recorder = new MediaRecorder(stream, { mimeType: "audio/webm" }); + + recorder.ondataavailable = (event) => { + ws.send(event.data); // send audio chunks to backend + }; + + recorder.start(500); // send audio every 250 ms +} diff --git a/test/test.py b/test/test.py new file mode 100644 index 0000000..61e216b --- /dev/null +++ b/test/test.py @@ -0,0 +1,27 @@ +import asyncio +import websockets +import json + +AUDIO_FILE = "./khabar_1_5.wav" # Replace with your audio file path +WS_URL = "ws://127.0.0.1:8000/asr" + +async def send_audio(): + async with websockets.connect(WS_URL) as ws: + print("Connected to ASR WebSocket") + + # Read the audio file in chunks + with open(AUDIO_FILE, "rb") as f: + chunk_size = 21920 + while chunk := f.read(chunk_size): + await ws.send(chunk) + + try: + while True: + message = await ws.recv() + data = json.loads(message) + print("Received:", data) + except websockets.exceptions.ConnectionClosed: + print("WebSocket closed by server") + +# Run the async client +asyncio.run(send_audio())