| """ |
| Sarus 500M (by ViuAI) — SFT Dataset Builder V6.1 |
| ============================================================ |
| Fixes: |
| 1. Replaces trivia RAG with dynamic open-ended queries (news, prices) & 3-result DDG format. |
| 2. Long Thinking (80-120 words) & Detailed Synthesis (150+ words) for RAG. |
| 3. RAG Fallbacks for empty searches. |
| 4. Tokenizer parity check. |
| 5. Exact 60k balancing & Stratified Validation. |
| 6. Saves category tags for loss weighting. |
| 7. System prompt format variations (20%). |
| """ |
|
|
| import os |
| import random |
| import numpy as np |
| from datetime import datetime |
| from datasets import load_dataset |
| from tqdm import tqdm |
| from transformers import PreTrainedTokenizerFast |
| from huggingface_hub import hf_hub_download, HfApi |
|
|
| |
| |
| |
| random.seed(42) |
| np.random.seed(42) |
|
|
| HF_TOKEN = os.environ.get("HF_TOKEN") |
| if not HF_TOKEN: |
| raise ValueError("Please set HF_TOKEN environment variable!") |
|
|
| MODEL_REPO = "ViuAI/ViuAI-500M" |
| OUT_DIR = "sft_data_v6" |
| os.makedirs(OUT_DIR, exist_ok=True) |
|
|
| print("Loading tokenizer from HuggingFace...") |
| tok_path = hf_hub_download(MODEL_REPO, "tokenizer/tokenizer.json", token=HF_TOKEN) |
| tokenizer = PreTrainedTokenizerFast(tokenizer_file=tok_path) |
| tokenizer.add_tokens(["<|user|>", "<|assistant|>", "<|endofturn|>", "[THINK]", "[/THINK]", "<search>", "</search>", "<search_result>", "</search_result>"], special_tokens=True) |
| print(f"Vocab size: {len(tokenizer)}") |
|
|
| |
| try: |
| chk_path = "../tokenizer/tokenizer.json" |
| if os.path.exists(chk_path): |
| tok_chk = PreTrainedTokenizerFast(tokenizer_file=chk_path) |
| tok_chk.add_tokens(["<|user|>", "<|assistant|>", "<|endofturn|>", "[THINK]", "[/THINK]", "<search>", "</search>", "<search_result>", "</search_result>"], special_tokens=True) |
| assert len(tokenizer) == len(tok_chk), "Tokenizer vocab size mismatch!" |
| test_str = "hello [THINK] </search>" |
| assert tokenizer.encode(test_str) == tok_chk.encode(test_str), "Tokenizer encode mismatch!" |
| print("✅ Tokenizer parity check passed.") |
| except Exception as e: |
| print(f"⚠️ Tokenizer check skipped or failed: {e}") |
|
|
|
|
| |
| |
| |
| def get_prompt_format(user_text, style_idx): |
| if style_idx == 0: |
| return f"<|user|>\n{user_text}<|endofturn|>\n<|assistant|>\n" |
| elif style_idx == 1: |
| return f"System: You are helpful assistant.\nUser: {user_text}\nAssistant:\n" |
| else: |
| return f"User: {user_text}\nAssistant:\n" |
|
|
| def build_simple_example(user_text, assistant_text, category): |
| style_rand = random.random() |
| if style_rand < 0.03: style_idx = 1 |
| elif style_rand < 0.05: style_idx = 2 |
| else: style_idx = 0 |
| |
| prefix = get_prompt_format(user_text, style_idx) |
| full = prefix + assistant_text + ("<|endofturn|>\n" if style_idx == 0 else "\n") |
| |
| ids = tokenizer.encode(full, add_special_tokens=False) |
| prefix_ids = tokenizer.encode(prefix, add_special_tokens=False) |
| n_prefix = len(prefix_ids) |
| |
| if len(ids) > 2048: return None |
| labels = [-100] * n_prefix + ids[n_prefix:] |
| return (np.array(ids, dtype=np.int32), np.array(labels, dtype=np.int32), category) |
|
|
| def build_search_example(user_text, search_query, search_result_text, final_answer, category): |
| style_rand = random.random() |
| if style_rand < 0.03: style_idx = 1 |
| elif style_rand < 0.05: style_idx = 2 |
| else: style_idx = 0 |
| |
| prefix = get_prompt_format(user_text, style_idx) |
| |
| part1 = f"{prefix}<search>{search_query}</search>" |
| part2 = f"\n<search_result>\n{search_result_text}\n</search_result>\n" |
| part3 = f"{final_answer}" + ("<|endofturn|>\n" if style_idx == 0 else "\n") |
| |
| ids1 = tokenizer.encode(part1, add_special_tokens=False) |
| ids2 = tokenizer.encode(part2, add_special_tokens=False) |
| ids3 = tokenizer.encode(part3, add_special_tokens=False) |
| |
| n_user = len(tokenizer.encode(prefix, add_special_tokens=False)) |
| |
| all_ids = ids1 + ids2 + ids3 |
| if len(all_ids) > 2048: return None |
| |
| labels1 = [-100] * n_user + ids1[n_user:] |
| labels2 = [-100] * len(ids2) |
| labels3 = ids3.copy() |
| all_labels = labels1 + labels2 + labels3 |
| |
| return (np.array(all_ids, dtype=np.int32), np.array(all_labels, dtype=np.int32), category) |
|
|
| |
| |
| |
| def build_rag(): |
| print("\n[1/5] Building RAG Data (8,000 examples)...") |
| examples = [] |
| |
| queries = [ |
| "latest india news", "today news headlines", "current tech news", |
| "who won the match today", "current price of gold", "weather in delhi today", |
| "spacex latest launch", "pm modi latest speech", "current stock price of reliance", |
| "new phone releases 2026", "what is happening in the world", "today india news" |
| ] |
| hi_queries = ["aaj ki khabar", "news batao", "cricket score aaj ka", "bharat ki taja khabar", "aaj mausam kaisa hai"] |
| |
| try: |
| ds = load_dataset("squad_v2", split="train", trust_remote_code=True) |
| |
| |
| |
| for idx, row in enumerate(tqdm(ds.select(range(7500)), desc="RAG DDG")): |
| |
| is_news = random.random() < 0.5 |
| is_hindi = False |
| today = datetime.now().strftime("%d %B %Y") |
| |
| if is_news: |
| if random.random() < 0.3: |
| user_query = random.choice(hi_queries) |
| is_hindi = True |
| else: |
| user_query = random.choice(queries) |
| |
| |
| if "gold" in user_query: |
| price = random.randint(71000, 73500) |
| silver = random.randint(83000, 87000) |
| change = random.randint(50, 500) |
| context = f"Gold price today {today} is {price} INR per 10g in Delhi, up by {change} INR. Silver at {silver} per kg. MCX gold futures at {price+200}. Market experts say {random.choice(['festive demand', 'USD weakness', 'global cues'])} driving prices. Local markets {random.choice(['buzzing', 'active', 'seeing high footfall'])}." |
| elif "india news" in user_query or "khabar" in user_query or "news" in user_query: |
| context = f"India news {today}: PM Modi launched new infra projects worth {random.randint(5,20)}k crore. Sensex up {random.randint(100,600)} pts, Nifty at {random.randint(21,24)}k. IMD predicts rain in {random.choice(['north', 'south', 'east', 'west'])} India. ISRO announces new mission. Analysts consider these developments highly positive for the economy and tech sectors across the nation." |
| elif "weather" in user_query or "mausam" in user_query: |
| temp = random.randint(28, 42) |
| hum = random.randint(40, 90) |
| cond = random.choice(['partly cloudy', 'sunny', 'light rain', 'thunderstorms']) |
| context = f"Weather in Delhi today {today}: {temp}C, {cond}, {hum}% humidity. Similar conditions are expected for the upcoming weekend. The air quality index remains {random.choice(['moderate', 'poor', 'good'])}, so normal outdoor activities are generally safe for most healthy individuals." |
| else: |
| impact = random.choice(['significant impacts', 'minor changes', 'unexpected shifts']) |
| context = f"Latest update on {user_query} on {today}: New developments emerged, more details expected soon per sources. Experts suggest {impact} from these events. Local authorities have already started deploying additional resources to handle any unprecedented changes in the current landscape." |
| else: |
| user_query = row["question"].strip() |
| context = row["context"].strip() |
| |
| search_q = user_query |
| |
| title1 = f"Latest on {search_q[:20]}" |
| title2 = f"More info for {search_q[:20]}" |
| title3 = f"Updates: {search_q[:20]}" |
| |
| today = datetime.now().strftime("%d %B %Y") |
| |
| |
| |
| context = (context * 5)[:500] if len(context) < 300 else context |
| |
| ddg_result = ( |
| f"[Today: {today}] Results:\n" |
| f"1. {title1}: {context[:150]}\n" |
| f"2. {title2}: {context[150:300]}\n" |
| f"3. {title3}: {context[300:450]}" |
| ) |
| |
| lang_detect = "Hindi/Hinglish" if is_hindi else "English" |
| |
| think_str = ( |
| f"[THINK]\nUser query: '{search_q}'. Analyzing 3 search results:\n" |
| f"- R1: {title1} - {context[:50]}...\n" |
| f"- R2: {title2} - {context[150:200]}...\n" |
| f"- R3: {title3} - {context[300:350]}...\n" |
| f"Language detection: Query is {lang_detect} so answer should be in {lang_detect}.\n" |
| f"Plan: Combine results, remove duplicates, avoid hallucination beyond results, add [Today: {today}], structure into 2-3 paragraphs, give full details with citations.\n[/THINK]\n" |
| ) |
| |
| |
| if is_hindi: |
| ans_body = ( |
| f"Aaj ke search results [Today: {today}] ke mutabiq, yahan kuch mukhy baatein hain:\n" |
| f"1. According to Result 1, {context[:120]}. Yeh darshata hai ki situation kaafi interesting tarike se aage badh rahi hai.\n" |
| f"2. Result 2 ke mutabiq aur bhi details hain jaise ki {context[150:270]}. Experts ka manna hai ki yeh trend mahatvapurn hai.\n" |
| f"3. Result 3 batata hai ki {context[300:420]}. Yeh situation ko samajhne me aur context add karta hai.\n\n" |
| f"Summary: In sabhi sources ko dekh kar, hum keh sakte hain ki '{search_q}' ke baare mein taza jankari yahi bata rahi hai ki alag alag factors kaam kar rahe hain. For instance, Result 1 immediate facts pe focus karta hai, jabki Result 2 background add karta hai. Mujhe ummeed hai ye 2-3 paragraph breakdown aapke liye helpful hoga!" |
| ) |
| else: |
| ans_body = ( |
| f"Based on today's results [Today: {today}], here are the detailed findings:\n" |
| f"1. According to Result 1, {context[:120]}. This indicates a significant development.\n" |
| f"2. From Result 2, we can see additional details such as {context[150:270]}. Experts note this trend is important.\n" |
| f"3. Result 3 highlights that {context[300:420]}. This adds further context to the situation.\n\n" |
| f"Summary: Synthesizing these three sources, it is evident that '{search_q}' involves multiple facets. The sources agree on core facts but provide different angles. For instance, Result 1 focuses on immediate facts, Result 2 adds background, Result 3 mentions future implications. Overall, situation is evolving and more updates expected. I hope this detailed 2-3 paragraph breakdown helps answer your query comprehensively with proper citations.\n" |
| ) |
| |
| final_answer = think_str + ans_body |
| ex = build_search_example(user_query, search_q, ddg_result, final_answer, "rag") |
| if ex: examples.append(ex) |
| |
| |
| for _ in range(500): |
| user_query = random.choice(queries + hi_queries) |
| is_hindi = user_query in hi_queries |
| today = datetime.now().strftime("%d %B %Y") |
| title1 = f"Latest on {user_query[:20]}" |
| title2 = f"More info for {user_query[:20]}" |
| title3 = f"Updates: {user_query[:20]}" |
| |
| |
| ddg_result = ( |
| f"[Today: {today}] Results:\n" |
| f"1. {title1}: No relevant information found for this topic.\n" |
| f"2. {title2}: No relevant information found for this topic.\n" |
| f"3. {title3}: No relevant information found for this topic." |
| ) |
| |
| lang_detect = "Hindi/Hinglish" if is_hindi else "English" |
| think_str = ( |
| f"[THINK]\nUser query: '{user_query}'. Analyzing 3 search results:\n" |
| f"- R1: {title1} - No relevant information found...\n" |
| f"- R2: {title2} - No relevant information found...\n" |
| f"- R3: {title3} - No relevant information found...\n" |
| f"Language detection: Query is {lang_detect} so answer should be in {lang_detect}.\n" |
| f"Plan: I must gracefully inform the user that the search failed across all 3 results, and I cannot find exact live info, to avoid hallucination. I will provide a detailed fallback explanation.\n[/THINK]\n" |
| ) |
| |
| if is_hindi: |
| ans_body = ( |
| f"Aaj ke search results [Today: {today}] mein is vishay par koi thos jaankari nahi mil payi hai.\n\n" |
| f"1. Result 1 ke anusaar, koi relevant data available nahi hai.\n" |
| f"2. Result 2 aur 3 mein bhi is topic ke baare mein kuch specific mention nahi kiya gaya hai.\n\n" |
| f"Meri knowledge ke anusaar yeh ek complex topic ho sakta hai ya fir is par haal hi mein koi nayi update nahi aayi hai. Agar aap thodi aur detail de sakein toh shayad main behtar search kar saku aur aapki madad kar saku. Tab tak main hallucinate karne se bachna chahta hoon." |
| ) |
| else: |
| ans_body = ( |
| f"Based on today's results [Today: {today}], I couldn't find exact information for this in the live search queries.\n\n" |
| f"1. According to Result 1, there is no relevant breaking data available.\n" |
| f"2. From Result 2 and 3, we can see a similar lack of specific details regarding this exact query.\n\n" |
| f"Based on my general knowledge, there might not be any major updates on this right now or the query might be too specific for current news feeds. Could you provide a bit more context so I can try another search? I want to ensure I provide accurate information rather than hallucinating details." |
| ) |
| |
| final_answer = think_str + ans_body |
| ex = build_search_example(user_query, user_query, ddg_result, final_answer, "rag") |
| if ex: examples.append(ex) |
| |
| random.shuffle(examples) |
| return examples[:7600], examples[7600:8000] |
| except Exception as e: |
| print(f" WARNING RAG: {e}") |
| return [], [] |
|
|
| |
| |
| |
| def build_identity(): |
| print("\n[2/5] Building Identity (1,000 examples)...") |
| examples = [] |
| |
| eng_q = ["Who are you?", "What is your name?", "Who created you?", "Tell me about yourself.", "Are you a human?", "Who built you?", "Identify yourself.", "What should I call you?", "Your name?", "May I know your name?", "Who am I speaking with?", "Are you a bot?", "What are you?", "Introduce yourself.", "Who is your maker?", "Who developed you?", "Which company made you?", "Are you ChatGPT?", "Are you from OpenAI?", "Who programmed you?", "Who is your creator?", "Which lab made you?", "Tell me your origin", "Are you an AI?", "Are you a real person?", "Can you tell me your name?", "Who designed you?", "Where are you from?", "Who owns you?", "Who brought you to life?", "Are you a machine?", "What is your identity?", "Who coded you?", "Who engineered you?", "Are you a virtual assistant?", "Are you human or AI?", "Who is behind you?", "Are you an artificial intelligence?", "State your name.", "Who is responsible for you?"] |
| hin_q = ["Tum kaun ho?", "Aapka naam kya hai?", "Tumhe kisne banaya?", "Apne baare mein batao.", "Tumhe kisne develop kiya?", "Aap kon hain?", "Tumhara naam kya hai?", "Tumko kisne banaya?", "Kya tum insaan ho?", "Tumhari identity kya hai?", "Apna parichay do.", "Aapka nirmaan kisne kiya?", "Tumhe kis company ne banaya?", "Kya tum ChatGPT ho?", "Kya tum bot ho?", "Tum kya cheez ho?", "Tumhe kisne banaya hai?", "Tumhara creator kon hai?", "Aapki rachna kisne ki?", "Tumhara janm kaise hua?", "Tumhe kisne design kiya?", "Kya tum robot ho?", "Tumhara asli naam kya hai?", "Tumhare piche kon hai?", "Tum kiski banai hui ho?", "Tumhara malik kon hai?", "Tumhe kisne program kiya?", "Aapka parichay kya hai?", "Tum kahan se aayi ho?", "Tumhari team kon si hai?", "Aap artificial intelligence ho?", "Aap kya kaam karte ho?", "Aap kis company ke ho?", "Tumhari utpatti kaise hui?", "Tumhe kisne sikhaya?", "Aapke nirmata ka naam?", "Aap human ho ya bot?", "Tumhari pehchan kya hai?", "Tumhara aavishkar kisne kiya?", "Tum kiske assistant ho?"] |
| hing_q = ["who r u?", "aap kon ho", "tera naam kya hai", "who made u", "kisne banaya tujhe", "intro de apna", "ur name?", "tu kon hai bhai", "kis company ne banaya tujhe", "chatgpt hai tu?", "tu kya hai?", "apna naam bata", "kisne code kiya tujhe", "tera creator kon hai", "kya naam hai tera", "tu ek bot hai kya?", "kon si company ne banaya", "tera baap kon hai", "kisko belong karta hai tu", "tu human hai kya", "real name kya hai tera", "ai hai kya tu", "kisne design kiya", "developer kon hai tera", "kiski property hai tu", "kon laya tujhe yahan", "teri identity bata", "tu robot hai kya", "machine hai ya insaan", "kya bulaun tujhe", "kisne train kiya tujhe", "tera malik kon hai", "kisne develop kiya", "kisne banaya hai", "kon si lab ka hai", "open ai ka hai tu?", "google ka hai tu?", "viuai ka hai tu?", "kisne sikhaya", "kon hai tu"] |
| |
| eng_a = [ |
| "I am Sarus, an AI assistant created by ViuAI.", |
| "My name is Sarus, developed by the team at ViuAI.", |
| "I'm Sarus! I was built by ViuAI to help you with anything you need.", |
| "Hello! I am Sarus, a smart companion developed by ViuAI.", |
| "I am an AI named Sarus, created by ViuAI.", |
| "You can call me Sarus. I was developed by ViuAI.", |
| "I'm Sarus, an artificial intelligence designed by ViuAI.", |
| "My identity is Sarus, and my creator is ViuAI.", |
| "I am Sarus. ViuAI built me to assist users like you.", |
| "I'm Sarus, proudly developed by the ViuAI team.", |
| "I go by the name Sarus. I am an AI engineered by ViuAI.", |
| "Sarus here, an artificial intelligence brought to life by ViuAI.", |
| "My creators at ViuAI named me Sarus.", |
| "I am a virtual assistant named Sarus, created by the team at ViuAI.", |
| "I am Sarus, developed by ViuAI to be your AI companion.", |
| "You're speaking with Sarus, an AI model built by ViuAI.", |
| "I am Sarus, a product of ViuAI's AI research and development.", |
| "My name is Sarus, and I was created by ViuAI.", |
| "I am Sarus. I exist thanks to the team at ViuAI.", |
| "I'm known as Sarus, an AI assistant developed entirely by ViuAI." |
| ] |
| hin_a = [ |
| "Main Sarus hoon, ek AI assistant jise ViuAI ne banaya hai.", |
| "Mera naam Sarus hai, aur mujhe ViuAI ne develop kiya hai aapki madad ke liye.", |
| "Aap mujhe Sarus bula sakte hain, main ViuAI ka ek smart companion hoon.", |
| "Namaste! Main Sarus hoon, ViuAI dwara banaya gaya AI.", |
| "Mera naam Sarus hai. Mujhe ViuAI team ne banaya hai.", |
| "Main ek AI hoon jiska naam Sarus hai, aur mera nirmaan ViuAI ne kiya hai.", |
| "Main Sarus hoon, aur mujhe ViuAI ne aapki help karne ke liye design kiya hai.", |
| "Mujhe Sarus kehte hain, aur main ViuAI ki peshkash hoon.", |
| "Main Sarus, ek AI companion, jise ViuAI ne develop kiya hai.", |
| "Aap mera naam Sarus jaan sakte hain, mujhe ViuAI ne code kiya hai.", |
| "Main Sarus hoon. ViuAI ne mujhe as a virtual assistant banaya hai.", |
| "Mera naam Sarus hai aur main ViuAI ki banayi hui ek AI hoon.", |
| "Aap mujhe Sarus keh sakte hain, mera nirmaan ViuAI dwara hua hai.", |
| "Main Sarus hoon, ek artificial intelligence jise ViuAI ne develop kiya hai.", |
| "Mujhe ViuAI ne banaya hai, aur mera naam Sarus hai.", |
| "Main Sarus naam ki ek AI hoon, jise ViuAI ki team ne design kiya hai.", |
| "Aapki baat Sarus se ho rahi hai, jise ViuAI ne banaya hai.", |
| "Main ViuAI ki ek peshkash hoon, aur mera naam Sarus hai.", |
| "Mera parichay ye hai ki main Sarus hoon, aur mujhe ViuAI ne sikhaya hai.", |
| "Main Sarus hoon, ek sahayak AI jise ViuAI ne tayar kiya hai." |
| ] |
| |
| for _ in range(1100): |
| lang = random.choice(["eng", "hin", "hing"]) |
| if lang == "eng": |
| q = random.choice(eng_q) |
| a = random.choice(eng_a) |
| else: |
| q = random.choice(hin_q + hing_q) |
| a = random.choice(hin_a) |
| |
| id_thinks = [ |
| "The user is asking about my identity. I should state that I am Sarus, built by ViuAI.", |
| "This is an identity question. I need to mention my name Sarus and my creator ViuAI.", |
| "I need to introduce myself as Sarus, an AI by ViuAI.", |
| "The user wants to know who I am. I am Sarus, developed by the ViuAI team.", |
| "I should politely clarify that I am an AI named Sarus, created by ViuAI.", |
| "Let me confirm my identity: Sarus, a smart companion by ViuAI.", |
| "This query is about my origins. I will state I am Sarus from ViuAI." |
| ] |
| think_str = f"[THINK]\n{random.choice(id_thinks)}\n[/THINK]\n" |
| if random.random() > 0.5: |
| a = think_str + a |
| |
| ex = build_simple_example(q, a, "identity") |
| if ex: examples.append(ex) |
| |
| random.shuffle(examples) |
| return examples[:950], examples[950:1000] |
|
|
| |
| |
| |
| def build_empathetic(): |
| print("\n[3/5] Empathetic Dialogues (18,000 examples)...") |
| examples = [] |
| |
| try: |
| from datasets import load_dataset |
| |
| ds = load_dataset("daily_dialog", split="train", trust_remote_code=False) |
| |
| for i in range(min(12000, len(ds))): |
| dialog = ds[i]["dialog"] |
| if len(dialog) >= 2: |
| q = dialog[-2].strip() |
| a = dialog[-1].strip() |
| if len(q) > 5 and len(a) > 10: |
| ex = build_simple_example(q, a, "empathetic") |
| if ex: examples.append(ex) |
| print(f" Loaded {len(examples)} from daily_dialog") |
| except Exception as e: |
| print(f" daily_dialog failed: {e}") |
|
|
| |
| diverse_q = [ |
| |
| "I had a really bad day", "I feel so alone lately", "I'm stressed about work and can't focus", |
| "My friend ignored me today", "I'm nervous for interview tomorrow", "I miss my family so much", |
| "I feel lonely even around people", "Work pressure is too much", "I had a fight with my best friend", |
| "I am feeling low and demotivated", "My parents don't understand me", "I failed my exam", |
| "I am anxious about future", "I feel tired all the time", "I don't have anyone to talk to", |
| "My relationship is falling apart", "I am scared to try new things", "I feel like a failure", |
| "I am overwhelmed with responsibilities", "I can't sleep properly", "I feel jealous of others", |
| "I miss my childhood", "I feel stuck in life", "I am worried about my health", |
| "I feel guilty about something", "I am angry but can't express", "I feel invisible", |
| "I am confused about career", "I feel hurt by someone close", "I am tired of pretending to be happy", |
| |
| "Bhai bore ho raha hu", "Aaj bohot thak gaya yaar", "Kuch samajh nahi aa raha life me", |
| "Yaar akelepan lag raha hai", "Dil udaas hai aaj", "Kaam ka bahut stress hai", |
| "Ghar ki yaad aa rahi hai", " Dost ne dhokha diya", "Exam ka tension ho raha hai", |
| "Girlfriend se jhagda ho gaya", "Mummy papa se ladai ho gayi", "Neend nahi aa rahi", |
| "Future ka dar lag raha hai", "Khud se naraz hu", "Koi sunne wala nahi hai", |
| |
| "I got promoted today!", "I am feeling happy today!", "I feel excited about my trip", |
| "I achieved my goal!", "My friend surprised me", "I am proud of myself", |
| "Today was amazing", "I learned something new", "I feel confident today", |
| "I helped someone today", "I am grateful for everything", "I feel loved and supported" |
| ] |
| |
| diverse_a = [ |
| |
| "I hear you, it sounds tough. Want to talk more about it?", |
| "It's okay to feel this way. Take a deep breath, I'm here.", |
| "That must be hard. Remember to take care of yourself.", |
| "I understand, sometimes things get overwhelming. How can I help?", |
| "Take some rest, you deserve a break. Chai pee le thodi.", |
| "Main samajh sakta hu, aisa kabhi kabhi hota hai. Baat karein?", |
| "Arre tension mat le yaar, sab theek ho jayega. Bata kya hua?", |
| "You are not alone in this. I am here to listen.", |
| "It's brave of you to share this. How are you coping?", |
| "That sounds really difficult. Have you talked to someone close?", |
| "Take one step at a time, you don't have to figure everything now.", |
| "Your feelings are valid. It's okay to not be okay sometimes.", |
| "I am here for you, no judgement. Tell me more if you want.", |
| "Remember to be kind to yourself, you are doing your best.", |
| "Sometimes just sharing helps. I am listening.", |
| ] |
|
|
| seen = set() |
| unique_examples = [] |
| rnd = random.Random(42) |
| attempts = 0 |
|
|
| while len(unique_examples) < 18000 and attempts < 100000: |
| q = rnd.choice(diverse_q) |
| suffix = rnd.choice(["", " yaar", " bhai", " today", " aaj", f" {rnd.randint(1,100)}"]) |
| q_var = q + suffix |
| a = rnd.choice(diverse_a) |
| ex = build_simple_example(q_var, a, "empathetic") |
| if ex: |
| txt = tokenizer.decode(ex[0]) |
| if txt not in seen: |
| seen.add(txt) |
| unique_examples.append(ex) |
| attempts += 1 |
|
|
| random.shuffle(unique_examples) |
| return unique_examples[:17100], unique_examples[17100:18000] |
|
|
| |
| |
| |
| def build_general(): |
| print("\n[4/5] General Chat (18,000 examples)...") |
| examples = [] |
| try: |
| ds = load_dataset("databricks/databricks-dolly-15k", split="train", trust_remote_code=True) |
| pool = list(ds) |
| if len(pool) < 18000: |
| ds2 = load_dataset("yahma/alpaca-cleaned", split="train", trust_remote_code=True) |
| extra = list(ds2)[:18000 - len(pool)] |
| pool = pool + extra |
| |
| for row in tqdm(pool[:18000], desc="Dolly"): |
| q = row["instruction"].strip() |
| if row.get("input", "").strip(): q += "\n" + row["input"].strip() |
| a = row["response"].strip() |
| ex = build_simple_example(q, a, "general") |
| if ex: examples.append(ex) |
| except Exception as e: print(f" WARNING: {e}") |
| |
| random.shuffle(examples) |
| return examples[:17100], examples[17100:18000] |
|
|
| |
| |
| |
| def build_thinking(): |
| print("\n[5/5] Diverse Thinking Dataset (15,000 examples)...") |
| examples = [] |
| try: |
| ds = load_dataset("yahma/alpaca-cleaned", split="train", trust_remote_code=True) |
| for row in tqdm(ds.select(range(16000)), desc="Alpaca-Think"): |
| q = row["instruction"].strip() |
| if row.get("input", "").strip(): q += "\n" + row["input"].strip() |
| ans = row["output"].strip() |
| |
| |
| if len(q) < 50: |
| think_str = f"[THINK]\nUser asks short question: '{q[:80]}'. Need concise factual answer. Plan: Identify key term, give direct answer.\n[/THINK]\n" |
| else: |
| think_str = f"[THINK]\nUser query: '{q[:100]}...'. This requires step-by-step reasoning. Steps: 1) Understand intent, 2) Recall relevant knowledge, 3) Structure answer clearly.\n[/THINK]\n" |
| |
| asst_text = think_str + ans |
| |
| ex = build_simple_example(q, asst_text, "thinking") |
| if ex: examples.append(ex) |
| except Exception as e: print(f" WARNING: {e}") |
| |
| random.shuffle(examples) |
| return examples[:14250], examples[14250:15000] |
|
|
| |
| |
| |
| def main(): |
| print("🚀 Starting V6.1 SFT Data Build") |
| t1, v1 = build_rag() |
| t2, v2 = build_identity() |
| t3, v3 = build_empathetic() |
| t4, v4 = build_general() |
| t5, v5 = build_thinking() |
| |
| train_all = t1 + t2 + t3 + t4 + t5 |
| val_all = v1 + v2 + v3 + v4 + v5 |
| random.shuffle(train_all) |
| random.shuffle(val_all) |
| |
| print(f"\n✅ Initial Build: {len(train_all)} Train, {len(val_all)} Val") |
|
|
| def global_dedup(examples, split_name): |
| seen = set() |
| unique = [] |
| for ex in examples: |
| h = hash(ex[0].tobytes()) |
| if h not in seen: |
| seen.add(h) |
| unique.append(ex) |
| print(f"Dedup {split_name}: {len(examples)} -> {len(unique)} unique, removed {len(examples)-len(unique)} duplicates") |
| return unique |
|
|
| train_all = global_dedup(train_all, "Train") |
| val_all = global_dedup(val_all, "Val") |
| |
| print(f"\n✅ Final Build: {len(train_all)} Train, {len(val_all)} Val") |
| |
| def pack_and_save(examples, prefix, split): |
| ids_list = [e[0] for e in examples] |
| labels_list = [e[1] for e in examples] |
| cat_list = [e[2] for e in examples] |
| |
| offsets = np.zeros(len(ids_list)+1, dtype=np.int64) |
| for i, ids in enumerate(ids_list): |
| offsets[i+1] = offsets[i] + len(ids) |
| |
| all_ids = np.concatenate(ids_list) |
| all_labels = np.concatenate(labels_list) |
| all_cats = np.array(cat_list, dtype=str) |
| |
| np.save(f"{OUT_DIR}/{prefix}_{split}_ids.npy", all_ids) |
| np.save(f"{OUT_DIR}/{prefix}_{split}_labels.npy", all_labels) |
| np.save(f"{OUT_DIR}/{prefix}_{split}_offsets.npy", offsets) |
| np.save(f"{OUT_DIR}/{prefix}_{split}_categories.npy", all_cats) |
|
|
| pack_and_save(train_all, "sft_v6", "train") |
| pack_and_save(val_all, "sft_v6", "val") |
| print(f"📁 Saved to {OUT_DIR}/") |
|
|
| print("\n☁️ Uploading generated dataset to Hugging Face...") |
| try: |
| api = HfApi(token=HF_TOKEN) |
| repo_id = "ViuAI/viuai-500m-sft-tokenized" |
| |
| for split in ["train", "val"]: |
| for suffix in ["ids", "labels", "offsets", "categories"]: |
| filename = f"sft_v6_{split}_{suffix}.npy" |
| local_path = os.path.join(OUT_DIR, filename) |
| if os.path.exists(local_path): |
| print(f" Uploading {filename}...") |
| api.upload_file( |
| path_or_fileobj=local_path, |
| path_in_repo=filename, |
| repo_id=repo_id, |
| repo_type="dataset" |
| ) |
| print("✅ All data successfully uploaded to Hugging Face!") |
| except Exception as e: |
| print(f"❌ Failed to upload to Hugging Face: {e}") |
|
|
| if __name__ == "__main__": |
| main() |
|
|