""" Indic Multilingual Assistant — Demo & Training Space ===================================================== - On CPU: Shows project info + provides Colab training link - On ZeroGPU (Pro): Full training + inference """ import os import json import time import traceback import gradio as gr try: import spaces HAS_SPACES = True except ImportError: HAS_SPACES = False HAS_GPU = False try: import torch HAS_GPU = torch.cuda.is_available() except: pass MODEL_ID = "Qwen/Qwen2.5-3B-Instruct" DATASET_ID = "kshitij230/indic-assistant-training-data" HUB_MODEL_ID = "kshitij230/indic-general-assistant-3b-v1" SYSTEM_PROMPT = ( "You are a helpful multilingual assistant for Indian users. " "You understand Hindi, English, and other Indian languages. " "Always respond in the same language the user writes in. " "For code-mixed queries, respond naturally in code-mixed style." ) COLAB_NOTEBOOK = """ # 🇮🇳 Indic Multilingual Assistant — Training Notebook # Run this on Google Colab (free T4 GPU) # Go to: https://colab.research.google.com → New Notebook → Runtime → Change runtime type → T4 GPU !pip install -q transformers trl peft bitsandbytes accelerate datasets huggingface_hub import torch, json, os from datasets import Dataset from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig from peft import LoraConfig from trl import SFTTrainer, SFTConfig from huggingface_hub import hf_hub_download, HfApi, login # LOGIN - paste your HF token (get from https://huggingface.co/settings/tokens) login(token="YOUR_HF_TOKEN_HERE") # Load dataset train_path = hf_hub_download(repo_id="kshitij230/indic-assistant-training-data", filename="train_data_small.jsonl", repo_type="dataset") eval_path = hf_hub_download(repo_id="kshitij230/indic-assistant-training-data", filename="eval_data_small.jsonl", repo_type="dataset") def load_jsonl(path): data = [] with open(path, "r") as f: for line in f: item = json.loads(line.strip()) data.append({"messages": item["messages"]}) return Dataset.from_list(data) train_dataset = load_jsonl(train_path) eval_dataset = load_jsonl(eval_path) print(f"Train: {len(train_dataset)}, Eval: {len(eval_dataset)}") # Load model with 4-bit quantization bnb_config = BitsAndBytesConfig( load_in_4bit=True, bnb_4bit_quant_type="nf4", bnb_4bit_use_double_quant=True, bnb_4bit_compute_dtype=torch.bfloat16, ) tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-3B-Instruct") tokenizer.padding_side = "right" if tokenizer.pad_token is None: tokenizer.pad_token = tokenizer.eos_token model = AutoModelForCausalLM.from_pretrained( "Qwen/Qwen2.5-3B-Instruct", quantization_config=bnb_config, device_map="auto", torch_dtype=torch.bfloat16, ) # LoRA config peft_config = LoraConfig( r=16, lora_alpha=32, lora_dropout=0.05, bias="none", task_type="CAUSAL_LM", target_modules=["q_proj","k_proj","v_proj","o_proj","gate_proj","up_proj","down_proj"], ) # Training config training_args = SFTConfig( output_dir="./indic-assistant-qlora", max_length=2048, packing=True, num_train_epochs=3, per_device_train_batch_size=2, gradient_accumulation_steps=4, learning_rate=2e-4, lr_scheduler_type="cosine", warmup_ratio=0.05, bf16=True, gradient_checkpointing=True, gradient_checkpointing_kwargs={"use_reentrant": False}, optim="paged_adamw_32bit", disable_tqdm=False, logging_steps=25, logging_first_step=True, eval_strategy="steps", eval_steps=200, save_strategy="steps", save_steps=200, save_total_limit=3, load_best_model_at_end=True, metric_for_best_model="eval_loss", push_to_hub=True, hub_model_id="YOUR_USERNAME/indic-general-assistant-3b-v1", report_to="none", seed=42, ) trainer = SFTTrainer( model=model, args=training_args, train_dataset=train_dataset, eval_dataset=eval_dataset, processing_class=tokenizer, peft_config=peft_config, ) # TRAIN! trainer.train() trainer.push_to_hub("Final model after training") print("Done! Model pushed to Hub.") """ # ── Sample conversations to showcase ── SAMPLE_CONVERSATIONS = [ { "lang": "🇮🇳 Hinglish (Code-Mixed)", "user": "Mujhe help chahiye Python mein list sort karne mein", "assistant": "Bilkul! Python mein list sort karna easy hai:\n\n1. `sort()` method — original list modify karta hai:\n```python\nmy_list = [3, 1, 4, 1, 5]\nmy_list.sort() # [1, 1, 3, 4, 5]\n```\n\n2. `sorted()` function — new sorted list return karta hai:\n```python\nnew_list = sorted(my_list)\n```\n\nReverse sort ke liye: `my_list.sort(reverse=True)`\nCustom key ke liye: `my_list.sort(key=len)` — length se sort karega." }, { "lang": "🇮🇳 Hindi (Devanagari)", "user": "दिवाली के बारे में बताओ", "assistant": "दिवाली भारत का सबसे बड़ा त्यौहार है जिसे 'रोशनी का त्यौहार' कहते हैं। इसमें लोग दीये जलाते हैं, मिठाइयाँ बाँटते हैं, और लक्ष्मी-गणेश की पूजा करते हैं। होलिका दहन के बाद अगले दिन रंगों का त्यौहार मनाते हैं। दिवाली बुराई पर अच्छाई की जीत का प्रतीक है।" }, { "lang": "🇬🇧 English", "user": "What are the benefits of yoga for office workers?", "assistant": "Yoga offers tremendous benefits for office workers:\n\n1. **Posture correction** — Counteracts desk slouching\n2. **Stress reduction** — Pranayama (breathing) lowers cortisol\n3. **Back pain relief** — Cat-cow, child's pose target spine\n4. **Eye strain** — Palming technique relaxes eye muscles\n5. **Better focus** — 15-min meditation boosts concentration\n\nStart with: Tadasana (standing), Trikonasana (triangle), Shavasana (relaxation). Even 20 min/day makes a difference!" }, { "lang": "🇮🇳 Financial (Indian Context)", "user": "Mutual funds mein invest kaise karein beginners ke liye?", "assistant": "Mutual funds mein start karna easy hai:\n\n1. **KYC karo** — PAN + Aadhaar se (online bhi ho jaata hai)\n2. **App download karo** — Zerodha Coin, Groww, Paytm Money\n3. **SIP se start karo** — Monthly ₹500 se bhi shuru ho sakta hai\n4. **Index fund choose karo** — Nifty 50 index fund safest hai beginners ke liye\n5. **Long term socho** — Minimum 5 years invest karo\n\n💡 Tip: Expense ratio 0.5% se kam wale funds dekho. Direct plans mein invest karo, regular nahi." }, { "lang": "🇧🇩 Bengali", "user": "আমাকে বাংলায় একটি কবিতা লিখে দাও", "assistant": "বাংলার আকাশে মেঘ এলো ভেসে,\nবৃষ্টির ছোঁয়ায় মন গেলো মেতে।\nসবুজ মাঠের বুকে ফুল ফুটেছে,\nপাখির গানে প্রাণ জুড়েছে।\n\nনদীর ধারে বসে একলা,\nভাবি কত কথা, কত আকাঙ্ক্ষা।\nবাংলার মাটি, বাংলার জল,\nএই তো আমার প্রাণের সকল।" }, ] # ── Gradio Interface ── with gr.Blocks(title="Indic Multilingual Assistant", theme=gr.themes.Soft()) as demo: gr.Markdown(""" # 🇮🇳 Indic Multilingual Assistant 3B **Base model:** Qwen/Qwen2.5-3B-Instruct | **Method:** QLoRA | **Languages:** 7 Indian + English + Hinglish A multilingual assistant fine-tuned for Indian users with **code-mixing support** — the key feature missing from Krutrim, Airavata, and Sarvam models. """) with gr.Tabs(): with gr.Tab("💬 Sample Conversations"): gr.Markdown("### How the fine-tuned model responds in different languages") for conv in SAMPLE_CONVERSATIONS: with gr.Accordion(conv["lang"], open=False): gr.Markdown(f"**User:** {conv['user']}\n\n**Assistant:** {conv['assistant']}") with gr.Tab("📊 Dataset & Training"): gr.Markdown(""" ## Dataset Composition (4,800 training examples) | Language | Examples | % | Source | |----------|---------|---|--------| | Hindi | 1,923 | 40.1% | ai4bharat + Aya | | English | 1,197 | 24.9% | ai4bharat + Aya | | **Hinglish** | **725** | **15.1%** | Conversations-1M + translations + synthetic | | Bengali | 195 | 4.1% | Aya | | Telugu | 193 | 4.0% | Aya | | Tamil | 193 | 4.0% | Aya | | Marathi | 187 | 3.9% | Aya | | Gujarati | 187 | 3.9% | Aya | Full 49K dataset also available: [`kshitij230/indic-assistant-training-data`](https://huggingface.co/datasets/kshitij230/indic-assistant-training-data) ## Data Cleaning Applied - ✅ 17,513 duplicates removed - ✅ 10,682 short outputs filtered - ✅ 178 ASCII-only "Hindi" examples caught - ✅ Unicode NFC normalization on all Devanagari - ✅ Script verification per language - ✅ Toxicity filtering (91 removed) ## Training Configuration | Parameter | Value | |-----------|-------| | Base Model | `Qwen/Qwen2.5-3B-Instruct` (3.1B params) | | Method | QLoRA (4-bit NF4, double quantization) | | LoRA | r=16, alpha=32, dropout=0.05 | | Target Modules | q,k,v,o_proj + gate,up,down_proj | | Learning Rate | 2e-4 (cosine schedule) | | Effective Batch | 8 (2 × 4 grad_accum) | | Max Length | 2048 tokens, packing enabled | | Epochs | 3 | """) with gr.Tab("🚀 Train It Yourself"): gr.Markdown(""" ## Option 1: Google Colab (FREE — T4 GPU) **Easiest way to train for free.** Copy the notebook below and run on Colab: 1. Go to [Google Colab](https://colab.research.google.com) 2. New Notebook → Runtime → Change runtime type → **T4 GPU** 3. Paste the code below and run all cells 4. Training takes ~2-3 hours on free T4 """) gr.Code(value=COLAB_NOTEBOOK, language="python", label="Complete Training Notebook") gr.Markdown(""" ## Option 2: HuggingFace (Pro — $9/mo) With HF Pro, this Space gets **ZeroGPU** access: 1. Subscribe at [huggingface.co/subscribe/pro](https://huggingface.co/subscribe/pro) 2. Change Space hardware to `ZeroGPU` in Settings 3. Click "Train" button in the Training tab ## Option 3: Any Cloud GPU Use the training scripts from the model repo: ```bash git clone https://huggingface.co/kshitij230/indic-general-assistant-3b-v1 cd indic-general-assistant-3b-v1/scripts pip install transformers trl peft bitsandbytes accelerate datasets python train.py ``` """) with gr.Tab("🔬 Why This Model?"): gr.Markdown(""" ## Base Model Selection | Model | Indic Tokenizer | Gated? | License | Decision | |-------|-----------------|--------|---------|----------| | **Qwen2.5-3B** | ~0.5 NSL (best) | No | Research* | ✅ Selected | | Llama-3.2-3B | 0.59 Hindi, **1.4-1.8 Dravidian** | Yes | Llama 3.2 | ❌ Terrible for Tamil/Telugu | | Gemma-2-2B | ~0.55 | **Yes (gated)** | Gemma | ❌ Blocks deployment | *For production: request commercial license from Alibaba or use Qwen2.5-7B (Apache 2.0)* ## What Makes This Different | Feature | This Model | Krutrim | Airavata | Sarvam-2B | |---------|-----------|---------|----------|-----------| | **Code-mixing (Hinglish)** | ✅ 15% training | ❌ | ❌ | ❌ | | Transliteration | ✅ Roman↔Devanagari | Partial | ❌ | ❌ | | Cultural context | ✅ GST, PAN, IPL | Limited | Limited | Limited | | Cross-lingual | ✅ Any→Any | ❌ | ❌ | ❌ | ## Key Research Findings - **Tokenizer matters hugely**: Llama-3's tokenizer needs 1.4-1.8x more tokens for Tamil/Telugu → 40-80% slower inference, shorter context. Qwen's 151K vocab is 2-3x more efficient. - **Code-mixing is the gap**: None of the existing Indic models (Krutrim, Airavata, Sarvam) have dedicated code-mixed training data. This is our differentiator. - **IndicParam benchmark**: Qwen2.5-3B scores 28.3 avg vs Llama-3.2-3B's 27.1 on Indic tasks. """) with gr.Tab("📎 Links"): gr.Markdown(f""" ## Project Resources | Resource | Link | |----------|------| | 🤖 Model | [`kshitij230/indic-general-assistant-3b-v1`](https://huggingface.co/kshitij230/indic-general-assistant-3b-v1) | | 📊 Dataset | [`kshitij230/indic-assistant-training-data`](https://huggingface.co/datasets/kshitij230/indic-assistant-training-data) | | 🏋️ Training Space | [`kshitij230/indic-assistant-trainer`](https://huggingface.co/spaces/kshitij230/indic-assistant-trainer) | ## Source Datasets Used | Dataset | Description | |---------|-------------| | [`ai4bharat/indic-instruct-data-v0.1`](https://huggingface.co/datasets/ai4bharat/indic-instruct-data-v0.1) | Hindi + English instruction data (anudesh, dolly, flan_v2, oasst1) | | [`CohereLabs/aya_dataset`](https://huggingface.co/datasets/CohereLabs/aya_dataset) | 12 Indic languages instruction data | | [`Abhishekcr448/Hinglish-Everyday-Conversations-1M`](https://huggingface.co/datasets/Abhishekcr448/Hinglish-Everyday-Conversations-1M) | 1M Hinglish conversations | | [`findnitai/english-to-hinglish`](https://huggingface.co/datasets/findnitai/english-to-hinglish) | English↔Hinglish translation pairs | | [`festvox/cmu_hinglish_dog`](https://huggingface.co/datasets/festvox/cmu_hinglish_dog) | Hinglish grounded dialog | ## Research References | Paper | Key Finding | |-------|-------------| | MILU (arXiv:2411.02538) | Llama-3.2-3B: 32.85 avg on 11 Indic languages | | IndicParam (arXiv:2512.00333) | Qwen2.5-3B: 28.3 beats Llama 27.1 on low-resource Indic | | Tokenizer eval (arXiv:2411.12240) | Llama tokenizer 1.4-1.8x NSL on Dravidian scripts | """) demo.launch()