{"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":"gpu","dataSources":[{"sourceId":121150,"databundleVersionId":14976537,"sourceType":"competition"},{"sourceId":14219426,"sourceType":"datasetVersion","datasetId":9070463},{"sourceId":691374,"sourceType":"modelInstanceVersion","modelInstanceId":524178,"modelId":538190},{"sourceId":693865,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":526172,"modelId":540224}],"dockerImageVersionId":31236,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np \nimport pandas as pd \nimport os\nimport re","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-12-21T05:18:55.663842Z","iopub.execute_input":"2025-12-21T05:18:55.664104Z","iopub.status.idle":"2025-12-21T05:18:56.629026Z","shell.execute_reply.started":"2025-12-21T05:18:55.664072Z","shell.execute_reply":"2025-12-21T05:18:56.628308Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Preprocessing","metadata":{}},{"cell_type":"code","source":"import re\n\n\ndef preprocess_akkadian_text(text, text_type=\"transliteration\"):\n    \"\"\"\n    Preprocess Akkadian/Old Assyrian texts for machine learning.\n    Follows ALL dataset instructions for cleaning transliterations and translations.\n\n    Args:\n        text (str): Raw text in transliteration or translation\n        text_type (str): 'transliteration' or 'translation'\n\n    Returns:\n        str: Cleaned and standardized text\n    \"\"\"\n    if text is None:\n        raise ValueError(\"Input text cannot be None\")\n\n    if not isinstance(text, str):\n        raise TypeError(f\"Input text must be str, got {type(text).__name__}\")\n\n    if text_type not in {\"transliteration\", \"translation\"}:\n        raise ValueError(\n            \"text_type must be either 'transliteration' or 'translation'\"\n        )\n    try:\n        # ============================================================================\n        # TRANSLATION-SPECIFIC CLEANING (minimal preprocessing)\n        # ============================================================================\n        \n        if text_type == \"translation\":\n            # For translations, only do minimal cleaning:\n    \n            # 1. Standardize gaps\n            text = re.sub(r\"\\[x\\]\", \"<gap>\", text)\n            text = re.sub(r\"\\[…\\s*…\\]\", \"<big_gap>\", text)\n            text = re.sub(r\"\\[\\.\\.\\.+\\]\", \"<big_gap>\", text)\n            text = re.sub(r\"…+\", \"<big_gap>\", text)\n            text = re.sub(r\"\\.\\.\\.+\", \"<big_gap>\", text)\n    \n            # 2. Remove half brackets (partially broken signs)\n            text = text.replace(\"˹\", \"\")\n            text = text.replace(\"˺\", \"\")\n    \n            # 3. Remove line numbers (5', 10'', etc.)\n            text = re.sub(r\"\\b\\d+\\'+\\b\", \"\", text)\n    \n            # 4. Clean up whitespace\n            text = re.sub(r\"\\s+\", \" \", text)\n            text = text.strip()\n    \n            # KEEP: punctuation, capitalization, parentheses, brackets (meaningful in translations)\n    \n            return text\n    \n        # ============================================================================\n        # TRANSLITERATION-SPECIFIC CLEANING (full preprocessing)\n        # ============================================================================\n    \n        # ============================================================================\n        # STEP 1: Handle Line Numbers (Remove before other processing)\n        # ============================================================================\n    \n        # Remove line numbers: 1, 5', 10'', 15, etc.\n        text = re.sub(r\"\\b\\d+\\'+\\s*\", \"\", text)  # With apostrophes\n        text = re.sub(r\"^\\s*\\d+\\s+\", \" \", text, flags=re.MULTILINE)  # Line-initial numbers\n    \n        # ============================================================================\n        # STEP 2: Superscript Determinative Conversion\n        # ============================================================================\n    \n        # Convert superscript Unicode characters to curly bracket format\n        # Common superscript determinatives\n        superscript_conversions = {\n            \"ᵈ\": \"{d}\",\n            \"ᵏⁱ\": \"{ki}\",\n            \"ᵏᶦ\": \"{ki}\",\n            \"ᶠ\": \"{mi}\",\n            \"ᵐ\": \"{m}\",\n            \"ᵍᵉˢ\": \"{geš}\",\n            \"ᵍᵉˢʰ\": \"{geš}\",\n            \"ᵗᵘᵍ\": \"{tug2}\",\n            \"ᵈᵘᵇ\": \"{dub}\",\n            \"ᶦᵈ\": \"{id2}\",\n            \"ᵐᵘˢᵉⁿ\": \"{mušen}\",\n            \"ⁿᵃ\": \"{na4}\",\n            \"ᵏᵘˢ\": \"{kuš}\",\n            \"ᵘ\": \"{u2}\",\n            \"ˡᵘ\": \"{lu2}\",\n            \"ᵉ\": \"{e2}\",\n            \"ᵘʳᵘ\": \"{uru}\",\n            \"ᵏᵘʳ\": \"{kur}\",\n            \"ᵐᵘˡ\": \"{mul}\",\n        }\n    \n        for sup, bracket in superscript_conversions.items():\n            text = text.replace(sup, bracket)\n    \n        # Handle remaining standalone superscript letters (generic catch-all)\n        # Superscript a-z range: ᵃᵇᶜᵈᵉᶠᵍʰⁱʲᵏˡᵐⁿᵒᵖqʳˢᵗᵘᵛʷˣʸᶻ\n        superscript_letters = \"ᵃᵇᶜᵈᵉᶠᵍʰⁱʲᵏˡᵐⁿᵒᵖʳˢᵗᵘᵛʷˣʸᶻ\"\n        regular_letters = \"abcdefghijklmnopqrstuvwxyz\"\n    \n        for sup, reg in zip(superscript_letters, regular_letters):\n            text = text.replace(sup, reg)\n    \n        # ============================================================================\n        # STEP 3: Character Normalization (Handle ALL THREE formats)\n        # ============================================================================\n    \n        # ORACC format (with Unicode subscripts) → Unicode characters\n        oracc_to_unicode = {\n            \"a₂\": \"á\",\n            \"a₃\": \"à\",\n            \"e₂\": \"é\",\n            \"e₃\": \"è\",\n            \"i₂\": \"í\",\n            \"i₃\": \"ì\",\n            \"u₂\": \"ú\",\n            \"u₃\": \"ù\",\n        }\n    \n        for oracc, uni in oracc_to_unicode.items():\n            text = text.replace(oracc, uni)\n    \n        # CDLI format → Unicode characters\n        cdli_to_unicode = {\n            \"a2\": \"á\",\n            \"a3\": \"à\",\n            \"e2\": \"é\",\n            \"e3\": \"è\",\n            \"i2\": \"í\",\n            \"i3\": \"ì\",\n            \"u2\": \"ú\",\n            \"u3\": \"ù\",\n            \"sz\": \"š\",\n            \"SZ\": \"Š\",\n            \"s,\": \"ṣ\",\n            \"S,\": \"Ṣ\",\n            \"t,\": \"ṭ\",\n            \"T,\": \"Ṭ\",\n            \"h\": \"ḫ\",\n            \"H\": \"Ḫ\",\n        }\n    \n        for cdli, uni in cdli_to_unicode.items():\n            text = text.replace(cdli, uni)\n    \n        # Aleph conversion\n        text = text.replace(\"'\", \"ʾ\")\n    \n        # ============================================================================\n        # STEP 4: Subscript Normalization (Numbers)\n        # ============================================================================\n    \n        # Convert Unicode subscripts (₀₁₂₃₄₅₆₇₈₉ₓ) to regular numbers\n        # Example: il₅ → il5, {lu₂} → {lu2}\n        subscript_map = str.maketrans(\"₀₁₂₃₄₅₆₇₈₉ₓ\", \"0123456789x\")\n        text = text.translate(subscript_map)\n    \n        # ============================================================================\n        # STEP 5: Standardize Gaps and Breaks\n        # ============================================================================\n    \n        # Single sign breaks → <gap>\n        text = re.sub(r\"\\[x\\]\", \"<gap>\", text)\n        text = re.sub(r\"\\[X\\]\", \"<gap>\", text)\n    \n        # Multiple signs / large breaks → <big_gap>\n        text = re.sub(r\"\\[…\\s*…\\]\", \"<big_gap>\", text)\n        text = re.sub(r\"\\[\\.\\.\\.+\\]\", \"<big_gap>\", text)\n        text = re.sub(r\"…+\", \"<big_gap>\", text)\n        text = re.sub(r\"\\.\\.\\.+\", \"<big_gap>\", text)\n    \n        # ============================================================================\n        # STEP 6: Remove Modern Scribal Notations\n        # ============================================================================\n    \n        # Remove exclamation marks (certain reading)\n        text = text.replace(\"!\", \"\")\n    \n        # Remove question marks (uncertain reading)\n        text = text.replace(\"?\", \"\")\n    \n        # Remove forward slashes (line divider)\n        text = text.replace(\"/\", \" \")  # Replace with space to avoid merging words\n    \n        # Remove colons (word divider)\n        text = text.replace(\":\", \"\")\n    \n        # Remove periods (word divider) - used in Sumerian logograms\n        # Note: Periods connect logogram components (e.g., KÙ.BABBAR)\n        # Per instructions: \"Remove : OR . (word divider)\"\n        text = text.replace(\".\", \"\")\n    \n        # ============================================================================\n        # STEP 7: Handle Bracket Notations\n        # ============================================================================\n    \n        # Remove pointy brackets < > but KEEP the text inside (scribal insertions)\n        text = re.sub(r\"<([^>]+)>\", r\"\\1\", text)\n    \n        # Remove double pointy brackets << >> but KEEP the text (erroneous signs)\n        text = re.sub(r\"<<([^>]+)>>\", r\"\\1\", text)\n    \n        # Remove half brackets ˹ ˺ (partially broken signs)\n        text = text.replace(\"˹\", \"\")\n        text = text.replace(\"˺\", \"\")\n    \n        # Remove square brackets [ ] but KEEP the text inside (clearly broken signs)\n        # Example: [KÙ.BABBAR] → KÙ.BABBAR (after period already removed)\n        text = re.sub(r\"\\[([^\\]]+)\\]\", r\"\\1\", text)\n    \n        # Remove parentheses ( ) but KEEP the text inside (comments for breaks/erasures)\n        text = re.sub(r\"\\(([^\\)]+)\\)\", r\"\\1\", text)\n    \n        # KEEP curly brackets { } - these are determinatives (essential!)\n        # Example: {ki}, {d}, {lu2} remain unchanged\n    \n        # ============================================================================\n        # STEP 8: Normalize Determinatives (ensure consistent format)\n        # ============================================================================\n    \n        # Ensure determinatives have consistent subscript numbers\n        # Example: {lu₂} should already be {lu2} from Step 4\n        # This is a verification step - determinatives should be properly formatted now\n    \n        # ============================================================================\n        # STEP 9: Clean Up Whitespace\n        # ============================================================================\n    \n        # Replace multiple spaces with single space\n        text = re.sub(r\"\\s+\", \" \", text)\n    \n        # Remove leading/trailing whitespace\n        text = text.strip()\n    \n        # Remove spaces before/after hyphens in syllabic words\n        text = re.sub(r\"\\s*-\\s*\", \"-\", text)\n    \n        return text\n    except Exception as e:\n        # Regex-specific failure\n        print(f\"Regex processing failed: {e}\")\n        return text\n\n\ndef batch_preprocess(texts, text_type=\"transliteration\"):\n    \"\"\"\n    Preprocess multiple texts at once.\n\n    Args:\n        texts (list): List of raw texts\n        text_type (str): 'transliteration' or 'translation'\n\n    Returns:\n        list: List of cleaned texts\n    \"\"\"\n    return [preprocess_akkadian_text(text, text_type) for text in texts]\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-21T05:18:56.630509Z","iopub.execute_input":"2025-12-21T05:18:56.630883Z","iopub.status.idle":"2025-12-21T05:18:56.649054Z","shell.execute_reply.started":"2025-12-21T05:18:56.630860Z","shell.execute_reply":"2025-12-21T05:18:56.648362Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Inference","metadata":{}},{"cell_type":"code","source":"from transformers import AutoTokenizer, AutoModelForSeq2SeqLM\nimport torch\n\n\n# Load your trained model\nmodel_path = \"/kaggle/input/t5-base-akkadian2english/transformers/default/1/t5_base_akkadian2English\"\n\n# Load tokenizer and model\ntokenizer = AutoTokenizer.from_pretrained(model_path)\nmodel = AutoModelForSeq2SeqLM.from_pretrained(model_path)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-21T05:18:56.650019Z","iopub.execute_input":"2025-12-21T05:18:56.650330Z","iopub.status.idle":"2025-12-21T05:19:24.530212Z","shell.execute_reply.started":"2025-12-21T05:18:56.650300Z","shell.execute_reply":"2025-12-21T05:19:24.529429Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Move to GPU if available\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nmodel = model.to(device)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-21T05:19:24.534244Z","iopub.execute_input":"2025-12-21T05:19:24.534508Z","iopub.status.idle":"2025-12-21T05:19:31.134915Z","shell.execute_reply.started":"2025-12-21T05:19:24.534467Z","shell.execute_reply":"2025-12-21T05:19:31.134129Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Inference function\ndef generate_text(input_text, max_length=128, num_beams=4, temperature=1.0):\n    \"\"\"\n    Generate text using the trained seq2seq model\n    \n    Args:\n        input_text: Input text to process\n        max_length: Maximum length of generated text\n        num_beams: Beam search width (higher = better quality, slower)\n        temperature: Sampling temperature (lower = more deterministic)\n    \"\"\"\n    try:\n        # Tokenize input\n        inputs = tokenizer(\n            input_text, \n            return_tensors=\"pt\", \n            max_length=512, \n            truncation=True,\n            padding=True\n        ).to(device)\n        \n        # Generate\n        with torch.no_grad():\n            outputs = model.generate(\n                inputs[\"input_ids\"],\n                max_length=max_length,\n                num_beams=num_beams,\n                temperature=temperature,\n                do_sample=True if temperature < 1.0 else False,\n                early_stopping=True,\n                no_repeat_ngram_size=2,\n                pad_token_id=tokenizer.pad_token_id,\n                eos_token_id=tokenizer.eos_token_id\n            )\n        \n        # Decode output\n        generated_text = tokenizer.decode(outputs[0], skip_special_tokens=True)\n        return generated_text\n    \n    except Exception as e:\n        return \"\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-21T05:19:31.136076Z","iopub.execute_input":"2025-12-21T05:19:31.136442Z","iopub.status.idle":"2025-12-21T05:19:31.142079Z","shell.execute_reply.started":"2025-12-21T05:19:31.136408Z","shell.execute_reply":"2025-12-21T05:19:31.141521Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_df = pd.read_csv(\"/kaggle/input/deep-past-initiative-machine-translation/test.csv\")\ntest_df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-21T05:19:31.142912Z","iopub.execute_input":"2025-12-21T05:19:31.143183Z","iopub.status.idle":"2025-12-21T05:19:31.188129Z","shell.execute_reply.started":"2025-12-21T05:19:31.143151Z","shell.execute_reply":"2025-12-21T05:19:31.187619Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"transliterations = test_df['transliteration']\ngen_translations = []\n\nfor transliteration in transliterations:\n    cleaned_transliteration = preprocess_akkadian_text(\n        transliteration, \n        text_type=\"transliteration\"\n    )\n\n    gen_translation = generate_text(cleaned_transliteration)\n    gen_translations.append(gen_translation)\n    print(f\"Input: {transliteration}\")\n    print(f\"Output: {gen_translation}\")\n    print(\"\\n\\n\")\n    ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-21T05:19:31.189002Z","iopub.execute_input":"2025-12-21T05:19:31.189308Z","iopub.status.idle":"2025-12-21T05:19:39.300551Z","shell.execute_reply.started":"2025-12-21T05:19:31.189272Z","shell.execute_reply":"2025-12-21T05:19:39.299763Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.DataFrame({\n    \"id\": range(len(gen_translations)),\n    \"translation\": gen_translations\n})\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-21T05:19:39.301480Z","iopub.execute_input":"2025-12-21T05:19:39.301721Z","iopub.status.idle":"2025-12-21T05:19:39.306223Z","shell.execute_reply.started":"2025-12-21T05:19:39.301698Z","shell.execute_reply":"2025-12-21T05:19:39.305300Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df.to_csv(\"submission.csv\", index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-21T05:19:39.308297Z","iopub.execute_input":"2025-12-21T05:19:39.308558Z","iopub.status.idle":"2025-12-21T05:19:39.343711Z","shell.execute_reply.started":"2025-12-21T05:19:39.308537Z","shell.execute_reply":"2025-12-21T05:19:39.343044Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-21T05:19:39.344442Z","iopub.execute_input":"2025-12-21T05:19:39.344719Z","iopub.status.idle":"2025-12-21T05:19:39.358770Z","shell.execute_reply.started":"2025-12-21T05:19:39.344696Z","shell.execute_reply":"2025-12-21T05:19:39.358177Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}