- Prompt now includes full dream text (not just entity name)
- Model has full context to generate relevant content
- JSON parsing handles escaped quotes (\" -> ")
- Replace \n with space in JSON for cleaner parsing
- Fixes generic output unrelated to user's dream
feat: JSON output for reliable dream content parsing
- Prompt asks for structured JSON with location/npc/quest/emotions
- Parse JSON from model output with regex fallback
- Build entities directly from parsed JSON data
- NPC dialog preserved from JSON output
- Quest name/description from JSON
- Fallback: if JSON parsing fails, use raw text as before
- Example prompt output format:
{"location": {"name": "...", "desc": "..."}, ...}
fix: structured prompt for parser-compatible output
- Combined prompt asks for exact format: 地点:[name] — [desc]
- Parse combined_output with _parse_text_format to extract entities
- Use parsed entities to build proper Location/NPC/Quest objects
- Fallback: if parsing fails, use raw output as before
- Single LLM call remains (performance), but output is structured
fix: move @spaces.GPU to app.py for ZeroGPU detection
- ZeroGPU scans app.py for @spaces.GPU at startup
- gpu_generate.py is a submodule — invisible to scanner
- Solution: define @spaces.GPU in app.py, register globally
- app.py: gpu_generate() with @spaces.GPU(duration=120)
- Registers on core.gpu_generate module for model_manager to find
- Fallback: local dev uses plain function without decorator
- Reference: cbensimon/gradio-zerogpu-handshake (app.py pattern)
- import spaces (NOT from gradio import spaces)
- Fallback _Spaces class for local dev (no-op decorator)
- @spaces.GPU(duration=120) at module level in gpu_generate.py
- Add accelerate to requirements (needed for device_map='auto')
- Reference: cbensimon/gradio-zerogpu-handshake pattern
- core/gpu_generate.py: standalone GPU generation function
- @spaces.GPU(duration=120) at module level (detectable at startup)
- Model caching in _model_cache dict (persists across calls)
- model_manager.py: simplified, delegates to gpu_generate
- ZeroGPU scans module-level @spaces.GPU decorators at startup
- Previous approach (decorator inside class) was invisible to scanner
fix: remove bucket dependency for ZeroGPU compatibility
- ZeroGPU doesn't support storage bucket mounts
- DATA_DIR uses /data if available, falls back to local ./data
- User must remove bucket mount from Space settings
fix: ZeroGPU @spaces.GPU support for model generation
- Import spaces from gradio, detect ZeroGPU environment
- @spaces.GPU(duration=120) wraps the generation function
- On ZeroGPU: GPU allocated dynamically inside decorated function
- On local: direct call without decorator
- Try MiniCPM4.1-8B first, fall back to MiniCPM5-1B
- Always use float16 (ZeroGPU always has GPU available)
feat: ZeroGPU (RTX Pro 6000) support with 8B model
- README: hardware: zero-gpu
- model_manager: try MiniCPM4.1-8B on GPU, fall back to MiniCPM5-1B
- config: TEXT_MODEL_REPO = MiniCPM4.1-8B (non-GGUF for transformers)
- On ZeroGPU (48GB VRAM): loads 8B float16 (~16GB), much better quality
- On CPU: falls back to 1B model automatically
- Better thinking output handling with 1024 token budget
fix: 1024 token budget for thinking model + robust fallback
- Increase max_tokens to 512 (give thinking room + content)
- Restore n_ctx to 2048
- Simplify combined prompt: just key phrases, not full sentences
- English system prompt: 'Output directly. No thinking. No tags.'
- Better fallback content when stripped output is too short
- The model WILL think - we just need enough tokens for both
fix: strip thinking tags from combined generation output
- Combined LLM output now passes through _strip_thinking()
- Fallback: if stripped output too short, use entity name/desc
- Fixes raw <think> tags appearing in location/NPC descriptions
fix: robust thinking tag handling for MiniCPM5-1B
- model_manager: handle unclosed <think> tags (max_tokens cutoff)
- model_manager: extract content from ALL thinking blocks, not just closed ones
- model_manager: skip reasoning prefix lines (首先/然后/嗯/用户要求...)
- parser.py: _strip_thinking() now extracts from thinking if result empty
- Both model output and parser input handle 100% thinking content
- Expanded skip list: 8 common Chinese reasoning prefixes
perf: single LLM call for dream pipeline (4x faster on CPU)
- Combine parse + location + NPC + quest generation into 1 LLM call
- Reduces CPU inference time from ~4min to ~1min
- Combined prompt asks model to generate all content in one response
- Each generator receives the same combined output as context
fix: remove token_type_ids for MiniCPM5-1B compatibility
- MiniCPM5-1B outputs ALL content inside <think> tags
- After stripping thinking, result was empty -> showed defaults
- Fix: if result empty after strip, extract last lines from thinking
- Skip reasoning lines (嗯, 想到, 考虑...) keep content lines
- Stronger system prompt: '禁止输出思考过程'
- Root cause: thinking model outputs reasoning, not final answer
- model_manager: float16 on GPU, float32 on CPU
- model_manager: fallback if chat_template fails (simple concat)
- model_manager: log generated text length and preview
- model_manager: device_map='auto' for GPU offload
- config: reduce TEXT_MODEL_MAX_TOKENS 512->256, N_CTX 2048->1024
- Fix deprecated torch_dtype warning
- Better system prompt for Chinese output
fix: refresh Explorer/Journal dropdowns after dream submission
- _process_and_refresh returns updated exp_dropdown and quest_dropdown
- Locations and quests refresh automatically after new dream
- Error case returns gr.update() for dropdowns (no change)
feat: wire up Explorer, Journal, Player, History, Map refresh handlers
- config.py: DATA_DIR uses /data when bucket is mounted
- persistence.py: simplified (data already at /data via config)
- All user data persists across Space restarts
- Bucket: build-small-hackathon/dreamland at /data (R/W)
- _on_action returns updated slot button labels (5 buttons)
- Slot buttons show character name after creation
- core/persistence.py: HF Buckets sync (download on startup, upload on save)
- app.py: sync_from_bucket() called before app creation
- player.py: sync_to_bucket() called after each save_player()
- Buckets mount via HF_BUCKETS_MOUNT env var
fix: per-user session isolation via ensure_session_id
- session_id starts empty, generated on first interaction
- ensure_session_id() generates unique ID if current one is invalid
- All handlers return session_id as output to persist it
- Each user gets isolated data directory (data/users/{hash}/)
- set_current_user handles None/empty values gracefully
fix: remove device_map='cpu' - not supported in HF Spaces
- Fix session_id: pass as gr.State in inputs, convert to str in handler
- Fix slot click: use gr.State(value=i) instead of lambda capture
- Fix missing history_display variable
- Fix hero_display stored for language toggle update
- Update README: MiniCPM5-1B via transformers (not MiniCPM4.1-8B/llama.cpp)
- Remove llama-cpp references from ATTRIBUTION
- Add features list, how-it-works, local run instructions to README
- ctransformers installs from pre-built wheel (no compilation timeout)
- Auto-fallback: ctransformers -> llama-cpp-python
- Supports both GPU and CPU modes
- Update requirements.txt: ctransformers>=0.2.0
- Fix model_manager: dual-backend support with _backend flag
fix: add llama-cpp-python to requirements (was missing)
- Remove gr.render, use standard gr.Blocks with all components upfront
- Slot selection: 5 clickable buttons + preview panel + action button
- Game tabs: Dream Input, World Map, Explorer, Quest Journal,
Player Sheet, History, Settings
- Editor: Accordion sections (collapsed by default) for location/NPC/quest
- All event wiring: submit, regen, save, explore, rest, complete quest
- ATTRIBUTION footer with model links
- CSS inline in HTML (no external file dependency)
- i18n support via Settings dropdown
- Compatible with HF Spaces Gradio SDK (no Docker needed)
- Embed <style>CSS</style> directly in _hero_html() gr.HTML
- Background: dedicated .dl-bg div (not pseudo-element on gradio-container)
- Remove CSS variables (var(--dl-*) → hardcoded colors) for reliability
- Google Fonts @import inside the style tag
- .gradio-container background set to transparent
- hero-title: explicit gradient + background-clip for font display
- gr.render conditional rendering: slot screen vs game screen
- Slot screen: preview + buttons + create/enter, separate from game
- Game screen: 7 tabs with all game features
- ATTRIBUTION_HTML: animated gradient background with floating orbs
and hue-rotation effect
- Favicon via <link rel="icon"> in head_html
- Editor accordions default collapsed (open=False)
- Editor always visible (no gr.Column visibility toggle)
- config.py: cleaned up, ATTRIBUTION_HTML added, ICON_PATH added
fix: remove all gr.Column/gr.Group outputs, add favicon
- Remove gr.Column(visible=False) wrapper from editor in dream_tab
- Editor always visible (no visibility toggle needed)
- Remove editor_group from process_dream return values and outputs
- Remove editor_group from main.py submit outputs
- Add favicon via head_html link tag
- Zero gr.update(visible=...) remaining
fix: single-page layout, no gr.Column/Group output components
- Remove ALL gr.Column(visible=...) and gr.Group(visible=...) outputs
(Gradio 6.0 rejects them as invalid output components)
- Single-page layout: slot selection at top, game tabs below
- All state changes via gr.HTML and gr.Button updates only
- Move icon.png to assets/
- Organize screenshots into screenshots/ folder
- Replace gr.update(visible=...) with single HTML panel approach
- _render_slot_action_panel: renders preview + action form in one HTML
- Slot click updates HTML panel + tracks selected_slot state
- Enter/Create button: uses selected_slot state to route action
- Existing char: direct enter, no creation form shown
- Empty slot: name input shown, validated before creation
- load_save: auto-selects current active slot on return
- _render_slot_preview restored in main.py
- _handle_slot: clear separation between new (creation form) and
existing (continue button with character name)
- Continue button now shows character name: "Explore - TestHero"
- Create form: validate name non-empty and max 20 chars
- Error messages shown inline without page refresh
- Restore slot selection page with 5 clickable buttons + preview
- Settings tab: remove rename, add "Load Save" button to return to
slot selection for switching between saves
- Player Sheet tab: shows current character info only (no slot mgmt)
- Dream submission now refreshes player_display for XP updates
- _process_and_refresh wrapper adds _render_player_sheet() to outputs