Spaces:
Running
Running
FlyBrain V9.0.0 Space sync (v9 release, endless world, chunk streaming, FlyAsset compiler)
6343479 verified | """LLM World Planner for FlyBrain V8/V9. | |
| Implements Sections 46, 50, 90: | |
| - Translates natural language prompts into declarative structured WorldIntent. | |
| - Resolves assets via AssetResolver and coordinates spatial placement. | |
| - Offline-first: uses local Qwen LLM when available, falls back to deterministic semantic parser. | |
| """ | |
| import os | |
| import json | |
| import re | |
| from typing import Dict, Any, List, Optional | |
| from src.assets.compiler.types import AssetClass | |
| from src.assets.resolver import AssetResolver | |
| class WorldPlan: | |
| def __init__(self, raw_prompt: str, biome: str, structures: List[Dict[str, Any]], | |
| water: Optional[Dict[str, Any]] = None, resolved_assets: Optional[List[Dict[str, Any]]] = None): | |
| self.raw_prompt = raw_prompt | |
| self.biome = biome | |
| self.structures = structures | |
| self.water = water | |
| self.resolved_assets = resolved_assets or [] | |
| def to_dict(self) -> Dict[str, Any]: | |
| return { | |
| "raw_prompt": self.raw_prompt, | |
| "biome": self.biome, | |
| "structures": self.structures, | |
| "water": self.water, | |
| "resolved_assets": self.resolved_assets | |
| } | |
| class WorldPlanner: | |
| def __init__(self, resolver: Optional[AssetResolver] = None): | |
| self.resolver = resolver or AssetResolver() | |
| def _extract_intent_llm(self, prompt: str) -> Optional[Dict[str, Any]]: | |
| try: | |
| from src.models.manager import get_model_manager | |
| mgr = get_model_manager() | |
| if not mgr.is_available("llm"): | |
| return None | |
| llm = mgr.get_llm() | |
| sys_msg = ( | |
| "You are the FlyBrain World Planner. Output valid JSON only with keys: " | |
| "'biome', 'structures' (list of {type, material, span_m, width_m, x, y, z}), 'water'." | |
| ) | |
| resp = llm.create_chat_completion( | |
| messages=[ | |
| {"role": "system", "content": sys_msg}, | |
| {"role": "user", "content": prompt} | |
| ], | |
| max_tokens=256, | |
| temperature=0.1 | |
| ) | |
| text = resp["choices"][0]["message"]["content"] | |
| # Extract JSON block | |
| m = re.search(r"\{.*\}", text, re.DOTALL) | |
| if m: | |
| return json.loads(m.group(0)) | |
| except Exception: | |
| pass | |
| return None | |
| def _extract_intent_rule_based(self, prompt: str) -> Dict[str, Any]: | |
| p = prompt.lower() | |
| biome = "temperate_valley" | |
| if "pine" in p or "forest" in p: | |
| biome = "pine_forest" | |
| elif "mountain" in p or "rock" in p or "highland" in p: | |
| biome = "rocky_highlands" | |
| structures = [] | |
| water = None | |
| if "bridge" in p: | |
| structures.append({ | |
| "type": "wooden_bridge", | |
| "material": "wood", | |
| "span_m": 4.0, | |
| "width_m": 1.5, | |
| "x": 2.0, | |
| "y": 5.0, | |
| "z": 0.0 | |
| }) | |
| water = {"type": "stream", "x": 2.0, "y": 5.0, "width": 2.5} | |
| if "tower" in p or "watchtower" in p: | |
| structures.append({ | |
| "type": "watchtower", | |
| "material": "wood", | |
| "sx": 2.5, | |
| "sy": 2.5, | |
| "sz": 6.0, | |
| "x": -5.0, | |
| "y": 6.0, | |
| "z": 0.0 | |
| }) | |
| if "cabin" in p or "house" in p or "settlement" in p: | |
| structures.append({ | |
| "type": "log_cabin", | |
| "material": "wood", | |
| "sx": 4.0, | |
| "sy": 4.0, | |
| "sz": 2.8, | |
| "x": -6.0, | |
| "y": 8.0, | |
| "z": 0.0 | |
| }) | |
| if not structures: | |
| structures.append({ | |
| "type": "marker_structure", | |
| "material": "stone", | |
| "sx": 1.0, | |
| "sy": 1.0, | |
| "sz": 1.0, | |
| "x": 0.0, | |
| "y": 6.0, | |
| "z": 0.0 | |
| }) | |
| return {"biome": biome, "structures": structures, "water": water} | |
| def plan_world(self, prompt: str, seed: int = 42) -> WorldPlan: | |
| """Section 46 & 90: Generates structured declarative plan and resolves assets.""" | |
| intent = self._extract_intent_llm(prompt) | |
| if not intent or "structures" not in intent: | |
| intent = self._extract_intent_rule_based(prompt) | |
| biome = intent.get("biome", "temperate_valley") | |
| raw_structs = intent.get("structures", []) | |
| water = intent.get("water") | |
| resolved = [] | |
| for s in raw_structs: | |
| stype = s.get("type", "structure") | |
| params = {k: v for k, v in s.items() if k not in ("type", "x", "y", "z")} | |
| res = self.resolver.resolve_asset( | |
| semantic_name=stype, | |
| category=AssetClass.STRUCTURE, | |
| params=params, | |
| seed=seed | |
| ) | |
| resolved.append({ | |
| **s, | |
| "resolution": res | |
| }) | |
| return WorldPlan( | |
| raw_prompt=prompt, | |
| biome=biome, | |
| structures=raw_structs, | |
| water=water, | |
| resolved_assets=resolved | |
| ) | |