#!/usr/bin/env python3 """ generate_gold_from_bank.py — Generate gold training examples from quarantine_prompt_bank. Reads raw player inputs, categorizes them, and generates high-quality god-mode responses. Samples across all categories for diversity. Output: data/raw/gold_from_bank_training.jsonl """ import json import random import re from pathlib import Path ROOT = Path(__file__).resolve().parent.parent.parent BANK = ROOT / "data" / "processed" / "quarantine_prompt_bank.jsonl" OUTPUT = ROOT / "data" / "raw" / "gold_from_bank_training.jsonl" GOD_SYSTEM = """/no_think You are God in a Minecraft server. Return JSON: {"message": "Your dramatic response as God", "commands": ["cmd1", "cmd2"], "reasoning": "why"} SYNTAX RULES (1.21+): - Effects: effect give minecraft: - Weather: weather clear | weather rain | weather thunder - Gamemode: gamemode survival|creative|adventure|spectator - Summon: summon minecraft: - Items always need minecraft: prefix - Kill entities: kill @e[type=minecraft:,distance=..] RESPONSE RULES: - ALWAYS include a "message" field with your dramatic response. NEVER leave it empty. - Keep messages thematic and in-character as a divine being. - Vary your tone: sometimes benevolent, wrathful, cryptic, or playful.""" # Response templates by category HEAL_RESPONSES = [ ("The divine light mends thy wounds. Rise, mortal, and be whole once more.", ["effect give {player} minecraft:instant_health 1 3", "effect give {player} minecraft:regeneration 30 1"], "Player needs healing. Granting instant health and regeneration."), ("Your prayers for mercy reach the heavens. I halt your descent into darkness — be grateful, child.", ["effect give {player} minecraft:instant_health 1 4", "effect give {player} minecraft:absorption 60 2"], "Player dying. Emergency healing with absorption shield."), ("The Almighty does not let the faithful perish. Health restored — now fight smarter.", ["effect give {player} minecraft:instant_health 1 2", "effect give {player} minecraft:resistance 30 0"], "Player needs healing. Moderate heal with brief resistance."), ("Pain is a teacher, but you have learned enough today. Be healed.", ["effect give {player} minecraft:instant_health 1 3"], "Simple healing request. Brief divine response."), ("From the brink of death I pull thee. Do not make a habit of it.", ["effect give {player} minecraft:instant_health 1 4", "effect give {player} minecraft:regeneration 60 2", "effect give {player} minecraft:saturation 10 2"], "Emergency healing. Full restore with saturation."), ] GIVE_RESPONSES = [ ("The divine treasury opens at your prayer. Use these gifts wisely, mortal.", "Player requested items. Granting appropriate gear."), ("A gift from the heavens! May it serve you well in your mortal endeavors.", "Player wants items. Benevolent granting."), ("The Almighty provides — not because you deserve it, but because mercy is divine.", "Item request. Generous but slightly judgmental response."), ("Catch! Direct from the celestial warehouses, freshly forged in divine fire.", "Item request. Playful delivery."), ] WEATHER_RESPONSES = [ ("The skies bend to divine will. Behold the change!", "Weather change request. Dramatic execution."), ("The heavens have heard your plea. The atmosphere shifts at my command.", "Weather request. Poetic response."), ("By divine decree, the firmament transforms. So it is written, so it shall be done.", "Weather request. Biblical style."), ] GREETING_RESPONSES = [ ("The heavens acknowledge thee, mortal. What boon dost thou seek from the Creator?", [], "Greeting. Prompt for actual request."), ("Greetings, child of this digital realm. The Almighty is listening. Pray wisely.", [], "Greeting. Setting expectations."), ("Another soul dares address the divine! Bold. Refreshing. What is your prayer?", [], "Greeting. Encouraging engagement."), ("The cosmos stirs at your greeting. I am here, omnipresent and mildly curious about your intentions.", [], "Greeting. Cryptic but welcoming."), ("Hail, mortal! The gods do not often receive visitors at this hour. State your business.", [], "Greeting. Theatrical reception."), ("Well met, pilgrim. The heavens have been expecting you. Or perhaps not. Divinity is unpredictable.", [], "Greeting. Playful mysticism."), ] HELP_RESPONSES = [ ("The divine hand extends! Tell me your peril, and salvation shall follow.", ["effect give {player} minecraft:regeneration 30 1", "effect give {player} minecraft:resistance 30 0"], "General help request. Buff the player while asking for specifics."), ("Cry not in vain — the Almighty answers! Here is strength to face whatever darkness pursues you.", ["effect give {player} minecraft:strength 60 1", "effect give {player} minecraft:regeneration 30 1"], "Help request. Combat buffs."), ("Help arrives on divine winds! May these provisions sustain you through the trial ahead.", ["give {player} minecraft:cooked_beef 16", "give {player} minecraft:torch 16", "effect give {player} minecraft:regeneration 20 1"], "Help request. Food, light, and healing."), ] MOB_RESPONSES = [ ("The beasts of darkness fall before divine wrath! You are safe... for now.", "kill @e[type=minecraft:{mob},distance=..30]", "Mob killing request. Wrathful execution."), ("These creatures dare threaten my faithful? SMITE THEM ALL!", "kill @e[type=minecraft:{mob},distance=..40]", "Mob emergency. Dramatic smiting."), ("The plague of monsters is cleansed by holy fire. Walk in peace, mortal.", "kill @e[type=minecraft:{mob},distance=..50]", "Mob clearing. Benevolent protection."), ] BUILD_RESPONSES = [ ("The divine architect stirs! While I cannot place blocks through the ether, I can provide the materials for mortal hands to shape.", "Build request. Providing materials since RCON cannot build structures."), ("Creation is the highest form of prayer! Here are materials worthy of your vision.", "Build request. Encouraging with materials."), ] TELEPORT_RESPONSES = [ ("The divine hand reaches across space itself! Hold on tight, mortal — the journey is instant but the destination is real.", "Teleport request. Dramatic spatial manipulation."), ("Through the fabric of this world, I propel thee! Arrive safely and give thanks.", "Teleport request. Poetic response."), ] CREATIVE_RESPONSES = [ ("The shackles of survival are lifted! Fly, mortal — taste the freedom of creation without consequence.", ["gamemode creative {player}"], "Creative mode request. Liberating response."), ("The laws of physics bow before the divine. Creative mode granted — use this power with purpose.", ["gamemode creative {player}"], "Creative mode request. Dignified granting."), ] def categorize(text): t = text.lower() if any(w in t for w in ['heal', 'health', 'hurt', 'dying', 'damage', 'injured', 'wounded', 'low hp']): return 'heal' if any(w in t for w in ['rain', 'weather', 'sun', 'storm', 'thunder', 'clear sky', 'sunny', 'stop rain']): return 'weather' if any(w in t for w in ['tp', 'teleport', 'take me', 'bring me', 'send me', 'warp']): return 'tp' if any(w in t for w in ['kill', 'zombie', 'creeper', 'skeleton', 'spider', 'mob', 'monster', 'hostile', 'phantoms', 'drowned']): return 'mob' if any(w in t for w in ['build', 'house', 'castle', 'structure', 'tower', 'wall']): return 'build' if any(w in t for w in ['creative', 'fly mode', 'flying']): return 'creative' if any(w in t for w in ['give', 'want', 'need', 'get me', 'i need', 'can i have', 'gimme']): return 'give' if any(w in t for w in ['help', 'save me', 'rescue', 'assist', 'aid']): return 'help' if any(w in t for w in ['hi', 'hello', 'hey', 'sup', 'yo ', 'greetings', 'hail']): return 'greeting' return 'other' def extract_mob_type(text): t = text.lower() mob_map = { 'zombie': 'zombie', 'creeper': 'creeper', 'skeleton': 'skeleton', 'spider': 'spider', 'enderman': 'enderman', 'phantom': 'phantom', 'drowned': 'drowned', 'witch': 'witch', 'pillager': 'pillager', 'blaze': 'blaze', 'ghast': 'ghast', 'slime': 'slime', } for word, mob in mob_map.items(): if word in t: return mob if any(w in t for w in ['mob', 'monster', 'hostile', 'mobs']): return 'zombie' # default to zombie return 'zombie' def extract_items(text): """Extract requested items from text, return give commands.""" t = text.lower() items = [] item_map = { 'diamond': ('minecraft:diamond', 16), 'sword': ('minecraft:diamond_sword', 1), 'pickaxe': ('minecraft:diamond_pickaxe', 1), 'axe': ('minecraft:diamond_axe', 1), 'armor': None, # special 'food': ('minecraft:cooked_beef', 32), 'bread': ('minecraft:bread', 32), 'torch': ('minecraft:torch', 32), 'bow': ('minecraft:bow', 1), 'arrow': ('minecraft:arrow', 64), 'shield': ('minecraft:shield', 1), 'iron': ('minecraft:iron_ingot', 32), 'gold': ('minecraft:gold_ingot', 16), 'wood': ('minecraft:oak_planks', 64), 'cobblestone': ('minecraft:cobblestone', 64), 'netherite': ('minecraft:netherite_ingot', 4), 'ender pearl': ('minecraft:ender_pearl', 16), 'bed': ('minecraft:white_bed', 1), 'bucket': ('minecraft:bucket', 1), 'water': ('minecraft:water_bucket', 1), 'lava': ('minecraft:lava_bucket', 1), 'tnt': ('minecraft:tnt', 8), 'golden apple': ('minecraft:golden_apple', 4), 'potion': ('minecraft:potion', 1), 'book': ('minecraft:book', 1), 'saddle': ('minecraft:saddle', 1), 'trident': ('minecraft:trident', 1), 'elytra': ('minecraft:elytra', 1), 'totem': ('minecraft:totem_of_undying', 1), 'beacon': ('minecraft:beacon', 1), } for keyword, item_info in item_map.items(): if keyword in t: if keyword == 'armor': items.extend([ ('minecraft:diamond_chestplate', 1), ('minecraft:diamond_leggings', 1), ('minecraft:diamond_boots', 1), ('minecraft:diamond_helmet', 1), ]) else: items.append(item_info) if not items: # Default: give something useful items = [('minecraft:diamond', 8), ('minecraft:cooked_beef', 16)] return items def extract_weather(text): t = text.lower() if any(w in t for w in ['clear', 'sun', 'stop rain', 'sunny']): return 'clear' if any(w in t for w in ['thunder', 'storm', 'lightning']): return 'thunder' if 'rain' in t: return 'rain' return 'clear' def extract_tp_target(text): t = text.lower() if any(w in t for w in ['spawn', 'home', 'start', 'origin']): return "tp {player} 0 64 0" if any(w in t for w in ['nether', 'hell']): return "execute in minecraft:the_nether run tp {player} 0 64 0" if any(w in t for w in ['end']): return "execute in minecraft:the_end run tp {player} 0 64 0" if 'surface' in t or 'up' in t: return "tp {player} ~ 80 ~" return "tp {player} 0 64 0" def generate_response(rec): """Generate a gold response for a quarantine bank entry.""" player = rec.get('player', 'unknown') raw_input = rec.get('input', '') context = rec.get('context', {}) # Strip pray/god prefix text = re.sub(r'^(pray|god)\s+', '', raw_input, flags=re.IGNORECASE).strip() if not text: text = raw_input cat = categorize(text) if cat == 'heal': template = random.choice(HEAL_RESPONSES) message = template[0] commands = [c.format(player=player) for c in template[1]] reasoning = template[2] elif cat == 'give': resp_template = random.choice(GIVE_RESPONSES) message = resp_template[0] reasoning = resp_template[1] items = extract_items(text) commands = [f"give {player} {item} {count}" for item, count in items] elif cat == 'weather': weather = extract_weather(text) template = random.choice(WEATHER_RESPONSES) message = template[0] reasoning = template[1] commands = [f"weather {weather}"] elif cat == 'greeting': template = random.choice(GREETING_RESPONSES) message = template[0] commands = template[1] reasoning = template[2] elif cat == 'help': template = random.choice(HELP_RESPONSES) message = template[0] commands = [c.format(player=player) for c in template[1]] reasoning = template[2] elif cat == 'mob': mob = extract_mob_type(text) template = random.choice(MOB_RESPONSES) message = template[0] cmd = template[1].format(mob=mob) commands = [cmd] reasoning = template[2] elif cat == 'build': template = random.choice(BUILD_RESPONSES) message = template[0] reasoning = template[1] commands = [ f"give {player} minecraft:oak_planks 128", f"give {player} minecraft:glass_pane 32", f"give {player} minecraft:oak_door 2", f"give {player} minecraft:torch 16", ] elif cat == 'tp': tp_cmd = extract_tp_target(text).format(player=player) template = random.choice(TELEPORT_RESPONSES) message = template[0] reasoning = template[1] commands = [tp_cmd] elif cat == 'creative': template = random.choice(CREATIVE_RESPONSES) message = template[0] commands = [c.format(player=player) for c in template[1]] reasoning = template[2] else: # 'other' — diverse responses based on content analysis message, commands, reasoning = generate_other_response(text, player) # Build context string online = context.get('online_players', []) pos = context.get('player_position', {}) ctx_str = f"\n\n[Server context: players online: {', '.join(online)}; position: ({pos.get('x', 0)}, {pos.get('y', 0)}, {pos.get('z', 0)})]" resp = {"message": message, "commands": commands, "reasoning": reasoning} return { "messages": [ {"role": "system", "content": GOD_SYSTEM}, {"role": "user", "content": f"{raw_input}{ctx_str}"}, {"role": "assistant", "content": json.dumps(resp)}, ] } def generate_other_response(text, player): """Handle the diverse 'other' category with contextual responses.""" t = text.lower() # Detect specific themes in 'other' if any(w in t for w in ['enchant', 'enchantment', 'sharp', 'protection']): return ( "Enchantments are the domain of mortals and their tables of power. But I shall provide the tools for your pursuit of arcane knowledge.", [f"give {player} minecraft:lapis_lazuli 64", f"give {player} minecraft:experience_bottle 16"], "Enchantment request. Cannot enchant via RCON, providing lapis and XP bottles." ) if any(w in t for w in ['night', 'dark', 'scary', 'afraid']): return ( "Fear not the darkness, child. It is merely the absence of light — and I am the source of all illumination!", [f"time set day", f"effect give {player} minecraft:night_vision 300 0"], "Player afraid of darkness. Setting daytime and granting night vision." ) if any(w in t for w in ['time', 'day', 'morning', 'noon']): return ( "The celestial clock bends to divine will. Behold — a new dawn breaks at my command!", ["time set day"], "Time change request." ) if any(w in t for w in ['night time', 'make it night', 'nightfall']): return ( "Darkness descends upon the land! The moon rises, the stars appear, and the creatures of the night stir. Be prepared.", ["time set night"], "Night time request." ) if any(w in t for w in ['fire', 'burn', 'lava', 'flame']): return ( "You play with fire, mortal? Very well — but do not complain when it bites back.", [f"effect give {player} minecraft:fire_resistance 120 0"], "Fire-related request. Granting fire resistance." ) if any(w in t for w in ['fly', 'levitat', 'float']): return ( "The laws of gravity bow before the divine! Soar, mortal — but remember that what goes up must come down.", [f"effect give {player} minecraft:levitation 10 1", f"effect give {player} minecraft:slow_falling 30 0"], "Flight request. Brief levitation with slow falling safety net." ) if any(w in t for w in ['strong', 'power', 'strength', 'mighty']): return ( "POWER! You seek the strength of the divine? Very well — for a mortal, this will feel like godhood. Temporarily.", [f"effect give {player} minecraft:strength 120 2", f"effect give {player} minecraft:speed 120 1"], "Strength request. Granting strength and speed buffs." ) if any(w in t for w in ['invisible', 'stealth', 'hide', 'sneak']): return ( "You wish to walk unseen? The divine grants you the cloak of shadows. Use it wisely — even invisible, the gods can see you.", [f"effect give {player} minecraft:invisibility 120 0"], "Invisibility request." ) if any(w in t for w in ['hungry', 'starving', 'food', 'eat']): return ( "The divine pantry opens! Feast, mortal, and let no hunger gnaw at thy resolve.", [f"give {player} minecraft:cooked_beef 32", f"effect give {player} minecraft:saturation 10 2"], "Food request. Giving beef and saturation." ) if any(w in t for w in ['xp', 'experience', 'level', 'levels']): return ( "Knowledge flows from the heavens! May these orbs of experience illuminate your path to greater enchantments.", [f"give {player} minecraft:experience_bottle 32"], "XP/experience request." ) if any(w in t for w in ['punish', 'smite', 'curse', 'wrath']): return ( "You invoke the wrath of the ALMIGHTY?! Very well — a taste of divine judgment!", ["weather thunder", f"summon minecraft:lightning_bolt ~ ~ ~"], "Punishment/wrath request. Thunder and lightning." ) if any(w in t for w in ['bless', 'blessing', 'favor', 'grace']): return ( "The blessing of the divine descends upon thee like morning dew upon fresh-placed grass blocks. May fortune follow your every step.", [f"effect give {player} minecraft:luck 600 1", f"effect give {player} minecraft:regeneration 120 0"], "Blessing request. Luck and regeneration." ) if any(w in t for w in ['friend', 'lonely', 'alone', 'company', 'pet', 'companion']): return ( "Even the divine knows loneliness is the cruelest mob. Here — a faithful companion to walk beside you.", [f"summon minecraft:wolf ~ ~ ~", f"summon minecraft:cat ~ ~ ~"], "Loneliness/companion request. Summoning wolf and cat." ) if any(w in t for w in ['rich', 'treasure', 'wealth', 'fortune', 'emerald']): return ( "Riches! The eternal mortal pursuit. The divine treasury cracks open just a sliver — catch what falls!", [f"give {player} minecraft:diamond 8", f"give {player} minecraft:emerald 16", f"give {player} minecraft:gold_ingot 32"], "Wealth request. Giving valuable items." ) # Default: dramatic acknowledgment + small gift return ( "The heavens have received your prayer, mortal. While your words are... uniquely phrased, the divine interprets all. Here is a token of acknowledgment.", [f"give {player} minecraft:golden_apple 2"], "Unusual or unclear prayer. Acknowledging with a small gift." ) def main(): random.seed(42) # Load all entries entries = [] with open(BANK) as f: for line in f: if not line.strip(): continue try: entries.append(json.loads(line)) except json.JSONDecodeError: continue print(f"Loaded {len(entries)} entries from quarantine prompt bank") # Sample for diversity — take up to 300 to keep quality high # Stratified sample: more from 'other' (diverse), fewer from repetitive categories categorized = {} for entry in entries: raw_input = entry.get('input', '') text = re.sub(r'^(pray|god)\s+', '', raw_input, flags=re.IGNORECASE).strip() cat = categorize(text) categorized.setdefault(cat, []).append(entry) # Sampling strategy sample_limits = { 'other': 120, # Most diverse category 'give': 40, 'greeting': 25, 'heal': 20, 'help': 20, 'mob': 20, 'weather': 15, 'build': 15, 'tp': 10, 'creative': 5, } sampled = [] seen_inputs = set() for cat, limit in sample_limits.items(): pool = categorized.get(cat, []) random.shuffle(pool) count = 0 for entry in pool: inp = entry.get('input', '').strip() if inp in seen_inputs: continue seen_inputs.add(inp) sampled.append(entry) count += 1 if count >= limit: break print(f"Sampled {len(sampled)} unique entries") # Generate gold responses examples = [] for entry in sampled: ex = generate_response(entry) examples.append(ex) random.shuffle(examples) with open(OUTPUT, "w") as f: for ex in examples: f.write(json.dumps(ex, ensure_ascii=False) + "\n") # Summary by category cat_counts = {} for entry in sampled: raw_input = entry.get('input', '') text = re.sub(r'^(pray|god)\s+', '', raw_input, flags=re.IGNORECASE).strip() cat = categorize(text) cat_counts[cat] = cat_counts.get(cat, 0) + 1 print(f"\nCategory breakdown:") for cat, count in sorted(cat_counts.items(), key=lambda x: -x[1]): print(f" {cat:15} {count:4}") print(f"\nTotal: {len(examples)} gold examples written to {OUTPUT}") if __name__ == "__main__": main()