anshcode1's picture
download
raw
8.75 kB
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "852385a9-bc7f-419e-8523-e3fa2c653166",
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import torch\n",
"import tempfile\n",
"import torchaudio\n",
"import librosa\n",
"from pydub import AudioSegment\n",
"from flask import Flask, request, jsonify\n",
"from flask_cors import CORS\n",
"from pyngrok import ngrok\n",
"from transformers import WhisperProcessor, WhisperForConditionalGeneration\n",
"from werkzeug.utils import secure_filename\n",
"from googletrans import Translator\n",
"from huggingface_hub import login\n",
"import logging\n",
"import time\n",
"\n",
"# ---------------- CONFIG ----------------\n",
"MODEL_NAME = \"openai/whisper-medium\"\n",
"MODEL_PATH = \"best_model.pt\"\n",
"UPLOAD_FOLDER = \"uploads\"\n",
"HF_TOKEN = \"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\" # <---- Your token\n",
"NGROK_TOKEN = \"2w81ifj5xPmsRpAON5rvg4OlVxY_49NCKqCvAAgrJ2b8coFft\" # <---- Your token\n",
"\n",
"os.makedirs(UPLOAD_FOLDER, exist_ok=True)\n",
"\n",
"# ----- LOGGING -----\n",
"logging.basicConfig(level=logging.INFO)\n",
"logger = logging.getLogger(__name__)\n",
"\n",
"# ----- AUTH -----\n",
"login(HF_TOKEN)\n",
"\n",
"# ----- LOAD MODEL -----\n",
"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
"logger.info(f\"Using device: {device}\")\n",
"\n",
"if device.type == \"cuda\":\n",
" torch.backends.cudnn.benchmark = True\n",
" os.environ[\"CUBLAS_WORKSPACE_CONFIG\"] = \":4096:8\"\n",
"\n",
"processor = WhisperProcessor.from_pretrained(\n",
" MODEL_NAME, use_auth_token=True, language=\"pashto\"\n",
")\n",
"agri_tokens = [\"ګیدړه\", \"باغونه\", \"کانال\", \"زراعت\", \"مالداری\"]\n",
"processor.tokenizer.add_tokens(agri_tokens)\n",
"\n",
"model = WhisperForConditionalGeneration.from_pretrained(\n",
" MODEL_NAME, use_auth_token=True\n",
")\n",
"model.resize_token_embeddings(len(processor.tokenizer))\n",
"model.load_state_dict(torch.load(MODEL_PATH, map_location=device))\n",
"model.to(device).eval()\n",
"\n",
"translator = Translator()\n",
"\n",
"# ----- FLASK SETUP -----\n",
"app = Flask(__name__)\n",
"CORS(app)\n",
"app.config[\"UPLOAD_FOLDER\"] = UPLOAD_FOLDER\n",
"app.config[\"MAX_CONTENT_LENGTH\"] = 10 * 1024 * 1024 # 10MB limit\n",
"\n",
"# ----- AUDIO PROCESSING -----\n",
"def convert_to_wav(path_in: str) -> str:\n",
" \"\"\"\n",
" Convert any audio file to 16kHz mono WAV using:\n",
" 1) TorchAudio\n",
" 2) Pydub/FFmpeg\n",
" 3) Librosa\n",
" \"\"\"\n",
" # 1) Try TorchAudio on the original file\n",
" try:\n",
" waveform, sample_rate = torchaudio.load(path_in)\n",
" logger.info(f\"Loaded with TorchAudio: {path_in}\")\n",
" except Exception as e:\n",
" logger.warning(f\"TorchAudio failed ({e}), trying Pydub/FFmpeg\")\n",
" # 2) Pydub fallback\n",
" try:\n",
" audio = AudioSegment.from_file(path_in)\n",
" audio = audio.set_frame_rate(16000).set_channels(1)\n",
" tmp = tempfile.NamedTemporaryFile(delete=False, suffix=\".wav\")\n",
" audio.export(\n",
" tmp.name,\n",
" format=\"wav\",\n",
" parameters=[\"-acodec\", \"pcm_s16le\"]\n",
" )\n",
" logger.info(f\"Pydub-converted audio saved to: {tmp.name}\")\n",
" return tmp.name\n",
" except Exception as e2:\n",
" logger.warning(f\"Pydub failed ({e2}), falling back to Librosa\")\n",
" # 3) Librosa fallback\n",
" y, sample_rate = librosa.load(path_in, sr=16000)\n",
" waveform = torch.from_numpy(y).unsqueeze(0)\n",
"\n",
" else:\n",
" # Resample & mono mix if TorchAudio succeeded\n",
" if sample_rate != 16000:\n",
" resampler = torchaudio.transforms.Resample(\n",
" orig_freq=sample_rate,\n",
" new_freq=16000\n",
" )\n",
" waveform = resampler(waveform)\n",
" if waveform.shape[0] > 1:\n",
" waveform = torch.mean(waveform, dim=0, keepdim=True)\n",
"\n",
" # Save final waveform as 16kHz PCM WAV\n",
" tmp = tempfile.NamedTemporaryFile(delete=False, suffix=\".wav\")\n",
" torchaudio.save(\n",
" tmp.name,\n",
" waveform,\n",
" 16000,\n",
" encoding=\"PCM_S\",\n",
" bits_per_sample=16\n",
" )\n",
" logger.info(f\"Final converted audio saved to: {tmp.name}\")\n",
" return tmp.name\n",
"\n",
"def transcribe_and_translate(wav_path: str):\n",
" \"\"\"\n",
" Always load the final WAV with librosa (avoids torchaudio backend issues),\n",
" then run through Whisper and Google Translate.\n",
" \"\"\"\n",
" # Load via librosa so we’re guaranteed to get a numpy array\n",
" y, sr = librosa.load(wav_path, sr=16000)\n",
" waveform = torch.from_numpy(y).unsqueeze(0).to(device)\n",
"\n",
" inputs = processor(\n",
" audio=waveform.squeeze().cpu().numpy(),\n",
" sampling_rate=16000,\n",
" return_tensors=\"pt\"\n",
" ).to(device)\n",
"\n",
" with torch.inference_mode():\n",
" ids = model.generate(inputs[\"input_features\"])\n",
" text = processor.batch_decode(ids, skip_special_tokens=True)[0]\n",
"\n",
" try:\n",
" trans = translator.translate(text, dest=\"ur\")\n",
" urdu = trans.text\n",
" except Exception as e:\n",
" logger.error(f\"Translation error: {e}\")\n",
" urdu = \"Translation unavailable\"\n",
"\n",
" return text, urdu\n",
"\n",
"# ----- ROUTES -----\n",
"@app.route(\"/\", methods=[\"GET\"])\n",
"def index():\n",
" return jsonify({\"status\": \"ok\"}), 200\n",
"\n",
"time.sleep(5)\n",
"\n",
"@app.route(\"/transcribe\", methods=[\"POST\"])\n",
"def transcribe():\n",
" try:\n",
" if \"audio\" not in request.files:\n",
" return jsonify({\"error\": \"No audio file\"}), 400\n",
"\n",
" f = request.files[\"audio\"]\n",
" if f.filename == \"\":\n",
" return jsonify({\"error\": \"Empty filename\"}), 400\n",
"\n",
" filename = secure_filename(f.filename)\n",
" in_path = os.path.join(app.config[\"UPLOAD_FOLDER\"], filename)\n",
" f.save(in_path)\n",
"\n",
" wav_path = None\n",
" try:\n",
" wav_path = convert_to_wav(in_path)\n",
" text, urdu = transcribe_and_translate(wav_path)\n",
" except Exception as e:\n",
" logger.error(f\"Audio processing error: {e}\")\n",
" return jsonify({\"error\": \"Audio processing failed\"}), 500\n",
" finally:\n",
" for p in (in_path, wav_path):\n",
" if p and os.path.exists(p):\n",
" try:\n",
" os.remove(p)\n",
" except Exception as e:\n",
" logger.warning(f\"Cleanup error: {e}\")\n",
"\n",
" return jsonify({\n",
" \"pashto_transcription\": text,\n",
" \"urdu_translation\": urdu\n",
" }), 200\n",
"\n",
" except Exception as e:\n",
" logger.error(f\"Endpoint error: {e}\")\n",
" return jsonify({\"error\": \"Server error\"}), 500\n",
"\n",
"# ----- RUN -----\n",
"if __name__ == \"__main__\":\n",
" ngrok.set_auth_token(NGROK_TOKEN)\n",
" public_url = ngrok.connect(5000)\n",
" logger.info(f\"Ngrok tunnel -> {public_url}\")\n",
" app.run(host=\"0.0.0.0\", port=5000)\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.5"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

Xet Storage Details

Size:
8.75 kB
·
Xet hash:
4d26c4e5ad880f92419c03aa53f0cfa798bdac4328a75827d04990ecf5f6f96e

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.