Compare commits

...

3 Commits

Author SHA1 Message Date
ALIHAN DIKEL
07289cd408 update reqs.txt 2025-04-14 00:13:19 +03:00
ALIHAN DIKEL
4e580bae89 converted to mcp server 2025-04-14 00:12:35 +03:00
ALIHAN DIKEL
af4be8fddd claude committed this 2025-04-13 22:41:33 +03:00
2 changed files with 146 additions and 30 deletions

View File

@@ -1,10 +1,80 @@
uvicorn[standard]
librosa
openai-whisper
torch
loguru
fastapi
python-multipart
jinja2
pillow
python-dotenv
annotated-types==0.7.0
anyio==4.8.0
audioread==3.0.1
certifi==2025.1.31
cffi==1.17.1
charset-normalizer==3.4.1
click==8.1.8
decorator==5.2.1
fastapi==0.115.11
fastapi-mcp==0.2.0
ffmpeg-python==0.2.0
filelock==3.17.0
fsspec==2025.3.0
future==1.0.0
h11==0.14.0
httpcore==1.0.8
httptools==0.6.4
httpx==0.28.1
httpx-sse==0.4.0
huggingface-hub==0.29.2
idna==3.10
Jinja2==3.1.6
joblib==1.4.2
lazy_loader==0.4
librosa==0.10.2.post1
llvmlite==0.44.0
loguru==0.7.3
markdown-it-py==3.0.0
MarkupSafe==3.0.2
mcp==1.6.0
mcp-proxy==0.5.1
mdurl==0.1.2
more-itertools==10.6.0
mpmath==1.3.0
msgpack==1.1.0
networkx==3.4.2
numba==0.61.0
numpy==2.1.3
packaging==24.2
pillow==11.1.0
platformdirs==4.3.6
pooch==1.8.2
pycparser==2.22
pydantic==2.10.6
pydantic-settings==2.8.1
pydantic_core==2.27.2
Pygments==2.19.1
python-dotenv==1.0.1
python-multipart==0.0.20
PyYAML==6.0.2
regex==2024.11.6
requests==2.32.3
rich==14.0.0
safetensors==0.5.3
scikit-learn==1.6.1
scipy==1.15.2
setuptools==75.8.0
shellingham==1.5.4
sniffio==1.3.1
soundfile==0.13.1
soxr==0.5.0.post1
sse-starlette==2.2.1
starlette==0.46.1
sympy==1.13.1
threadpoolctl==3.5.0
tokenizers==0.21.0
tomli==2.2.1
torch==2.6.0
tqdm==4.67.1
transformers==4.49.0
typer==0.15.2
typing_extensions==4.12.2
urllib3==2.3.0
uvicorn==0.34.0
uvloop==0.21.0
watchfiles==1.0.4
websockets==15.0.1
wheel==0.45.1
whisper-openai==1.0.0
yt-dlp==2025.2.19

View File

@@ -1,9 +1,11 @@
import asyncio
import os
import shutil
import json
from contextlib import asynccontextmanager
from typing import List
from fastapi_mcp import FastApiMCP
from fastapi import FastAPI, UploadFile, File, HTTPException, Request, WebSocket, WebSocketDisconnect, Form
from fastapi.responses import HTMLResponse, JSONResponse, StreamingResponse
from fastapi.staticfiles import StaticFiles
@@ -29,8 +31,18 @@ async def lifespan(app: FastAPI):
app = FastAPI(title="Transcriptor", lifespan=lifespan)
mcp = FastApiMCP(app,
name="agent-transcriptor",
description="user uploads audio files (in mp3 format) and transcriptor uses AI STT model to transcribe text from files",
base_url=os.environ["MCP_BASE_URL"],
exclude_operations=["get_upload_page"],
describe_all_responses=True,
describe_full_response_schema=True,
)
active_connections = []
mcp.mount()
app.mount("/static", StaticFiles(directory=STATIC_DIR), name="static")
templates = Jinja2Templates(directory=TEMPLATES_DIR)
@@ -39,19 +51,23 @@ def is_valid_file(filename: str) -> bool:
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@app.get("/", response_class=HTMLResponse)
@app.get("/", response_class=HTMLResponse, operation_id="get_upload_page")
async def get_upload_page(request: Request):
"""Serve the HTML frontend"""
return templates.TemplateResponse("index.html", {"request": request})
@app.post("/upload")
@app.post("/upload", operation_id="upload_single_audio_file")
async def upload_file(file: UploadFile = File(...)):
"""
API endpoint to handle file uploads
- Validates that the file is mp3 or wav
- Saves it to the local filesystem
- Checks for duplicate filenames
Upload a single MP3/WAV audio file.
Example curl command:
curl -X 'POST' \
'http://0.0.0.0:33754/upload' \
-H 'accept: application/json' \
-H 'Content-Type: multipart/form-data' \
-F 'file=@How To Parallel Charge LiPo Batteries Without Burning Down Your House.mp3;type=audio/mpeg'
"""
# Validate file extension
if not is_valid_file(file.filename):
@@ -75,12 +91,15 @@ async def upload_file(file: UploadFile = File(...)):
return {"filename": file.filename, "saved_path": str(file_path), "status": "success"}
@app.post("/upload-multiple")
@app.post("/upload-multiple", operation_id="upload_multiple_audio_files")
async def upload_multiple_files(files: List[UploadFile] = File(...)):
"""
API endpoint to handle multiple file uploads
- Processes each file individually
- Returns a summary of the upload results
Upload multiple audio files simultaneously.
Parameters:
- files: List of audio files (required)
Returns: Summary of upload results for each file
"""
results = []
@@ -137,10 +156,15 @@ async def upload_multiple_files(files: List[UploadFile] = File(...)):
return summary
@app.post("/process-multiple")
@app.post("/process-multiple", operation_id="transcribe_multiple_files_in_batch")
async def process_multiple_files(filenames: List[str] = Form(...)):
"""
API endpoint to process multiple files at once
Batch transcribe multiple audio files by filename.
Parameters:
- filenames: List of audio file names to process
Returns: Batch transcription results
"""
results = []
@@ -193,7 +217,12 @@ async def process_multiple_files(filenames: List[str] = Form(...)):
def get_file_list():
"""Helper function to get file list with metadata and status"""
"""
Retrieve audio files with metadata and processing status.
Returns: List of file objects containing name, size, creation time,
processing status, and transcript availability
"""
files = []
for file_path in UPLOAD_DIR.iterdir():
if file_path.is_file() and file_path.name != '.gitkeep': # Skip .gitkeep file
@@ -218,15 +247,28 @@ def get_file_list():
return files
@app.get("/files")
@app.get("/files", operation_id="list_uploaded_files")
async def list_files():
"""API endpoint to list all uploaded files"""
"""
Retrieve list of all uploaded audio files with metadata.
Returns: Object containing files array with status information
"""
return {"files": get_file_list()}
@app.post("/process/{filename}")
@app.post("/process/{filename}", operation_id="transcribe_single_file")
async def process_file(filename: str):
"""API endpoint to manually trigger file processing"""
"""
Transcribe a single audio file by filename.
Parameters:
- filename: Name of the audio file to process
Returns: Processing status information
Raises: 404 (file not found), 500 (processing failed)
"""
file_path = UPLOAD_DIR / filename
# Check if file exists
@@ -244,10 +286,14 @@ async def process_file(filename: str):
return {"filename": filename, "status": "processing_started"}
@app.get("/download-transcripts")
@app.get("/download-transcripts", operation_id="download_all_transcripts")
async def download_transcripts():
"""
API endpoint to download all transcript files as a single ZIP
Download all available transcripts as a ZIP archive.
Returns: ZIP file stream containing all transcript files
Raises: 404 (no transcripts available)
"""
# Check if there are any transcripts
transcript_files = list(TRANSCRIPT_DIR.glob("*.txt"))
@@ -307,4 +353,4 @@ async def broadcast_file_list():
logger.error(f"Error broadcasting to a client: {e}")
# Run with: uvicorn src.main:app --reload
mcp.setup_server()