5b28002001
Major changes from this session: Training: - 0.6.0 training running: 9B on steel141 3090 Ti, 27B on rented H100 NVL - 7,256 merged training examples (up from 3,183) - New training data: failure modes (85), midloop messaging (27), prompt injection defense (29), personality (32), gold from quarantine bank (232), new tool examples (30), claude's own experience (10) - All training data RCON-validated at 100% pass rate - Bake-off: gemma3:27b 66%, qwen3.5:27b 61%, translategemma:27b 56% Oracle Bot (Mind's Eye): - Invisible spectator bot (mineflayer) streams world state via WebSocket - HTML5 Canvas frontend at mind.mortdec.ai - Real-time tool trace visualization with expandable entries - Streaming model tokens during inference - Gateway integration: fire-and-forget POST /trace on every tool call Reinforcement Learning: - Gymnasium environment wrapping mineflayer bot (minecraft_env.py) - PPO training via Stable Baselines3 (10K param policy network) - Behavioral cloning pretraining (97.5% accuracy on expert policy) - Infinite training loop with auto-restart and checkpoint resume - Bot learns combat, survival, navigation from raw experience Bot Army: - 8-soldier marching formation with autonomous combat - Combat bots using mineflayer-pvp, pathfinder, armor-manager - Multilingual prayer bots via translategemma:27b (18 languages) - Frame-based AI architecture: LLM planner + reactive micro-scripts Infrastructure: - Fixed mattpc.sethpc.xyz billing gateway (API key + player list parser) - Billing gateway now tracks all LAN traffic (LAN auto-auth) - Gateway fallback for empty god-mode responses - Updated mortdec.ai landing page Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
554 lines
22 KiB
Python
554 lines
22 KiB
Python
#!/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 <target> minecraft:<effect> <seconds> <amplifier>
|
|
- Weather: weather clear | weather rain | weather thunder
|
|
- Gamemode: gamemode survival|creative|adventure|spectator <target>
|
|
- Summon: summon minecraft:<entity> <x> <y> <z>
|
|
- Items always need minecraft: prefix
|
|
- Kill entities: kill @e[type=minecraft:<entity>,distance=..<radius>]
|
|
|
|
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()
|