{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":129276,"databundleVersionId":15506988,"sourceType":"competition"}],"dockerImageVersionId":31260,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install -q transformers accelerate bitsandbytes scipy","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-04T11:34:25.635337Z","iopub.execute_input":"2026-02-04T11:34:25.635853Z","iopub.status.idle":"2026-02-04T11:34:32.446523Z","shell.execute_reply.started":"2026-02-04T11:34:25.635828Z","shell.execute_reply":"2026-02-04T11:34:32.445844Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nfrom transformers import pipeline, AutoModelForCausalLM, AutoTokenizer\n\ndevice = \"cuda:0\"\n\n# --- CONFIGURATION ---\n# Use your fine-tuned path \"./final_model\" if you trained it.\n# For now, we use a public baseline to ensure code runs.\nASR_MODEL_ID = \"bangla-speech-processing/BanglaASR\" \nLLM_MODEL_ID = \"Qwen/Qwen2.5-7B-Instruct\" \n\n# 1. Load ASR Pipeline\nasr_pipeline = pipeline(\n    \"automatic-speech-recognition\",\n    model=ASR_MODEL_ID,\n    chunk_length_s=30,\n    device=device\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-04T11:34:32.448306Z","iopub.execute_input":"2026-02-04T11:34:32.448632Z","iopub.status.idle":"2026-02-04T11:35:09.349841Z","shell.execute_reply.started":"2026-02-04T11:34:32.448600Z","shell.execute_reply":"2026-02-04T11:35:09.349071Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 2. Load LLM (The Corrector)\n# We use 4-bit loading to save memory\nfrom transformers import BitsAndBytesConfig\n\nbnb_config = BitsAndBytesConfig(\n    load_in_4bit=True,\n    bnb_4bit_quant_type=\"nf4\",\n    bnb_4bit_compute_dtype=torch.float16\n)\n\nllm_tokenizer = AutoTokenizer.from_pretrained(LLM_MODEL_ID)\nllm_model = AutoModelForCausalLM.from_pretrained(\n    LLM_MODEL_ID,\n    quantization_config=bnb_config,\n    device_map=\"auto\" # Automatically splits between GPUs\n)\n\ndef llm_correct_text(raw_text):\n    if not raw_text or len(raw_text) < 5:\n        return raw_text\n        \n    prompt = f\"\"\"\n    You are an expert Bangla text editor. \n    Correct the spelling and grammar of the following Bangla text. \n    Do not add any punctuation. Do not add any explanation.\n    \n    Input: {raw_text}\n    Output:\"\"\"\n    \n    inputs = llm_tokenizer(prompt, return_tensors=\"pt\").to(\"cuda\")\n    \n    # Generate correction\n    with torch.no_grad():\n        outputs = llm_model.generate(\n            **inputs, \n            max_new_tokens=len(inputs['input_ids'][0]) + 50,\n            temperature=0.1 # Low temp for precision\n        )\n        \n    response = llm_tokenizer.decode(outputs[0], skip_special_tokens=True)\n    \n    # Extract output (Simple parsing)\n    if \"Output:\" in response:\n        return response.split(\"Output:\")[-1].strip()\n    return response.strip()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-04T11:43:30.351801Z","iopub.execute_input":"2026-02-04T11:43:30.352594Z","iopub.status.idle":"2026-02-04T11:44:50.636910Z","shell.execute_reply.started":"2026-02-04T11:43:30.352563Z","shell.execute_reply":"2026-02-04T11:44:50.636123Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport torch\nimport gc\nimport pandas as pd\nfrom tqdm.auto import tqdm\nfrom transformers import pipeline, AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig\nimport string\n\n# --- CONFIGURATION ---\nTEST_AUDIO_DIR = \"/kaggle/input/dl-sprint-4-0-bengali-long-form-speech-recognition/transcription/transcription/test/audio\"\nASR_MODEL_ID = \"bangla-speech-processing/BanglaASR\" \nLLM_MODEL_ID = \"Qwen/Qwen2.5-7B-Instruct\"\n\n# Get list of files\nfiles = [f for f in os.listdir(TEST_AUDIO_DIR) if f.endswith('.wav')]\ntemp_results = []\n\n# ==========================================\n# PART 1: ASR TRANSCRIPTION (Audio -> Text)\n# ==========================================\nprint(f\"--- STARTING PART 1: ASR ({len(files)} files) ---\")\n\n# Load ASR Model ONLY\nasr_pipeline = pipeline(\n    \"automatic-speech-recognition\",\n    model=ASR_MODEL_ID,\n    chunk_length_s=30,   # CRITICAL: Process in 30s chunks to avoid OOM\n    stride_length_s=(5, 5), # Overlap chunks to not cut words\n    device=\"cuda:0\"\n)\n\nfor file in tqdm(files):\n    path = os.path.join(TEST_AUDIO_DIR, file)\n    try:\n        # Batch size 1 is safer for memory\n        # We use return_timestamps=\"word\" if supported, else just text\n        out = asr_pipeline(path, batch_size=1, return_timestamps=False)\n        text = out['text']\n        temp_results.append({\"id\": file.replace('.wav', ''), \"raw_text\": text})\n    except Exception as e:\n        print(f\"ASR Fail {file}: {e}\")\n        # If GPU fails, try a tiny fallback or leave empty\n        temp_results.append({\"id\": file.replace('.wav', ''), \"raw_text\": \"\"})\n\n# FREE GPU MEMORY\ndel asr_pipeline\ntorch.cuda.empty_cache()\ngc.collect()\nprint(\"ASR Model removed from memory.\")\n\n# ==========================================\n# PART 2: LLM CORRECTION (Text -> Text)\n# ==========================================\nprint(f\"--- STARTING PART 2: LLM Correction ---\")\n\n# Load LLM ONLY (Now we have full VRAM available)\nbnb_config = BitsAndBytesConfig(\n    load_in_4bit=True,\n    bnb_4bit_quant_type=\"nf4\",\n    bnb_4bit_compute_dtype=torch.float16\n)\n\nllm_tokenizer = AutoTokenizer.from_pretrained(LLM_MODEL_ID)\nllm_model = AutoModelForCausalLM.from_pretrained(\n    LLM_MODEL_ID,\n    quantization_config=bnb_config,\n    device_map=\"auto\"\n)\n\nfinal_results = []\n\ndef clean_punctuation(text):\n    # Remove all punctuation including Bangla ones\n    remove_chars = string.punctuation + '।॥'\n    translator = str.maketrans('', '', remove_chars)\n    return text.translate(translator).strip()\n\ndef llm_correct(text):\n    if not text or len(text) < 5: return text\n    \n    prompt = f\"\"\"Correct the spelling errors in this Bangla text. Keep the meaning same. Output only the corrected text.\n    Input: {text}\n    Output:\"\"\"\n    \n    inputs = llm_tokenizer(prompt, return_tensors=\"pt\").to(\"cuda\")\n    with torch.no_grad():\n        outputs = llm_model.generate(**inputs, max_new_tokens=len(text)+50, temperature=0.1)\n    \n    response = llm_tokenizer.decode(outputs[0], skip_special_tokens=True)\n    return response.split(\"Output:\")[-1].strip() if \"Output:\" in response else response\n\n# Process the text generated in Part 1\nfor item in tqdm(temp_results):\n    raw = item['raw_text']\n    file_id = item['id']\n    \n    try:\n        if len(raw) > 5:\n            # Step A: Correct with LLM\n            corrected = llm_correct(raw)\n            # Step B: Final Cleanup (Remove punctuation)\n            final = clean_punctuation(corrected)\n        else:\n            final = \"\"\n            \n        final_results.append({\"id\": file_id, \"sentence\": final})\n        \n    except Exception as e:\n        print(f\"LLM Fail {file_id}: {e}\")\n        # Fallback: use raw text cleaned\n        final_results.append({\"id\": file_id, \"sentence\": clean_punctuation(raw)})\n\n# ==========================================\n# PART 3: SAVE SUBMISSION\n# ==========================================\ndf_sub = pd.DataFrame(final_results)\ndf_sub = df_sub.sort_values('id')\ndf_sub.to_csv(\"submission.csv\", index=False)\nprint(\"SUCCESS: submission.csv created with actual data.\")","metadata":{"trusted":true,"execution":{"execution_failed":"2026-02-04T12:17:54.053Z"}},"outputs":[],"execution_count":null}]}