topguy commited on
Commit
e480cd9
·
1 Parent(s): 2115291

Phase 5.5: UI Model Selection & Enhanced Fault Diagnostics

Browse files

- [UI] Converted Hugging Face model inputs to curated dropdowns with a 'Manual Entry' toggle.
- [UI] Implemented high-visibility 'Synthesis Chamber Fault' error display in the central canvas.
- [UI] Upgraded the action status bar to be reactive to failure states (pulsing red text).
- [Backend] Restored SD-XL-base to the curated image model list in config.py.
- [API] Exposed hf_text_models and hf_image_models in the config endpoint.

README.md CHANGED
@@ -16,21 +16,18 @@ RPGPortrait is a decoupled Next.js + FastAPI web application that helps users bu
16
  ## Features
17
  - **25+ Character Parameters**: Deep customization including Identity, Appearance, Equipment, Environment, VFX, and Technical settings.
18
  - **🧠 AI Refinement**: Intelligent prompt enhancement using **Gemini (Cloud)**, **Curated Hugging Face Models**, or **Ollama (Local)**.
19
- - **🛠Externalized Prompts**: Tweak the core AI system instructions by editing `prompts.yaml`.
 
 
20
  - **🖼️ Multi-Backend Image Gen**: Toggle between **Gemini (Cloud)**, **Hugging Face (Cloud)**, and **ComfyUI (Local)**.
21
  - **⚡ Hugging Face Pro Features**:
22
- - Curated list of 4 text and 4 image models.
23
- - Manual **Inference Provider** support (e.g., `fal-ai`, `black-forest-labs`) to bypass rate limits or use partner backends.
24
- - Automated "auto" provider selection by default.
25
- - **🔍 Dynamic Model Discovery**: Automatically pings local Ollama and ComfyUI servers to fetch available models and hide unavailable backends.
26
- - **Workflow Injection**: Automated prompt, resolution, and seed injection into custom ComfyUI workflows.
27
- - **💾 Save & Load**: Export your character configurations as JSON files and import them back to restore your exact selections.
28
- - **⚔️ Exotic Arsenal**: Expanded collection of exotic weapons, armor, and accessories (Katanas, Bone Armor, Arcane Plate, etc.).
29
- - **🎒 Dual Accessories**: Select up to two different accessories for your character.
30
- - **📥 Pro Downloads**: Standard PNG downloads for portraits with friendly filenames.
31
- - **Randomization**: Check individual 🎲 boxes to randomize specific features on regeneration.
32
- - **🛡️ Robust Error Handling**: AI refinement errors are logged to the console and displayed in the UI status area without polluting your current prompt.
33
- - **YAML Data Storage**: Easily add or modify races, classes, backgrounds, and templates in `features.yaml`.
34
 
35
  ## Installation & Setup
36
 
 
16
  ## Features
17
  - **25+ Character Parameters**: Deep customization including Identity, Appearance, Equipment, Environment, VFX, and Technical settings.
18
  - **🧠 AI Refinement**: Intelligent prompt enhancement using **Gemini (Cloud)**, **Curated Hugging Face Models**, or **Ollama (Local)**.
19
+ - **Configuration Hub**: A dedicated center for managing AI engines, models, and API tokens with real-time status detection.
20
+ - **🍪 Milk and Cookies Persistence**: All character selections and engine configurations are locally persisted and survive page refreshes.
21
+ - **🔦 Full-Resolution Lightbox**: View your masterpieces in high-definition with a premium blur-in effect and direct download button.
22
  - **🖼️ Multi-Backend Image Gen**: Toggle between **Gemini (Cloud)**, **Hugging Face (Cloud)**, and **ComfyUI (Local)**.
23
  - **⚡ Hugging Face Pro Features**:
24
+ - Support for advanced models (e.g., FLUX.1-dev).
25
+ - Manual **Inference Provider** support (e.g., `fal-ai`, `replicate`) to bypass rate limits.
26
+ - **🔍 Dynamic Model Discovery**: Automatically pings local Ollama and ComfyUI servers to reflect availability in the UI.
27
+ - **💾 Save & Load**: Export character configurations as JSON and import them to restore your exact studio state.
28
+ - **🎒 Dual Accessories & Exotic Arsenal**: Deep customization for your hero's gear and artifacts.
29
+ - **🛡️ Robust Error Handling**: Clear, non-intrusive status messages for AI synthesis and refinement errors.
30
+ - **YAML Data Storage**: Flexible character features and prompt templates managed via `features.yaml` and `prompts.yaml`.
 
 
 
 
 
31
 
32
  ## Installation & Setup
33
 
api.py CHANGED
@@ -74,12 +74,18 @@ class ImageGenerationRequest(BaseModel):
74
  def get_config():
75
  """Returns static config info needed by frontend to render dropdowns, etc."""
76
  from modules.core_logic import features_data, get_example_list
 
 
77
  return {
78
  "features_data": features_data,
79
  "feature_sequence": FEATURE_SEQUENCE,
80
  "sections": SECTIONS,
81
  "ollama_models": get_ollama_models(),
82
  "comfy_active": check_comfy_availability(),
 
 
 
 
83
  "examples": get_example_list()
84
  }
85
 
@@ -127,6 +133,7 @@ def refine_prompt(req: RefinementRequest):
127
 
128
  @app.post("/api/generate_image")
129
  def generate_image(req: ImageGenerationRequest):
 
130
  img, img_path, status_msg = generate_image_master(
131
  req.refined_prompt,
132
  req.technical_prompt,
 
74
  def get_config():
75
  """Returns static config info needed by frontend to render dropdowns, etc."""
76
  from modules.core_logic import features_data, get_example_list
77
+ from modules.integrations import gemini_active, hf_active
78
+ from modules.config import HF_TEXT_MODELS, HF_IMAGE_MODELS
79
  return {
80
  "features_data": features_data,
81
  "feature_sequence": FEATURE_SEQUENCE,
82
  "sections": SECTIONS,
83
  "ollama_models": get_ollama_models(),
84
  "comfy_active": check_comfy_availability(),
85
+ "gemini_active": gemini_active,
86
+ "hf_active": hf_active,
87
+ "hf_text_models": HF_TEXT_MODELS,
88
+ "hf_image_models": HF_IMAGE_MODELS,
89
  "examples": get_example_list()
90
  }
91
 
 
133
 
134
  @app.post("/api/generate_image")
135
  def generate_image(req: ImageGenerationRequest):
136
+ print(f"DEBUG: Received Image Request: {req.dict()}")
137
  img, img_path, status_msg = generate_image_master(
138
  req.refined_prompt,
139
  req.technical_prompt,
design.md CHANGED
@@ -1,80 +1,56 @@
1
  # RPGPortrait Design Document
2
 
3
  ## Project Overview
4
- RPGPortrait is a Gradio-based web application that helps users build detailed prompts and generate character portraits leveraging Gemini AI models.
5
 
6
  ## UI Design
7
- The UI is built using `gradio.Blocks` to allow for a structured, multi-column layout.
8
 
9
  ### Layout Structure
10
- - **Global Control**: Save/Load character (JSON), Randomize features, **Character Naming**.
11
- - **Input Sections**: Organized into columns/rows of dropdown menus.
12
- - **Identity**: Race, Class (with **🎲 Auto-Name**), Gender, Age.
13
- - **Appearance**: Hair Style/Color, Eye Color, Build, Skin Tone, Distinguishing Features.
14
- - **Equipment**: Armor/Clothing, Weapons, Accessories (up to 2), Materials.
15
- - **Environment**: Background, Lighting, Atmosphere.
16
- - **Artistic Style**: Art Style, Mood, Special Effects (VFX).
17
- - **Generation Suite**:
18
- - Large technical prompt textbox (read-only).
19
- - **🧠 Refine with Gemini**: Calls Gemini 3 Pro to create a vivid prompt.
20
- - **🖼️ Generate Image**: Routes to selected backend (Gemini or ComfyUI).
21
- - **Backend Selector**:
22
- - Radio buttons to toggle between **Gemini (Cloud)** and **ComfyUI (Local)**.
23
- - **Output Area**:
24
- - Image display for the portrait.
25
- - 📥 Download button (PNG) for the generated image.
26
 
27
  ## Prompt Assembly Logic
28
- The app uses a 3-stage prompt pipeline:
29
- 1. **Technical Segmenting**: Combines dropdown values and extra info text into a base technical prompt using a YAML-based template.
30
- 2. **AI Refinement**: The technical prompt is sent to an LLM to "art-ify" the description. The system instructions for this are stored in `prompts.yaml`.
31
- - **Cloud**: Uses `gemini-3-pro-preview`.
32
- - **Local**: Uses Ollama (e.g., `llama3`).
33
  3. **Image Synthesis**:
34
- - **Cloud**: Sent to `imagen-4.0-generate-001`.
35
- - **Local**: Sent to a ComfyUI endpoint via `POST /prompt`, utilizing a custom workflow (`comfy_rpg_char_gen.json`).
36
 
37
- ## Naming & Metadata
38
- - **Local Naming**: Uses a procedural generator based on the `fictional-names` library for instant, thematic results.
39
- - **Metadata Embedding**: Generation prompts and character names are embedded directly into the PNG `tEXt` chunks (Comment and CharacterName keys).
40
- - **Filenames**: Character names are sanitized and used for both JSON and PNG output.
41
-
42
- ## Data & Persistence
43
- - **YAML Configuration**: `features.yaml` stores all possible dropdown values, their descriptive labels, and the final prompt template.
44
- - **JSON Serialization**: "Save/Load" functionality allows users to export and import their full character state as a JSON file.
45
 
46
  ## Technical Stack
47
- - **Backend**: Python 3
48
- - **SDK**: `google-genai`
49
- - **UI Framework**: Gradio
50
- - **AI Models**:
51
- - **Text (Cloud)**: `gemini-3-pro-preview`
52
- - **Text (Local)**: Ollama
53
- - **Image Cloud**: `imagen-4.0-generate-001`
54
- - **Image Local**: ComfyUI (Local Server)
55
- - **Configuration**:
56
- - `.env` for API keys and connection hosts/ports (ComfyUI, Ollama).
57
- ## Maintenance & Development Lessons
58
-
59
- ### 1. Server Lifecycle
60
- - **Mandatory Restarts**: Any modification to the `modules/` folder or configuration files (`features.yaml`, `prompts.yaml`) requires a manual restart of the Gradio server.
61
- - **Process Management (CRITICAL)**: Always ensure the previously running process is fully terminated before starting a new one.
62
- - **Safe Command**: Use this PowerShell command to only kill the process using the target port (7860):
63
- ```powershell
64
- Stop-Process -Id (Get-NetTCPConnection -LocalPort 7860 -ErrorAction SilentlyContinue).OwningProcess -Force -ErrorAction SilentlyContinue
65
- ```
66
-
67
- ### 2. Project Architecture (Modular)
68
- - **`app.py`**: Entry point that launches the Gradio `demo`.
69
- - **`modules/config.py`**: Global constants and environment variables.
70
- - **`modules/integrations.py`**: Wrappers for AI backends (Gemini, Ollama, ComfyUI).
71
- - **`modules/core_logic.py`**: Character state management and prompt assembly.
72
- - **`modules/ui_layout.py`**: The full Gradio UI definition (`build_ui`).
73
- - **`modules/name_generator.py`**: Local procedural name generator using the `fictional-names` library.
74
- - **`comfy/`**: Dedicated folder for ComfyUI-specific JSON workflows and utility scripts.
75
-
76
- ### 3. Deployment (Hugging Face Spaces)
77
- - **Containerization**: The app is containerized using the provided `Dockerfile` and `.dockerignore`.
78
- - **User Permissions**: The Dockerfile uses `useradd -m -u 1000 user` to comply with Hugging Face's security requirements for non-root users.
79
- - **Port Mapping**: Hugging Face Spaces expects the app on port 7860. The `GRADIO_SERVER_NAME="0.0.0.0"` and `GRADIO_SERVER_PORT=7860` environment variables ensure the app is bound correctly for external routing.
80
- - **Local Testing**: Run `docker-compose up --build` to verify the deployment state locally.
 
1
  # RPGPortrait Design Document
2
 
3
  ## Project Overview
4
+ RPGPortrait is a decoupled, modern web application for tabletop RPG players to build detailed prompts and generate character portraits. It follows a **Next.js (Frontend)** and **FastAPI (Backend)** architecture, utilizing a premium "Obsidian & Ember" dark-aesthetic UI.
5
 
6
  ## UI Design
7
+ The interface is a responsive, single-page application (SPA) with a primary content area and a secondary configuration hub.
8
 
9
  ### Layout Structure
10
+ - **Navigation Tabs**:
11
+ - **Identity**: Core character traits (Race, Class, Gender, Age).
12
+ - **Appearance**: Visual details (Hair, Eyes, Build, Distinguishing Features).
13
+ - **Equipment**: Gear and artifacts (Armor, Weapons, Accessories).
14
+ - **Environment**: Scene settings (Background, Lighting, Mood).
15
+ - **Render Style**: Artistic direction (Art Style, VFX, Aspect Ratio).
16
+ - **Configuration**: System management (AI Engines, API Tokens, Local Models).
17
+ - **Portrait Studio (Center)**:
18
+ - **Full-Resolution Masterpiece**: Interactive image display with lightbox.
19
+ - **Refinement Suite**: Narrative enhancement and renaming features.
20
+ - **Action Bar**: Synthesize and Randomize controls.
21
+ - **State Management (Sidebar)**:
22
+ - **Save/Load**: JSON-based state export/import.
23
+ - **Prompt Preview**: Real-time technical prompt construction.
 
 
24
 
25
  ## Prompt Assembly Logic
26
+ The system uses a modular 3-stage pipeline:
27
+ 1. **Technical Segmenting**: Assembles dropdown values into a base prompt using `features.yaml`.
28
+ 2. **AI Refinement**: Transmutes technical tokens into vivid descriptions using LLMs (Gemini, Ollama, or HF). Instructions are stored in `prompts.yaml`.
 
 
29
  3. **Image Synthesis**:
30
+ - **Cloud**: Google Gemini (Imagen) or Hugging Face (Direct API/Router).
31
+ - **Local**: ComfyUI via WebSocket/REST with dynamic workflow injection.
32
 
33
+ ## Persistence & State
34
+ - **Milk and Cookies**: All UI selections and engine configurations are persisted in `localStorage`.
35
+ - **Metadata**: Generated images embed the full character prompt and name in PNG metadata (`tEXt` chunks).
 
 
 
 
 
36
 
37
  ## Technical Stack
38
+ - **Frontend**: Next.js 15, Tailwind CSS v4 (Glassmorphism), Lucide Icons.
39
+ - **Backend**: FastAPI (Python 3.11+), Uvicorn.
40
+ - **AI Backend**:
41
+ - **Gemini**: `google-genai` SDK.
42
+ - **Ollama**: Local REST API exploration.
43
+ - **Hugging Face**: `huggingface_hub` and direct Router requests.
44
+ - **ComfyUI**: WebSocket bridge for status and history tracking.
45
+
46
+ ## Project Architecture
47
+ - **`api.py`**: FastAPI server hosting the REST API and serving the static frontend in production.
48
+ - **`frontend/src/`**: Next.js source code, components, and Tailwind styles.
49
+ - **`modules/`**: Shared backend logic for integrations, prompt assembly, and config.
50
+ - **`features.yaml` / `prompts.yaml`**: Externalized data and instruction layers.
51
+
52
+ ## Maintenance & Development
53
+ - **Dev Servers**:
54
+ - Frontend: `npm run dev` (Port 3000)
55
+ - Backend: `python api.py` (Port 8000)
56
+ - **Deployment**: Configured for Hugging Face Spaces via Docker. Static export mode is used for high-performance delivery.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
frontend/dev.log ADDED
@@ -0,0 +1,2173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ > frontend@0.1.0 dev
3
+ > next dev
4
+
5
+ Γû▓ Next.js 16.2.1 (Turbopack)
6
+ - Local: http://localhost:3000
7
+ - Network: http://192.168.10.118:3000
8
+ Γ£ô Ready in 254ms
9
+
10
+ HEAD / 200 in 184ms (next.js: 109ms, application-code: 76ms)
11
+ GET / 200 in 21ms (next.js: 2ms, application-code: 19ms)
12
+ GET / 200 in 26ms (next.js: 3ms, application-code: 23ms)
13
+ ΓÜá Blocked cross-origin request to Next.js dev resource /_next/webpack-hmr from "127.0.0.1".
14
+ Cross-origin access to Next.js dev resources is blocked by default for safety.
15
+
16
+ To allow this host in development, add it to "allowedDevOrigins" in next.config.js and restart the dev server:
17
+
18
+ // next.config.js
19
+ module.exports = {
20
+ allowedDevOrigins: ['127.0.0.1'],
21
+ }
22
+
23
+ Read more: https://nextjs.org/docs/app/api-reference/config/next-config-js/allowedDevOrigins
24
+ GET / 200 in 28ms (next.js: 2ms, application-code: 25ms)
25
+ GET / 200 in 22ms (next.js: 1867┬╡s, application-code: 20ms)
26
+ GET / 200 in 25ms (next.js: 2ms, application-code: 23ms)
27
+ GET / 200 in 24ms (next.js: 1998┬╡s, application-code: 22ms)
28
+ [browser] A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR-ed Client Component used:
29
+
30
+ - A server/client branch `if (typeof window !== 'undefined')`.
31
+ - Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.
32
+ - Date formatting in a user's locale which doesn't match the server.
33
+ - External changing data without sending a snapshot of it along with the HTML.
34
+ - Invalid HTML tag nesting.
35
+
36
+ It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
37
+
38
+ https://react.dev/link/hydration-mismatch
39
+
40
+ ...
41
+ <HotReload globalError={[...]} webSocket={WebSocket} staticIndicatorState={{pathname:null, ...}}>
42
+ <AppDevOverlayErrorBoundary globalError={[...]}>
43
+ <ReplaySsrOnlyErrors>
44
+ <DevRootHTTPAccessFallbackBoundary>
45
+ <HTTPAccessFallbackBoundary notFound={<NotAllowedRootHTTPFallbackError>}>
46
+ <HTTPAccessFallbackErrorBoundary pathname="/" notFound={<NotAllowedRootHTTPFallbackError>} ...>
47
+ <RedirectBoundary>
48
+ <RedirectErrorBoundary router={{...}}>
49
+ <Head>
50
+ <__next_root_layout_boundary__>
51
+ <SegmentViewNode type="layout" pagePath="layout.tsx">
52
+ <SegmentTrieNode>
53
+ <link>
54
+ <script>
55
+ <script>
56
+ <RootLayout>
57
+ <html
58
+ lang="en"
59
+ - data-jetski-tab-id="11505165"
60
+ >
61
+ ...
62
+
63
+ GET / 200 in 27ms (next.js: 3ms, application-code: 25ms)
64
+ GET / 200 in 28ms (next.js: 2ms, application-code: 26ms)
65
+ GET / 200 in 20ms (next.js: 2ms, application-code: 17ms)
66
+ GET / 200 in 24ms (next.js: 2ms, application-code: 22ms)
67
+ GET / 200 in 23ms (next.js: 1755┬╡s, application-code: 21ms)
68
+ [browser] A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR-ed Client Component used:
69
+
70
+ - A server/client branch `if (typeof window !== 'undefined')`.
71
+ - Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.
72
+ - Date formatting in a user's locale which doesn't match the server.
73
+ - External changing data without sending a snapshot of it along with the HTML.
74
+ - Invalid HTML tag nesting.
75
+
76
+ It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
77
+
78
+ https://react.dev/link/hydration-mismatch
79
+
80
+ ...
81
+ <HotReload globalError={[...]} webSocket={WebSocket} staticIndicatorState={{pathname:null, ...}}>
82
+ <AppDevOverlayErrorBoundary globalError={[...]}>
83
+ <ReplaySsrOnlyErrors>
84
+ <DevRootHTTPAccessFallbackBoundary>
85
+ <HTTPAccessFallbackBoundary notFound={<NotAllowedRootHTTPFallbackError>}>
86
+ <HTTPAccessFallbackErrorBoundary pathname="/" notFound={<NotAllowedRootHTTPFallbackError>} ...>
87
+ <RedirectBoundary>
88
+ <RedirectErrorBoundary router={{...}}>
89
+ <Head>
90
+ <__next_root_layout_boundary__>
91
+ <SegmentViewNode type="layout" pagePath="layout.tsx">
92
+ <SegmentTrieNode>
93
+ <link>
94
+ <script>
95
+ <script>
96
+ <RootLayout>
97
+ <html
98
+ lang="en"
99
+ - data-jetski-tab-id="11505165"
100
+ >
101
+ ...
102
+
103
+ GET / 200 in 23ms (next.js: 3ms, application-code: 20ms)
104
+ GET / 200 in 21ms (next.js: 2ms, application-code: 18ms)
105
+ Γ£ô Compiled in 42ms
106
+ GET / 200 in 114ms (next.js: 54ms, application-code: 60ms)
107
+ Γ£ô Compiled in 20ms
108
+ ΓÜá Found a change in next.config.ts. Restarting the server to apply the changes...
109
+ Γû▓ Next.js 16.2.1 (Turbopack)
110
+ - Local: http://localhost:3000
111
+ - Network: http://192.168.10.118:3000
112
+ Γ£ô Ready in 349ms
113
+
114
+ GET / 200 in 268ms (next.js: 181ms, application-code: 87ms)
115
+ Γ£ô Compiled in 64ms
116
+ GET / 200 in 61ms (next.js: 37ms, application-code: 25ms)
117
+ GET / 200 in 24ms (next.js: 3ms, application-code: 21ms)
118
+ Γ£ô Compiled in 39ms
119
+ GET / 200 in 52ms (next.js: 35ms, application-code: 17ms)
120
+ GET / 200 in 21ms (next.js: 2ms, application-code: 19ms)
121
+ [browser] Failed to load config TypeError: NetworkError when attempting to fetch resource.
122
+ Γ£ô Compiled in 44ms
123
+ GET / 200 in 44ms (next.js: 28ms, application-code: 16ms)
124
+ GET / 200 in 20ms (next.js: 2ms, application-code: 18ms)
125
+ GET / 200 in 42ms (next.js: 2ms, application-code: 40ms)
126
+ [browser] A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR-ed Client Component used:
127
+
128
+ - A server/client branch `if (typeof window !== 'undefined')`.
129
+ - Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.
130
+ - Date formatting in a user's locale which doesn't match the server.
131
+ - External changing data without sending a snapshot of it along with the HTML.
132
+ - Invalid HTML tag nesting.
133
+
134
+ It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
135
+
136
+ https://react.dev/link/hydration-mismatch
137
+
138
+ ...
139
+ <HotReload globalError={[...]} webSocket={WebSocket} staticIndicatorState={{pathname:null, ...}}>
140
+ <AppDevOverlayErrorBoundary globalError={[...]}>
141
+ <ReplaySsrOnlyErrors>
142
+ <DevRootHTTPAccessFallbackBoundary>
143
+ <HTTPAccessFallbackBoundary notFound={<NotAllowedRootHTTPFallbackError>}>
144
+ <HTTPAccessFallbackErrorBoundary pathname="/" notFound={<NotAllowedRootHTTPFallbackError>} ...>
145
+ <RedirectBoundary>
146
+ <RedirectErrorBoundary router={{...}}>
147
+ <Head>
148
+ <__next_root_layout_boundary__>
149
+ <SegmentViewNode type="layout" pagePath="layout.tsx">
150
+ <SegmentTrieNode>
151
+ <link>
152
+ <script>
153
+ <script>
154
+ <RootLayout>
155
+ <html
156
+ lang="en"
157
+ - data-jetski-tab-id="11505257"
158
+ >
159
+ <body
160
+ - className="antigravity-scroll-lock"
161
+ >
162
+ ...
163
+
164
+ [browser] Failed to load config TypeError: Failed to fetch
165
+ at ClientApp.useEffect (src/components/ClientApp.tsx:78:5)
166
+ 76 |
167
+ 77 | useEffect(() => {
168
+ > 78 | fetch(`${API_URL}/api/config`)
169
+ | ^
170
+ 79 | .then(res => res.json())
171
+ 80 | .then(data => {
172
+ 81 | setConfig(data); (src/components/ClientApp.tsx:100:29)
173
+ GET / 200 in 27ms (next.js: 3ms, application-code: 24ms)
174
+ [browser] A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR-ed Client Component used:
175
+
176
+ - A server/client branch `if (typeof window !== 'undefined')`.
177
+ - Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.
178
+ - Date formatting in a user's locale which doesn't match the server.
179
+ - External changing data without sending a snapshot of it along with the HTML.
180
+ - Invalid HTML tag nesting.
181
+
182
+ It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
183
+
184
+ https://react.dev/link/hydration-mismatch
185
+
186
+ ...
187
+ <HotReload globalError={[...]} webSocket={WebSocket} staticIndicatorState={{pathname:null, ...}}>
188
+ <AppDevOverlayErrorBoundary globalError={[...]}>
189
+ <ReplaySsrOnlyErrors>
190
+ <DevRootHTTPAccessFallbackBoundary>
191
+ <HTTPAccessFallbackBoundary notFound={<NotAllowedRootHTTPFallbackError>}>
192
+ <HTTPAccessFallbackErrorBoundary pathname="/" notFound={<NotAllowedRootHTTPFallbackError>} ...>
193
+ <RedirectBoundary>
194
+ <RedirectErrorBoundary router={{...}}>
195
+ <Head>
196
+ <__next_root_layout_boundary__>
197
+ <SegmentViewNode type="layout" pagePath="layout.tsx">
198
+ <SegmentTrieNode>
199
+ <link>
200
+ <script>
201
+ <script>
202
+ <RootLayout>
203
+ <html
204
+ lang="en"
205
+ - data-jetski-tab-id="11505257"
206
+ >
207
+ ...
208
+
209
+ [browser] Failed to load config TypeError: Failed to fetch
210
+ at ClientApp.useEffect (src/components/ClientApp.tsx:78:5)
211
+ 76 |
212
+ 77 | useEffect(() => {
213
+ > 78 | fetch(`${API_URL}/api/config`)
214
+ | ^
215
+ 79 | .then(res => res.json())
216
+ 80 | .then(data => {
217
+ 81 | setConfig(data); (src/components/ClientApp.tsx:100:29)
218
+ GET /api/config 404 in 301ms (next.js: 272ms, application-code: 29ms)
219
+ [browser] A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR-ed Client Component used:
220
+
221
+ - A server/client branch `if (typeof window !== 'undefined')`.
222
+ - Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.
223
+ - Date formatting in a user's locale which doesn't match the server.
224
+ - External changing data without sending a snapshot of it along with the HTML.
225
+ - Invalid HTML tag nesting.
226
+
227
+ It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
228
+
229
+ https://react.dev/link/hydration-mismatch
230
+
231
+ ...
232
+ <HotReload globalError={[...]} webSocket={WebSocket} staticIndicatorState={{pathname:null, ...}}>
233
+ <AppDevOverlayErrorBoundary globalError={[...]}>
234
+ <ReplaySsrOnlyErrors>
235
+ <DevRootHTTPAccessFallbackBoundary>
236
+ <HTTPAccessFallbackBoundary notFound={<NotAllowedRootHTTPFallbackError>}>
237
+ <HTTPAccessFallbackErrorBoundary pathname="/api/config" notFound={<NotAllowedRootHTTPFallbackError>} ...>
238
+ <RedirectBoundary>
239
+ <RedirectErrorBoundary router={{...}}>
240
+ <Head>
241
+ <__next_root_layout_boundary__>
242
+ <SegmentViewNode type="layout" pagePath="layout.tsx">
243
+ <SegmentTrieNode>
244
+ <link>
245
+ <script>
246
+ <script>
247
+ <RootLayout>
248
+ <html
249
+ lang="en"
250
+ - data-jetski-tab-id="11505257"
251
+ >
252
+ ...
253
+
254
+ GET / 200 in 26ms (next.js: 3ms, application-code: 23ms)
255
+ [browser] A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR-ed Client Component used:
256
+
257
+ - A server/client branch `if (typeof window !== 'undefined')`.
258
+ - Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.
259
+ - Date formatting in a user's locale which doesn't match the server.
260
+ - External changing data without sending a snapshot of it along with the HTML.
261
+ - Invalid HTML tag nesting.
262
+
263
+ It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
264
+
265
+ https://react.dev/link/hydration-mismatch
266
+
267
+ ...
268
+ <HotReload globalError={[...]} webSocket={WebSocket} staticIndicatorState={{pathname:null, ...}}>
269
+ <AppDevOverlayErrorBoundary globalError={[...]}>
270
+ <ReplaySsrOnlyErrors>
271
+ <DevRootHTTPAccessFallbackBoundary>
272
+ <HTTPAccessFallbackBoundary notFound={<NotAllowedRootHTTPFallbackError>}>
273
+ <HTTPAccessFallbackErrorBoundary pathname="/" notFound={<NotAllowedRootHTTPFallbackError>} ...>
274
+ <RedirectBoundary>
275
+ <RedirectErrorBoundary router={{...}}>
276
+ <Head>
277
+ <__next_root_layout_boundary__>
278
+ <SegmentViewNode type="layout" pagePath="layout.tsx">
279
+ <SegmentTrieNode>
280
+ <link>
281
+ <script>
282
+ <script>
283
+ <RootLayout>
284
+ <html
285
+ lang="en"
286
+ - data-jetski-tab-id="11505257"
287
+ >
288
+ ...
289
+
290
+ [browser] Failed to load config TypeError: Failed to fetch
291
+ at ClientApp.useEffect (src/components/ClientApp.tsx:78:5)
292
+ 76 |
293
+ 77 | useEffect(() => {
294
+ > 78 | fetch(`${API_URL}/api/config`)
295
+ | ^
296
+ 79 | .then(res => res.json())
297
+ 80 | .then(data => {
298
+ 81 | setConfig(data); (src/components/ClientApp.tsx:100:29)
299
+ GET / 200 in 34ms (next.js: 3ms, application-code: 31ms)
300
+ [browser] A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR-ed Client Component used:
301
+
302
+ - A server/client branch `if (typeof window !== 'undefined')`.
303
+ - Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.
304
+ - Date formatting in a user's locale which doesn't match the server.
305
+ - External changing data without sending a snapshot of it along with the HTML.
306
+ - Invalid HTML tag nesting.
307
+
308
+ It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
309
+
310
+ https://react.dev/link/hydration-mismatch
311
+
312
+ ...
313
+ <HotReload globalError={[...]} webSocket={WebSocket} staticIndicatorState={{pathname:null, ...}}>
314
+ <AppDevOverlayErrorBoundary globalError={[...]}>
315
+ <ReplaySsrOnlyErrors>
316
+ <DevRootHTTPAccessFallbackBoundary>
317
+ <HTTPAccessFallbackBoundary notFound={<NotAllowedRootHTTPFallbackError>}>
318
+ <HTTPAccessFallbackErrorBoundary pathname="/" notFound={<NotAllowedRootHTTPFallbackError>} ...>
319
+ <RedirectBoundary>
320
+ <RedirectErrorBoundary router={{...}}>
321
+ <Head>
322
+ <__next_root_layout_boundary__>
323
+ <SegmentViewNode type="layout" pagePath="layout.tsx">
324
+ <SegmentTrieNode>
325
+ <link>
326
+ <script>
327
+ <script>
328
+ <RootLayout>
329
+ <html
330
+ lang="en"
331
+ - data-jetski-tab-id="11505257"
332
+ >
333
+ ...
334
+
335
+ GET / 200 in 26ms (next.js: 3ms, application-code: 23ms)
336
+ [browser] A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR-ed Client Component used:
337
+
338
+ - A server/client branch `if (typeof window !== 'undefined')`.
339
+ - Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.
340
+ - Date formatting in a user's locale which doesn't match the server.
341
+ - External changing data without sending a snapshot of it along with the HTML.
342
+ - Invalid HTML tag nesting.
343
+
344
+ It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
345
+
346
+ https://react.dev/link/hydration-mismatch
347
+
348
+ ...
349
+ <HotReload globalError={[...]} webSocket={WebSocket} staticIndicatorState={{pathname:null, ...}}>
350
+ <AppDevOverlayErrorBoundary globalError={[...]}>
351
+ <ReplaySsrOnlyErrors>
352
+ <DevRootHTTPAccessFallbackBoundary>
353
+ <HTTPAccessFallbackBoundary notFound={<NotAllowedRootHTTPFallbackError>}>
354
+ <HTTPAccessFallbackErrorBoundary pathname="/" notFound={<NotAllowedRootHTTPFallbackError>} ...>
355
+ <RedirectBoundary>
356
+ <RedirectErrorBoundary router={{...}}>
357
+ <Head>
358
+ <__next_root_layout_boundary__>
359
+ <SegmentViewNode type="layout" pagePath="layout.tsx">
360
+ <SegmentTrieNode>
361
+ <link>
362
+ <script>
363
+ <script>
364
+ <RootLayout>
365
+ <html
366
+ lang="en"
367
+ - data-jetski-tab-id="11505257"
368
+ >
369
+ ...
370
+
371
+ GET / 200 in 21ms (next.js: 2ms, application-code: 19ms)
372
+ [browser] A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR-ed Client Component used:
373
+
374
+ - A server/client branch `if (typeof window !== 'undefined')`.
375
+ - Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.
376
+ - Date formatting in a user's locale which doesn't match the server.
377
+ - External changing data without sending a snapshot of it along with the HTML.
378
+ - Invalid HTML tag nesting.
379
+
380
+ It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
381
+
382
+ https://react.dev/link/hydration-mismatch
383
+
384
+ ...
385
+ <HotReload globalError={[...]} webSocket={WebSocket} staticIndicatorState={{pathname:null, ...}}>
386
+ <AppDevOverlayErrorBoundary globalError={[...]}>
387
+ <ReplaySsrOnlyErrors>
388
+ <DevRootHTTPAccessFallbackBoundary>
389
+ <HTTPAccessFallbackBoundary notFound={<NotAllowedRootHTTPFallbackError>}>
390
+ <HTTPAccessFallbackErrorBoundary pathname="/" notFound={<NotAllowedRootHTTPFallbackError>} ...>
391
+ <RedirectBoundary>
392
+ <RedirectErrorBoundary router={{...}}>
393
+ <Head>
394
+ <__next_root_layout_boundary__>
395
+ <SegmentViewNode type="layout" pagePath="layout.tsx">
396
+ <SegmentTrieNode>
397
+ <link>
398
+ <script>
399
+ <script>
400
+ <RootLayout>
401
+ <html
402
+ lang="en"
403
+ - data-jetski-tab-id="11505257"
404
+ >
405
+ ...
406
+
407
+ GET / 200 in 24ms (next.js: 1710┬╡s, application-code: 23ms)
408
+ Γ£ô Compiled in 40ms
409
+ GET / 200 in 118ms (next.js: 56ms, application-code: 62ms)
410
+ GET / 200 in 37ms (next.js: 3ms, application-code: 35ms)
411
+ [browser] A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR-ed Client Component used:
412
+
413
+ - A server/client branch `if (typeof window !== 'undefined')`.
414
+ - Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.
415
+ - Date formatting in a user's locale which doesn't match the server.
416
+ - External changing data without sending a snapshot of it along with the HTML.
417
+ - Invalid HTML tag nesting.
418
+
419
+ It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
420
+
421
+ https://react.dev/link/hydration-mismatch
422
+
423
+ ...
424
+ <HotReload globalError={[...]} webSocket={WebSocket} staticIndicatorState={{pathname:null, ...}}>
425
+ <AppDevOverlayErrorBoundary globalError={[...]}>
426
+ <ReplaySsrOnlyErrors>
427
+ <DevRootHTTPAccessFallbackBoundary>
428
+ <HTTPAccessFallbackBoundary notFound={<NotAllowedRootHTTPFallbackError>}>
429
+ <HTTPAccessFallbackErrorBoundary pathname="/" notFound={<NotAllowedRootHTTPFallbackError>} ...>
430
+ <RedirectBoundary>
431
+ <RedirectErrorBoundary router={{...}}>
432
+ <Head>
433
+ <__next_root_layout_boundary__>
434
+ <SegmentViewNode type="layout" pagePath="layout.tsx">
435
+ <SegmentTrieNode>
436
+ <link>
437
+ <script>
438
+ <script>
439
+ <RootLayout>
440
+ <html
441
+ lang="en"
442
+ - data-jetski-tab-id="11505259"
443
+ >
444
+ ...
445
+
446
+ Γ£ô Compiled in 46ms
447
+ Γ¿» ./src/components/ClientApp.tsx:496:20
448
+ Unterminated regexp literal
449
+ 494 | </div>
450
+ 495 | </div>
451
+ > 496 | </div>
452
+ | ^^^^^
453
+ 497 | )}
454
+ 498 | {activeTab === 'identity' && (
455
+ 499 | <div className="w-full">
456
+
457
+ Parsing ecmascript source code failed
458
+
459
+ Import trace:
460
+ Server Component:
461
+ ./src/components/ClientApp.tsx
462
+ ./src/app/page.tsx
463
+
464
+
465
+ Γ¿» ./src/components/ClientApp.tsx:496:20
466
+ Unterminated regexp literal
467
+ 494 | </div>
468
+ 495 | </div>
469
+ > 496 | </div>
470
+ | ^^^^^
471
+ 497 | )}
472
+ 498 | {activeTab === 'identity' && (
473
+ 499 | <div className="w-full">
474
+
475
+ Parsing ecmascript source code failed
476
+
477
+ Import trace:
478
+ Server Component:
479
+ ./src/components/ClientApp.tsx
480
+ ./src/app/page.tsx
481
+
482
+
483
+ [browser] ./src/components/ClientApp.tsx:496:20
484
+ Unterminated regexp literal
485
+ 494 | </div>
486
+ 495 | </div>
487
+ > 496 | </div>
488
+ | ^^^^^
489
+ 497 | )}
490
+ 498 | {activeTab === 'identity' && (
491
+ 499 | <div className="w-full">
492
+
493
+ Parsing ecmascript source code failed
494
+
495
+ Import trace:
496
+ Server Component:
497
+ ./src/components/ClientApp.tsx
498
+ ./src/app/page.tsx
499
+ [browser] ./src/components/ClientApp.tsx:496:20
500
+ Unterminated regexp literal
501
+ 494 | </div>
502
+ 495 | </div>
503
+ > 496 | </div>
504
+ | ^^^^^
505
+ 497 | )}
506
+ 498 | {activeTab === 'identity' && (
507
+ 499 | <div className="w-full">
508
+
509
+ Parsing ecmascript source code failed
510
+
511
+ Import trace:
512
+ Server Component:
513
+ ./src/components/ClientApp.tsx
514
+ ./src/app/page.tsx
515
+ [browser] ./src/components/ClientApp.tsx:496:20
516
+ Unterminated regexp literal
517
+ 494 | </div>
518
+ 495 | </div>
519
+ > 496 | </div>
520
+ | ^^^^^
521
+ 497 | )}
522
+ 498 | {activeTab === 'identity' && (
523
+ 499 | <div className="w-full">
524
+
525
+ Parsing ecmascript source code failed
526
+
527
+ Import trace:
528
+ Server Component:
529
+ ./src/components/ClientApp.tsx
530
+ ./src/app/page.tsx
531
+ GET / 500 in 290ms (next.js: 153ms, application-code: 137ms)
532
+ GET / 500 in 292ms (next.js: 280ms, application-code: 12ms)
533
+ [browser] ./src/components/ClientApp.tsx:496:20
534
+ Unterminated regexp literal
535
+ 494 | </div>
536
+ 495 | </div>
537
+ > 496 | </div>
538
+ | ^^^^^
539
+ 497 | )}
540
+ 498 | {activeTab === 'identity' && (
541
+ 499 | <div className="w-full">
542
+
543
+ Parsing ecmascript source code failed
544
+
545
+ Import trace:
546
+ Server Component:
547
+ ./src/components/ClientApp.tsx
548
+ ./src/app/page.tsx
549
+ Γ¿» ./src/components/ClientApp.tsx:496:20
550
+ Unterminated regexp literal
551
+ 494 | </div>
552
+ 495 | </div>
553
+ > 496 | </div>
554
+ | ^^^^^
555
+ 497 | )}
556
+ 498 | {activeTab === 'identity' && (
557
+ 499 | <div className="w-full">
558
+
559
+ Parsing ecmascript source code failed
560
+
561
+ Import trace:
562
+ Server Component:
563
+ ./src/components/ClientApp.tsx
564
+ ./src/app/page.tsx
565
+
566
+
567
+ [browser] ./src/components/ClientApp.tsx:496:20
568
+ Unterminated regexp literal
569
+ 494 | </div>
570
+ 495 | </div>
571
+ > 496 | </div>
572
+ | ^^^^^
573
+ 497 | )}
574
+ 498 | {activeTab === 'identity' && (
575
+ 499 | <div className="w-full">
576
+
577
+ Parsing ecmascript source code failed
578
+
579
+ Import trace:
580
+ Server Component:
581
+ ./src/components/ClientApp.tsx
582
+ ./src/app/page.tsx
583
+ Γ¿» ./src/components/ClientApp.tsx:496:20
584
+ Unterminated regexp literal
585
+ 494 | </div>
586
+ 495 | </div>
587
+ > 496 | </div>
588
+ | ^^^^^
589
+ 497 | )}
590
+ 498 | {activeTab === 'identity' && (
591
+ 499 | <div className="w-full">
592
+
593
+ Parsing ecmascript source code failed
594
+
595
+ Import trace:
596
+ Server Component:
597
+ ./src/components/ClientApp.tsx
598
+ ./src/app/page.tsx
599
+
600
+
601
+ GET / 500 in 20ms (next.js: 9ms, application-code: 11ms)
602
+ Γ¿» ./src/components/ClientApp.tsx:496:20
603
+ Unterminated regexp literal
604
+ 494 | </div>
605
+ 495 | </div>
606
+ > 496 | </div>
607
+ | ^^^^^
608
+ 497 | )}
609
+ 498 | {activeTab === 'identity' && (
610
+ 499 | <div className="w-full">
611
+
612
+ Parsing ecmascript source code failed
613
+
614
+ Import trace:
615
+ Server Component:
616
+ ./src/components/ClientApp.tsx
617
+ ./src/app/page.tsx
618
+
619
+
620
+ GET / 500 in 25ms (next.js: 16ms, application-code: 10ms)
621
+ Γ¿» ./src/components/ClientApp.tsx:496:20
622
+ Unterminated regexp literal
623
+ 494 | </div>
624
+ 495 | </div>
625
+ > 496 | </div>
626
+ | ^^^^^
627
+ 497 | )}
628
+ 498 | {activeTab === 'identity' && (
629
+ 499 | <div className="w-full">
630
+
631
+ Parsing ecmascript source code failed
632
+
633
+ Import trace:
634
+ Server Component:
635
+ ./src/components/ClientApp.tsx
636
+ ./src/app/page.tsx
637
+
638
+
639
+ GET / 500 in 35ms (next.js: 18ms, application-code: 17ms)
640
+ GET / 500 in 26ms (next.js: 16ms, application-code: 9ms)
641
+ Γ¿» ./src/components/ClientApp.tsx:496:20
642
+ Unterminated regexp literal
643
+ 494 | </div>
644
+ 495 | </div>
645
+ > 496 | </div>
646
+ | ^^^^^
647
+ 497 | )}
648
+ 498 | {activeTab === 'identity' && (
649
+ 499 | <div className="w-full">
650
+
651
+ Parsing ecmascript source code failed
652
+
653
+ Import trace:
654
+ Server Component:
655
+ ./src/components/ClientApp.tsx
656
+ ./src/app/page.tsx
657
+
658
+
659
+ Γ¿» ./src/components/ClientApp.tsx:496:20
660
+ Unterminated regexp literal
661
+ 494 | </div>
662
+ 495 | </div>
663
+ > 496 | </div>
664
+ | ^^^^^
665
+ 497 | )}
666
+ 498 | {activeTab === 'identity' && (
667
+ 499 | <div className="w-full">
668
+
669
+ Parsing ecmascript source code failed
670
+
671
+ Import trace:
672
+ Server Component:
673
+ ./src/components/ClientApp.tsx
674
+ ./src/app/page.tsx
675
+
676
+
677
+ GET / 500 in 25ms (next.js: 13ms, application-code: 12ms)
678
+ GET / 500 in 42ms (next.js: 22ms, application-code: 20ms)
679
+ [browser] Uncaught Error: ./src/components/ClientApp.tsx:496:20
680
+ Unterminated regexp literal
681
+ 494 | </div>
682
+ 495 | </div>
683
+ > 496 | </div>
684
+ | ^^^^^
685
+ 497 | )}
686
+ 498 | {activeTab === 'identity' && (
687
+ 499 | <div className="w-full">
688
+
689
+ Parsing ecmascript source code failed
690
+
691
+ Import trace:
692
+ Server Component:
693
+ ./src/components/ClientApp.tsx
694
+ ./src/app/page.tsx
695
+
696
+
697
+ at <unknown> (Error: ./src/components/ClientApp.tsx:496:20)
698
+ at <unknown> (Error: (./src/components/ClientApp.tsx:496:20)
699
+ [browser] Uncaught Error: ./src/components/ClientApp.tsx:496:20
700
+ Unterminated regexp literal
701
+ 494 | </div>
702
+ 495 | </div>
703
+ > 496 | </div>
704
+ | ^^^^^
705
+ 497 | )}
706
+ 498 | {activeTab === 'identity' && (
707
+ 499 | <div className="w-full">
708
+
709
+ Parsing ecmascript source code failed
710
+
711
+ Import trace:
712
+ Server Component:
713
+ ./src/components/ClientApp.tsx
714
+ ./src/app/page.tsx
715
+
716
+
717
+ at <unknown> (Error: ./src/components/ClientApp.tsx:496:20)
718
+ at <unknown> (Error: (./src/components/ClientApp.tsx:496:20)
719
+ [browser] ./src/components/ClientApp.tsx:496:20
720
+ Unterminated regexp literal
721
+ 494 | </div>
722
+ 495 | </div>
723
+ > 496 | </div>
724
+ | ^^^^^
725
+ 497 | )}
726
+ 498 | {activeTab === 'identity' && (
727
+ 499 | <div className="w-full">
728
+
729
+ Parsing ecmascript source code failed
730
+
731
+ Import trace:
732
+ Server Component:
733
+ ./src/components/ClientApp.tsx
734
+ ./src/app/page.tsx
735
+ [browser] Uncaught Error: ./src/components/ClientApp.tsx:496:20
736
+ Unterminated regexp literal
737
+ 494 | </div>
738
+ 495 | </div>
739
+ > 496 | </div>
740
+ | ^^^^^
741
+ 497 | )}
742
+ 498 | {activeTab === 'identity' && (
743
+ 499 | <div className="w-full">
744
+
745
+ Parsing ecmascript source code failed
746
+
747
+ Import trace:
748
+ Server Component:
749
+ ./src/components/ClientApp.tsx
750
+ ./src/app/page.tsx
751
+
752
+
753
+ at <unknown> (Error: ./src/components/ClientApp.tsx:496:20)
754
+ at <unknown> (Error: (./src/components/ClientApp.tsx:496:20)
755
+ [browser] ./src/components/ClientApp.tsx:496:20
756
+ Unterminated regexp literal
757
+ 494 | </div>
758
+ 495 | </div>
759
+ > 496 | </div>
760
+ | ^^^^^
761
+ 497 | )}
762
+ 498 | {activeTab === 'identity' && (
763
+ 499 | <div className="w-full">
764
+
765
+ Parsing ecmascript source code failed
766
+
767
+ Import trace:
768
+ Server Component:
769
+ ./src/components/ClientApp.tsx
770
+ ./src/app/page.tsx
771
+ [browser] ./src/components/ClientApp.tsx:496:20
772
+ Unterminated regexp literal
773
+ 494 | </div>
774
+ 495 | </div>
775
+ > 496 | </div>
776
+ | ^^^^^
777
+ 497 | )}
778
+ 498 | {activeTab === 'identity' && (
779
+ 499 | <div className="w-full">
780
+
781
+ Parsing ecmascript source code failed
782
+
783
+ Import trace:
784
+ Server Component:
785
+ ./src/components/ClientApp.tsx
786
+ ./src/app/page.tsx
787
+ [browser] ./src/components/ClientApp.tsx:496:20
788
+ Unterminated regexp literal
789
+ 494 | </div>
790
+ 495 | </div>
791
+ > 496 | </div>
792
+ | ^^^^^
793
+ 497 | )}
794
+ 498 | {activeTab === 'identity' && (
795
+ 499 | <div className="w-full">
796
+
797
+ Parsing ecmascript source code failed
798
+
799
+ Import trace:
800
+ Server Component:
801
+ ./src/components/ClientApp.tsx
802
+ ./src/app/page.tsx
803
+ [browser] ./src/components/ClientApp.tsx:496:20
804
+ Unterminated regexp literal
805
+ 494 | </div>
806
+ 495 | </div>
807
+ > 496 | </div>
808
+ | ^^^^^
809
+ 497 | )}
810
+ 498 | {activeTab === 'identity' && (
811
+ 499 | <div className="w-full">
812
+
813
+ Parsing ecmascript source code failed
814
+
815
+ Import trace:
816
+ Server Component:
817
+ ./src/components/ClientApp.tsx
818
+ ./src/app/page.tsx
819
+ [browser] ./src/components/ClientApp.tsx:496:20
820
+ Unterminated regexp literal
821
+ 494 | </div>
822
+ 495 | </div>
823
+ > 496 | </div>
824
+ | ^^^^^
825
+ 497 | )}
826
+ 498 | {activeTab === 'identity' && (
827
+ 499 | <div className="w-full">
828
+
829
+ Parsing ecmascript source code failed
830
+
831
+ Import trace:
832
+ Server Component:
833
+ ./src/components/ClientApp.tsx
834
+ ./src/app/page.tsx
835
+ [browser] ./src/components/ClientApp.tsx:496:20
836
+ Unterminated regexp literal
837
+ 494 | </div>
838
+ 495 | </div>
839
+ > 496 | </div>
840
+ | ^^^^^
841
+ 497 | )}
842
+ 498 | {activeTab === 'identity' && (
843
+ 499 | <div className="w-full">
844
+
845
+ Parsing ecmascript source code failed
846
+
847
+ Import trace:
848
+ Server Component:
849
+ ./src/components/ClientApp.tsx
850
+ ./src/app/page.tsx
851
+ [browser] ./src/components/ClientApp.tsx:496:20
852
+ Unterminated regexp literal
853
+ 494 | </div>
854
+ 495 | </div>
855
+ > 496 | </div>
856
+ | ^^^^^
857
+ 497 | )}
858
+ 498 | {activeTab === 'identity' && (
859
+ 499 | <div className="w-full">
860
+
861
+ Parsing ecmascript source code failed
862
+
863
+ Import trace:
864
+ Server Component:
865
+ ./src/components/ClientApp.tsx
866
+ ./src/app/page.tsx
867
+ [browser] ./src/components/ClientApp.tsx:496:20
868
+ Unterminated regexp literal
869
+ 494 | </div>
870
+ 495 | </div>
871
+ > 496 | </div>
872
+ | ^^^^^
873
+ 497 | )}
874
+ 498 | {activeTab === 'identity' && (
875
+ 499 | <div className="w-full">
876
+
877
+ Parsing ecmascript source code failed
878
+
879
+ Import trace:
880
+ Server Component:
881
+ ./src/components/ClientApp.tsx
882
+ ./src/app/page.tsx
883
+ [browser] ./src/components/ClientApp.tsx:496:20
884
+ Unterminated regexp literal
885
+ 494 | </div>
886
+ 495 | </div>
887
+ > 496 | </div>
888
+ | ^^^^^
889
+ 497 | )}
890
+ 498 | {activeTab === 'identity' && (
891
+ 499 | <div className="w-full">
892
+
893
+ Parsing ecmascript source code failed
894
+
895
+ Import trace:
896
+ Server Component:
897
+ ./src/components/ClientApp.tsx
898
+ ./src/app/page.tsx
899
+ [browser] ./src/components/ClientApp.tsx:496:20
900
+ Unterminated regexp literal
901
+ 494 | </div>
902
+ 495 | </div>
903
+ > 496 | </div>
904
+ | ^^^^^
905
+ 497 | )}
906
+ 498 | {activeTab === 'identity' && (
907
+ 499 | <div className="w-full">
908
+
909
+ Parsing ecmascript source code failed
910
+
911
+ Import trace:
912
+ Server Component:
913
+ ./src/components/ClientApp.tsx
914
+ ./src/app/page.tsx
915
+ [browser] ./src/components/ClientApp.tsx:496:20
916
+ Unterminated regexp literal
917
+ 494 | </div>
918
+ 495 | </div>
919
+ > 496 | </div>
920
+ | ^^^^^
921
+ 497 | )}
922
+ 498 | {activeTab === 'identity' && (
923
+ 499 | <div className="w-full">
924
+
925
+ Parsing ecmascript source code failed
926
+
927
+ Import trace:
928
+ Server Component:
929
+ ./src/components/ClientApp.tsx
930
+ ./src/app/page.tsx
931
+ [browser] ./src/components/ClientApp.tsx:496:20
932
+ Unterminated regexp literal
933
+ 494 | </div>
934
+ 495 | </div>
935
+ > 496 | </div>
936
+ | ^^^^^
937
+ 497 | )}
938
+ 498 | {activeTab === 'identity' && (
939
+ 499 | <div className="w-full">
940
+
941
+ Parsing ecmascript source code failed
942
+
943
+ Import trace:
944
+ Server Component:
945
+ ./src/components/ClientApp.tsx
946
+ ./src/app/page.tsx
947
+ [browser] ./src/components/ClientApp.tsx:496:20
948
+ Unterminated regexp literal
949
+ 494 | </div>
950
+ 495 | </div>
951
+ > 496 | </div>
952
+ | ^^^^^
953
+ 497 | )}
954
+ 498 | {activeTab === 'identity' && (
955
+ 499 | <div className="w-full">
956
+
957
+ Parsing ecmascript source code failed
958
+
959
+ Import trace:
960
+ Server Component:
961
+ ./src/components/ClientApp.tsx
962
+ ./src/app/page.tsx
963
+ [browser] ./src/components/ClientApp.tsx:496:20
964
+ Unterminated regexp literal
965
+ 494 | </div>
966
+ 495 | </div>
967
+ > 496 | </div>
968
+ | ^^^^^
969
+ 497 | )}
970
+ 498 | {activeTab === 'identity' && (
971
+ 499 | <div className="w-full">
972
+
973
+ Parsing ecmascript source code failed
974
+
975
+ Import trace:
976
+ Server Component:
977
+ ./src/components/ClientApp.tsx
978
+ ./src/app/page.tsx
979
+ [browser] ./src/components/ClientApp.tsx:496:20
980
+ Unterminated regexp literal
981
+ 494 | </div>
982
+ 495 | </div>
983
+ > 496 | </div>
984
+ | ^^^^^
985
+ 497 | )}
986
+ 498 | {activeTab === 'identity' && (
987
+ 499 | <div className="w-full">
988
+
989
+ Parsing ecmascript source code failed
990
+
991
+ Import trace:
992
+ Server Component:
993
+ ./src/components/ClientApp.tsx
994
+ ./src/app/page.tsx
995
+ [browser] ./src/components/ClientApp.tsx:496:20
996
+ Unterminated regexp literal
997
+ 494 | </div>
998
+ 495 | </div>
999
+ > 496 | </div>
1000
+ | ^^^^^
1001
+ 497 | )}
1002
+ 498 | {activeTab === 'identity' && (
1003
+ 499 | <div className="w-full">
1004
+
1005
+ Parsing ecmascript source code failed
1006
+
1007
+ Import trace:
1008
+ Server Component:
1009
+ ./src/components/ClientApp.tsx
1010
+ ./src/app/page.tsx
1011
+ [browser] ./src/components/ClientApp.tsx:496:20
1012
+ Unterminated regexp literal
1013
+ 494 | </div>
1014
+ 495 | </div>
1015
+ > 496 | </div>
1016
+ | ^^^^^
1017
+ 497 | )}
1018
+ 498 | {activeTab === 'identity' && (
1019
+ 499 | <div className="w-full">
1020
+
1021
+ Parsing ecmascript source code failed
1022
+
1023
+ Import trace:
1024
+ Server Component:
1025
+ ./src/components/ClientApp.tsx
1026
+ ./src/app/page.tsx
1027
+ [browser] ./src/components/ClientApp.tsx:496:20
1028
+ Unterminated regexp literal
1029
+ 494 | </div>
1030
+ 495 | </div>
1031
+ > 496 | </div>
1032
+ | ^^^^^
1033
+ 497 | )}
1034
+ 498 | {activeTab === 'identity' && (
1035
+ 499 | <div className="w-full">
1036
+
1037
+ Parsing ecmascript source code failed
1038
+
1039
+ Import trace:
1040
+ Server Component:
1041
+ ./src/components/ClientApp.tsx
1042
+ ./src/app/page.tsx
1043
+ [browser] ./src/components/ClientApp.tsx:496:20
1044
+ Unterminated regexp literal
1045
+ 494 | </div>
1046
+ 495 | </div>
1047
+ > 496 | </div>
1048
+ | ^^^^^
1049
+ 497 | )}
1050
+ 498 | {activeTab === 'identity' && (
1051
+ 499 | <div className="w-full">
1052
+
1053
+ Parsing ecmascript source code failed
1054
+
1055
+ Import trace:
1056
+ Server Component:
1057
+ ./src/components/ClientApp.tsx
1058
+ ./src/app/page.tsx
1059
+ [browser] ./src/components/ClientApp.tsx:496:20
1060
+ Unterminated regexp literal
1061
+ 494 | </div>
1062
+ 495 | </div>
1063
+ > 496 | </div>
1064
+ | ^^^^^
1065
+ 497 | )}
1066
+ 498 | {activeTab === 'identity' && (
1067
+ 499 | <div className="w-full">
1068
+
1069
+ Parsing ecmascript source code failed
1070
+
1071
+ Import trace:
1072
+ Server Component:
1073
+ ./src/components/ClientApp.tsx
1074
+ ./src/app/page.tsx
1075
+ [browser] ./src/components/ClientApp.tsx:496:20
1076
+ Unterminated regexp literal
1077
+ 494 | </div>
1078
+ 495 | </div>
1079
+ > 496 | </div>
1080
+ | ^^^^^
1081
+ 497 | )}
1082
+ 498 | {activeTab === 'identity' && (
1083
+ 499 | <div className="w-full">
1084
+
1085
+ Parsing ecmascript source code failed
1086
+
1087
+ Import trace:
1088
+ Server Component:
1089
+ ./src/components/ClientApp.tsx
1090
+ ./src/app/page.tsx
1091
+ [browser] ./src/components/ClientApp.tsx:496:20
1092
+ Unterminated regexp literal
1093
+ 494 | </div>
1094
+ 495 | </div>
1095
+ > 496 | </div>
1096
+ | ^^^^^
1097
+ 497 | )}
1098
+ 498 | {activeTab === 'identity' && (
1099
+ 499 | <div className="w-full">
1100
+
1101
+ Parsing ecmascript source code failed
1102
+
1103
+ Import trace:
1104
+ Server Component:
1105
+ ./src/components/ClientApp.tsx
1106
+ ./src/app/page.tsx
1107
+ [browser] ./src/components/ClientApp.tsx:496:20
1108
+ Unterminated regexp literal
1109
+ 494 | </div>
1110
+ 495 | </div>
1111
+ > 496 | </div>
1112
+ | ^^^^^
1113
+ 497 | )}
1114
+ 498 | {activeTab === 'identity' && (
1115
+ 499 | <div className="w-full">
1116
+
1117
+ Parsing ecmascript source code failed
1118
+
1119
+ Import trace:
1120
+ Server Component:
1121
+ ./src/components/ClientApp.tsx
1122
+ ./src/app/page.tsx
1123
+ [browser] ./src/components/ClientApp.tsx:496:20
1124
+ Unterminated regexp literal
1125
+ 494 | </div>
1126
+ 495 | </div>
1127
+ > 496 | </div>
1128
+ | ^^^^^
1129
+ 497 | )}
1130
+ 498 | {activeTab === 'identity' && (
1131
+ 499 | <div className="w-full">
1132
+
1133
+ Parsing ecmascript source code failed
1134
+
1135
+ Import trace:
1136
+ Server Component:
1137
+ ./src/components/ClientApp.tsx
1138
+ ./src/app/page.tsx
1139
+ [browser] ./src/components/ClientApp.tsx:496:20
1140
+ Unterminated regexp literal
1141
+ 494 | </div>
1142
+ 495 | </div>
1143
+ > 496 | </div>
1144
+ | ^^^^^
1145
+ 497 | )}
1146
+ 498 | {activeTab === 'identity' && (
1147
+ 499 | <div className="w-full">
1148
+
1149
+ Parsing ecmascript source code failed
1150
+
1151
+ Import trace:
1152
+ Server Component:
1153
+ ./src/components/ClientApp.tsx
1154
+ ./src/app/page.tsx
1155
+ [browser] ./src/components/ClientApp.tsx:496:20
1156
+ Unterminated regexp literal
1157
+ 494 | </div>
1158
+ 495 | </div>
1159
+ > 496 | </div>
1160
+ | ^^^^^
1161
+ 497 | )}
1162
+ 498 | {activeTab === 'identity' && (
1163
+ 499 | <div className="w-full">
1164
+
1165
+ Parsing ecmascript source code failed
1166
+
1167
+ Import trace:
1168
+ Server Component:
1169
+ ./src/components/ClientApp.tsx
1170
+ ./src/app/page.tsx
1171
+ [browser] ./src/components/ClientApp.tsx:496:20
1172
+ Unterminated regexp literal
1173
+ 494 | </div>
1174
+ 495 | </div>
1175
+ > 496 | </div>
1176
+ | ^^^^^
1177
+ 497 | )}
1178
+ 498 | {activeTab === 'identity' && (
1179
+ 499 | <div className="w-full">
1180
+
1181
+ Parsing ecmascript source code failed
1182
+
1183
+ Import trace:
1184
+ Server Component:
1185
+ ./src/components/ClientApp.tsx
1186
+ ./src/app/page.tsx
1187
+ [browser] ./src/components/ClientApp.tsx:496:20
1188
+ Unterminated regexp literal
1189
+ 494 | </div>
1190
+ 495 | </div>
1191
+ > 496 | </div>
1192
+ | ^^^^^
1193
+ 497 | )}
1194
+ 498 | {activeTab === 'identity' && (
1195
+ 499 | <div className="w-full">
1196
+
1197
+ Parsing ecmascript source code failed
1198
+
1199
+ Import trace:
1200
+ Server Component:
1201
+ ./src/components/ClientApp.tsx
1202
+ ./src/app/page.tsx
1203
+ [browser] ./src/components/ClientApp.tsx:496:20
1204
+ Unterminated regexp literal
1205
+ 494 | </div>
1206
+ 495 | </div>
1207
+ > 496 | </div>
1208
+ | ^^^^^
1209
+ 497 | )}
1210
+ 498 | {activeTab === 'identity' && (
1211
+ 499 | <div className="w-full">
1212
+
1213
+ Parsing ecmascript source code failed
1214
+
1215
+ Import trace:
1216
+ Server Component:
1217
+ ./src/components/ClientApp.tsx
1218
+ ./src/app/page.tsx
1219
+ [browser] ./src/components/ClientApp.tsx:496:20
1220
+ Unterminated regexp literal
1221
+ 494 | </div>
1222
+ 495 | </div>
1223
+ > 496 | </div>
1224
+ | ^^^^^
1225
+ 497 | )}
1226
+ 498 | {activeTab === 'identity' && (
1227
+ 499 | <div className="w-full">
1228
+
1229
+ Parsing ecmascript source code failed
1230
+
1231
+ Import trace:
1232
+ Server Component:
1233
+ ./src/components/ClientApp.tsx
1234
+ ./src/app/page.tsx
1235
+ [browser] ./src/components/ClientApp.tsx:496:20
1236
+ Unterminated regexp literal
1237
+ 494 | </div>
1238
+ 495 | </div>
1239
+ > 496 | </div>
1240
+ | ^^^^^
1241
+ 497 | )}
1242
+ 498 | {activeTab === 'identity' && (
1243
+ 499 | <div className="w-full">
1244
+
1245
+ Parsing ecmascript source code failed
1246
+
1247
+ Import trace:
1248
+ Server Component:
1249
+ ./src/components/ClientApp.tsx
1250
+ ./src/app/page.tsx
1251
+ [browser] ./src/components/ClientApp.tsx:496:20
1252
+ Unterminated regexp literal
1253
+ 494 | </div>
1254
+ 495 | </div>
1255
+ > 496 | </div>
1256
+ | ^^^^^
1257
+ 497 | )}
1258
+ 498 | {activeTab === 'identity' && (
1259
+ 499 | <div className="w-full">
1260
+
1261
+ Parsing ecmascript source code failed
1262
+
1263
+ Import trace:
1264
+ Server Component:
1265
+ ./src/components/ClientApp.tsx
1266
+ ./src/app/page.tsx
1267
+ [browser] ./src/components/ClientApp.tsx:496:20
1268
+ Unterminated regexp literal
1269
+ 494 | </div>
1270
+ 495 | </div>
1271
+ > 496 | </div>
1272
+ | ^^^^^
1273
+ 497 | )}
1274
+ 498 | {activeTab === 'identity' && (
1275
+ 499 | <div className="w-full">
1276
+
1277
+ Parsing ecmascript source code failed
1278
+
1279
+ Import trace:
1280
+ Server Component:
1281
+ ./src/components/ClientApp.tsx
1282
+ ./src/app/page.tsx
1283
+ [browser] ./src/components/ClientApp.tsx:496:20
1284
+ Unterminated regexp literal
1285
+ 494 | </div>
1286
+ 495 | </div>
1287
+ > 496 | </div>
1288
+ | ^^^^^
1289
+ 497 | )}
1290
+ 498 | {activeTab === 'identity' && (
1291
+ 499 | <div className="w-full">
1292
+
1293
+ Parsing ecmascript source code failed
1294
+
1295
+ Import trace:
1296
+ Server Component:
1297
+ ./src/components/ClientApp.tsx
1298
+ ./src/app/page.tsx
1299
+ [browser] ./src/components/ClientApp.tsx:496:20
1300
+ Unterminated regexp literal
1301
+ 494 | </div>
1302
+ 495 | </div>
1303
+ > 496 | </div>
1304
+ | ^^^^^
1305
+ 497 | )}
1306
+ 498 | {activeTab === 'identity' && (
1307
+ 499 | <div className="w-full">
1308
+
1309
+ Parsing ecmascript source code failed
1310
+
1311
+ Import trace:
1312
+ Server Component:
1313
+ ./src/components/ClientApp.tsx
1314
+ ./src/app/page.tsx
1315
+ [browser] ./src/components/ClientApp.tsx:496:20
1316
+ Unterminated regexp literal
1317
+ 494 | </div>
1318
+ 495 | </div>
1319
+ > 496 | </div>
1320
+ | ^^^^^
1321
+ 497 | )}
1322
+ 498 | {activeTab === 'identity' && (
1323
+ 499 | <div className="w-full">
1324
+
1325
+ Parsing ecmascript source code failed
1326
+
1327
+ Import trace:
1328
+ Server Component:
1329
+ ./src/components/ClientApp.tsx
1330
+ ./src/app/page.tsx
1331
+ [browser] ./src/components/ClientApp.tsx:496:20
1332
+ Unterminated regexp literal
1333
+ 494 | </div>
1334
+ 495 | </div>
1335
+ > 496 | </div>
1336
+ | ^^^^^
1337
+ 497 | )}
1338
+ 498 | {activeTab === 'identity' && (
1339
+ 499 | <div className="w-full">
1340
+
1341
+ Parsing ecmascript source code failed
1342
+
1343
+ Import trace:
1344
+ Server Component:
1345
+ ./src/components/ClientApp.tsx
1346
+ ./src/app/page.tsx
1347
+ [browser] ./src/components/ClientApp.tsx:496:20
1348
+ Unterminated regexp literal
1349
+ 494 | </div>
1350
+ 495 | </div>
1351
+ > 496 | </div>
1352
+ | ^^^^^
1353
+ 497 | )}
1354
+ 498 | {activeTab === 'identity' && (
1355
+ 499 | <div className="w-full">
1356
+
1357
+ Parsing ecmascript source code failed
1358
+
1359
+ Import trace:
1360
+ Server Component:
1361
+ ./src/components/ClientApp.tsx
1362
+ ./src/app/page.tsx
1363
+ [browser] ./src/components/ClientApp.tsx:496:20
1364
+ Unterminated regexp literal
1365
+ 494 | </div>
1366
+ 495 | </div>
1367
+ > 496 | </div>
1368
+ | ^^^^^
1369
+ 497 | )}
1370
+ 498 | {activeTab === 'identity' && (
1371
+ 499 | <div className="w-full">
1372
+
1373
+ Parsing ecmascript source code failed
1374
+
1375
+ Import trace:
1376
+ Server Component:
1377
+ ./src/components/ClientApp.tsx
1378
+ ./src/app/page.tsx
1379
+ [browser] ./src/components/ClientApp.tsx:496:20
1380
+ Unterminated regexp literal
1381
+ 494 | </div>
1382
+ 495 | </div>
1383
+ > 496 | </div>
1384
+ | ^^^^^
1385
+ 497 | )}
1386
+ 498 | {activeTab === 'identity' && (
1387
+ 499 | <div className="w-full">
1388
+
1389
+ Parsing ecmascript source code failed
1390
+
1391
+ Import trace:
1392
+ Server Component:
1393
+ ./src/components/ClientApp.tsx
1394
+ ./src/app/page.tsx
1395
+ [browser] ./src/components/ClientApp.tsx:496:20
1396
+ Unterminated regexp literal
1397
+ 494 | </div>
1398
+ 495 | </div>
1399
+ > 496 | </div>
1400
+ | ^^^^^
1401
+ 497 | )}
1402
+ 498 | {activeTab === 'identity' && (
1403
+ 499 | <div className="w-full">
1404
+
1405
+ Parsing ecmascript source code failed
1406
+
1407
+ Import trace:
1408
+ Server Component:
1409
+ ./src/components/ClientApp.tsx
1410
+ ./src/app/page.tsx
1411
+ [browser] ./src/components/ClientApp.tsx:496:20
1412
+ Unterminated regexp literal
1413
+ 494 | </div>
1414
+ 495 | </div>
1415
+ > 496 | </div>
1416
+ | ^^^^^
1417
+ 497 | )}
1418
+ 498 | {activeTab === 'identity' && (
1419
+ 499 | <div className="w-full">
1420
+
1421
+ Parsing ecmascript source code failed
1422
+
1423
+ Import trace:
1424
+ Server Component:
1425
+ ./src/components/ClientApp.tsx
1426
+ ./src/app/page.tsx
1427
+ [browser] ./src/components/ClientApp.tsx:496:20
1428
+ Unterminated regexp literal
1429
+ 494 | </div>
1430
+ 495 | </div>
1431
+ > 496 | </div>
1432
+ | ^^^^^
1433
+ 497 | )}
1434
+ 498 | {activeTab === 'identity' && (
1435
+ 499 | <div className="w-full">
1436
+
1437
+ Parsing ecmascript source code failed
1438
+
1439
+ Import trace:
1440
+ Server Component:
1441
+ ./src/components/ClientApp.tsx
1442
+ ./src/app/page.tsx
1443
+ [browser] ./src/components/ClientApp.tsx:496:20
1444
+ Unterminated regexp literal
1445
+ 494 | </div>
1446
+ 495 | </div>
1447
+ > 496 | </div>
1448
+ | ^^^^^
1449
+ 497 | )}
1450
+ 498 | {activeTab === 'identity' && (
1451
+ 499 | <div className="w-full">
1452
+
1453
+ Parsing ecmascript source code failed
1454
+
1455
+ Import trace:
1456
+ Server Component:
1457
+ ./src/components/ClientApp.tsx
1458
+ ./src/app/page.tsx
1459
+ [browser] ./src/components/ClientApp.tsx:496:20
1460
+ Unterminated regexp literal
1461
+ 494 | </div>
1462
+ 495 | </div>
1463
+ > 496 | </div>
1464
+ | ^^^^^
1465
+ 497 | )}
1466
+ 498 | {activeTab === 'identity' && (
1467
+ 499 | <div className="w-full">
1468
+
1469
+ Parsing ecmascript source code failed
1470
+
1471
+ Import trace:
1472
+ Server Component:
1473
+ ./src/components/ClientApp.tsx
1474
+ ./src/app/page.tsx
1475
+ [browser] ./src/components/ClientApp.tsx:496:20
1476
+ Unterminated regexp literal
1477
+ 494 | </div>
1478
+ 495 | </div>
1479
+ > 496 | </div>
1480
+ | ^^^^^
1481
+ 497 | )}
1482
+ 498 | {activeTab === 'identity' && (
1483
+ 499 | <div className="w-full">
1484
+
1485
+ Parsing ecmascript source code failed
1486
+
1487
+ Import trace:
1488
+ Server Component:
1489
+ ./src/components/ClientApp.tsx
1490
+ ./src/app/page.tsx
1491
+ [browser] ./src/components/ClientApp.tsx:496:20
1492
+ Unterminated regexp literal
1493
+ 494 | </div>
1494
+ 495 | </div>
1495
+ > 496 | </div>
1496
+ | ^^^^^
1497
+ 497 | )}
1498
+ 498 | {activeTab === 'identity' && (
1499
+ 499 | <div className="w-full">
1500
+
1501
+ Parsing ecmascript source code failed
1502
+
1503
+ Import trace:
1504
+ Server Component:
1505
+ ./src/components/ClientApp.tsx
1506
+ ./src/app/page.tsx
1507
+ [browser] ./src/components/ClientApp.tsx:496:20
1508
+ Unterminated regexp literal
1509
+ 494 | </div>
1510
+ 495 | </div>
1511
+ > 496 | </div>
1512
+ | ^^^^^
1513
+ 497 | )}
1514
+ 498 | {activeTab === 'identity' && (
1515
+ 499 | <div className="w-full">
1516
+
1517
+ Parsing ecmascript source code failed
1518
+
1519
+ Import trace:
1520
+ Server Component:
1521
+ ./src/components/ClientApp.tsx
1522
+ ./src/app/page.tsx
1523
+ [browser] ./src/components/ClientApp.tsx:496:20
1524
+ Unterminated regexp literal
1525
+ 494 | </div>
1526
+ 495 | </div>
1527
+ > 496 | </div>
1528
+ | ^^^^^
1529
+ 497 | )}
1530
+ 498 | {activeTab === 'identity' && (
1531
+ 499 | <div className="w-full">
1532
+
1533
+ Parsing ecmascript source code failed
1534
+
1535
+ Import trace:
1536
+ Server Component:
1537
+ ./src/components/ClientApp.tsx
1538
+ ./src/app/page.tsx
1539
+ [browser] ./src/components/ClientApp.tsx:496:20
1540
+ Unterminated regexp literal
1541
+ 494 | </div>
1542
+ 495 | </div>
1543
+ > 496 | </div>
1544
+ | ^^^^^
1545
+ 497 | )}
1546
+ 498 | {activeTab === 'identity' && (
1547
+ 499 | <div className="w-full">
1548
+
1549
+ Parsing ecmascript source code failed
1550
+
1551
+ Import trace:
1552
+ Server Component:
1553
+ ./src/components/ClientApp.tsx
1554
+ ./src/app/page.tsx
1555
+ [browser] ./src/components/ClientApp.tsx:496:20
1556
+ Unterminated regexp literal
1557
+ 494 | </div>
1558
+ 495 | </div>
1559
+ > 496 | </div>
1560
+ | ^^^^^
1561
+ 497 | )}
1562
+ 498 | {activeTab === 'identity' && (
1563
+ 499 | <div className="w-full">
1564
+
1565
+ Parsing ecmascript source code failed
1566
+
1567
+ Import trace:
1568
+ Server Component:
1569
+ ./src/components/ClientApp.tsx
1570
+ ./src/app/page.tsx
1571
+ [browser] ./src/components/ClientApp.tsx:496:20
1572
+ Unterminated regexp literal
1573
+ 494 | </div>
1574
+ 495 | </div>
1575
+ > 496 | </div>
1576
+ | ^^^^^
1577
+ 497 | )}
1578
+ 498 | {activeTab === 'identity' && (
1579
+ 499 | <div className="w-full">
1580
+
1581
+ Parsing ecmascript source code failed
1582
+
1583
+ Import trace:
1584
+ Server Component:
1585
+ ./src/components/ClientApp.tsx
1586
+ ./src/app/page.tsx
1587
+ [browser] ./src/components/ClientApp.tsx:496:20
1588
+ Unterminated regexp literal
1589
+ 494 | </div>
1590
+ 495 | </div>
1591
+ > 496 | </div>
1592
+ | ^^^^^
1593
+ 497 | )}
1594
+ 498 | {activeTab === 'identity' && (
1595
+ 499 | <div className="w-full">
1596
+
1597
+ Parsing ecmascript source code failed
1598
+
1599
+ Import trace:
1600
+ Server Component:
1601
+ ./src/components/ClientApp.tsx
1602
+ ./src/app/page.tsx
1603
+ [browser] ./src/components/ClientApp.tsx:496:20
1604
+ Unterminated regexp literal
1605
+ 494 | </div>
1606
+ 495 | </div>
1607
+ > 496 | </div>
1608
+ | ^^^^^
1609
+ 497 | )}
1610
+ 498 | {activeTab === 'identity' && (
1611
+ 499 | <div className="w-full">
1612
+
1613
+ Parsing ecmascript source code failed
1614
+
1615
+ Import trace:
1616
+ Server Component:
1617
+ ./src/components/ClientApp.tsx
1618
+ ./src/app/page.tsx
1619
+ [browser] ./src/components/ClientApp.tsx:496:20
1620
+ Unterminated regexp literal
1621
+ 494 | </div>
1622
+ 495 | </div>
1623
+ > 496 | </div>
1624
+ | ^^^^^
1625
+ 497 | )}
1626
+ 498 | {activeTab === 'identity' && (
1627
+ 499 | <div className="w-full">
1628
+
1629
+ Parsing ecmascript source code failed
1630
+
1631
+ Import trace:
1632
+ Server Component:
1633
+ ./src/components/ClientApp.tsx
1634
+ ./src/app/page.tsx
1635
+ [browser] ./src/components/ClientApp.tsx:496:20
1636
+ Unterminated regexp literal
1637
+ 494 | </div>
1638
+ 495 | </div>
1639
+ > 496 | </div>
1640
+ | ^^^^^
1641
+ 497 | )}
1642
+ 498 | {activeTab === 'identity' && (
1643
+ 499 | <div className="w-full">
1644
+
1645
+ Parsing ecmascript source code failed
1646
+
1647
+ Import trace:
1648
+ Server Component:
1649
+ ./src/components/ClientApp.tsx
1650
+ ./src/app/page.tsx
1651
+ [browser] ./src/components/ClientApp.tsx:496:20
1652
+ Unterminated regexp literal
1653
+ 494 | </div>
1654
+ 495 | </div>
1655
+ > 496 | </div>
1656
+ | ^^^^^
1657
+ 497 | )}
1658
+ 498 | {activeTab === 'identity' && (
1659
+ 499 | <div className="w-full">
1660
+
1661
+ Parsing ecmascript source code failed
1662
+
1663
+ Import trace:
1664
+ Server Component:
1665
+ ./src/components/ClientApp.tsx
1666
+ ./src/app/page.tsx
1667
+ [browser] ./src/components/ClientApp.tsx:496:20
1668
+ Unterminated regexp literal
1669
+ 494 | </div>
1670
+ 495 | </div>
1671
+ > 496 | </div>
1672
+ | ^^^^^
1673
+ 497 | )}
1674
+ 498 | {activeTab === 'identity' && (
1675
+ 499 | <div className="w-full">
1676
+
1677
+ Parsing ecmascript source code failed
1678
+
1679
+ Import trace:
1680
+ Server Component:
1681
+ ./src/components/ClientApp.tsx
1682
+ ./src/app/page.tsx
1683
+ [browser] ./src/components/ClientApp.tsx:496:20
1684
+ Unterminated regexp literal
1685
+ 494 | </div>
1686
+ 495 | </div>
1687
+ > 496 | </div>
1688
+ | ^^^^^
1689
+ 497 | )}
1690
+ 498 | {activeTab === 'identity' && (
1691
+ 499 | <div className="w-full">
1692
+
1693
+ Parsing ecmascript source code failed
1694
+
1695
+ Import trace:
1696
+ Server Component:
1697
+ ./src/components/ClientApp.tsx
1698
+ ./src/app/page.tsx
1699
+ [browser] ./src/components/ClientApp.tsx:496:20
1700
+ Unterminated regexp literal
1701
+ 494 | </div>
1702
+ 495 | </div>
1703
+ > 496 | </div>
1704
+ | ^^^^^
1705
+ 497 | )}
1706
+ 498 | {activeTab === 'identity' && (
1707
+ 499 | <div className="w-full">
1708
+
1709
+ Parsing ecmascript source code failed
1710
+
1711
+ Import trace:
1712
+ Server Component:
1713
+ ./src/components/ClientApp.tsx
1714
+ ./src/app/page.tsx
1715
+ [browser] ./src/components/ClientApp.tsx:496:20
1716
+ Unterminated regexp literal
1717
+ 494 | </div>
1718
+ 495 | </div>
1719
+ > 496 | </div>
1720
+ | ^^^^^
1721
+ 497 | )}
1722
+ 498 | {activeTab === 'identity' && (
1723
+ 499 | <div className="w-full">
1724
+
1725
+ Parsing ecmascript source code failed
1726
+
1727
+ Import trace:
1728
+ Server Component:
1729
+ ./src/components/ClientApp.tsx
1730
+ ./src/app/page.tsx
1731
+ [browser] ./src/components/ClientApp.tsx:496:20
1732
+ Unterminated regexp literal
1733
+ 494 | </div>
1734
+ 495 | </div>
1735
+ > 496 | </div>
1736
+ | ^^^^^
1737
+ 497 | )}
1738
+ 498 | {activeTab === 'identity' && (
1739
+ 499 | <div className="w-full">
1740
+
1741
+ Parsing ecmascript source code failed
1742
+
1743
+ Import trace:
1744
+ Server Component:
1745
+ ./src/components/ClientApp.tsx
1746
+ ./src/app/page.tsx
1747
+ [browser] ./src/components/ClientApp.tsx:496:20
1748
+ Unterminated regexp literal
1749
+ 494 | </div>
1750
+ 495 | </div>
1751
+ > 496 | </div>
1752
+ | ^^^^^
1753
+ 497 | )}
1754
+ 498 | {activeTab === 'identity' && (
1755
+ 499 | <div className="w-full">
1756
+
1757
+ Parsing ecmascript source code failed
1758
+
1759
+ Import trace:
1760
+ Server Component:
1761
+ ./src/components/ClientApp.tsx
1762
+ ./src/app/page.tsx
1763
+ [browser] ./src/components/ClientApp.tsx:496:20
1764
+ Unterminated regexp literal
1765
+ 494 | </div>
1766
+ 495 | </div>
1767
+ > 496 | </div>
1768
+ | ^^^^^
1769
+ 497 | )}
1770
+ 498 | {activeTab === 'identity' && (
1771
+ 499 | <div className="w-full">
1772
+
1773
+ Parsing ecmascript source code failed
1774
+
1775
+ Import trace:
1776
+ Server Component:
1777
+ ./src/components/ClientApp.tsx
1778
+ ./src/app/page.tsx
1779
+ [browser] ./src/components/ClientApp.tsx:496:20
1780
+ Unterminated regexp literal
1781
+ 494 | </div>
1782
+ 495 | </div>
1783
+ > 496 | </div>
1784
+ | ^^^^^
1785
+ 497 | )}
1786
+ 498 | {activeTab === 'identity' && (
1787
+ 499 | <div className="w-full">
1788
+
1789
+ Parsing ecmascript source code failed
1790
+
1791
+ Import trace:
1792
+ Server Component:
1793
+ ./src/components/ClientApp.tsx
1794
+ ./src/app/page.tsx
1795
+ [browser] ./src/components/ClientApp.tsx:496:20
1796
+ Unterminated regexp literal
1797
+ 494 | </div>
1798
+ 495 | </div>
1799
+ > 496 | </div>
1800
+ | ^^^^^
1801
+ 497 | )}
1802
+ 498 | {activeTab === 'identity' && (
1803
+ 499 | <div className="w-full">
1804
+
1805
+ Parsing ecmascript source code failed
1806
+
1807
+ Import trace:
1808
+ Server Component:
1809
+ ./src/components/ClientApp.tsx
1810
+ ./src/app/page.tsx
1811
+ [browser] ./src/components/ClientApp.tsx:496:20
1812
+ Unterminated regexp literal
1813
+ 494 | </div>
1814
+ 495 | </div>
1815
+ > 496 | </div>
1816
+ | ^^^^^
1817
+ 497 | )}
1818
+ 498 | {activeTab === 'identity' && (
1819
+ 499 | <div className="w-full">
1820
+
1821
+ Parsing ecmascript source code failed
1822
+
1823
+ Import trace:
1824
+ Server Component:
1825
+ ./src/components/ClientApp.tsx
1826
+ ./src/app/page.tsx
1827
+ [browser] ./src/components/ClientApp.tsx:496:20
1828
+ Unterminated regexp literal
1829
+ 494 | </div>
1830
+ 495 | </div>
1831
+ > 496 | </div>
1832
+ | ^^^^^
1833
+ 497 | )}
1834
+ 498 | {activeTab === 'identity' && (
1835
+ 499 | <div className="w-full">
1836
+
1837
+ Parsing ecmascript source code failed
1838
+
1839
+ Import trace:
1840
+ Server Component:
1841
+ ./src/components/ClientApp.tsx
1842
+ ./src/app/page.tsx
1843
+ GET / 200 in 317ms (next.js: 78ms, application-code: 239ms)
1844
+ GET / 200 in 197ms (next.js: 6ms, application-code: 191ms)
1845
+ GET / 200 in 97ms (next.js: 16ms, application-code: 81ms)
1846
+ [browser] A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR-ed Client Component used:
1847
+
1848
+ - A server/client branch `if (typeof window !== 'undefined')`.
1849
+ - Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.
1850
+ - Date formatting in a user's locale which doesn't match the server.
1851
+ - External changing data without sending a snapshot of it along with the HTML.
1852
+ - Invalid HTML tag nesting.
1853
+
1854
+ It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
1855
+
1856
+ https://react.dev/link/hydration-mismatch
1857
+
1858
+ ...
1859
+ <HotReload globalError={[...]} webSocket={WebSocket} staticIndicatorState={{pathname:null, ...}}>
1860
+ <AppDevOverlayErrorBoundary globalError={[...]}>
1861
+ <ReplaySsrOnlyErrors>
1862
+ <DevRootHTTPAccessFallbackBoundary>
1863
+ <HTTPAccessFallbackBoundary notFound={<NotAllowedRootHTTPFallbackError>}>
1864
+ <HTTPAccessFallbackErrorBoundary pathname="/" notFound={<NotAllowedRootHTTPFallbackError>} ...>
1865
+ <RedirectBoundary>
1866
+ <RedirectErrorBoundary router={{...}}>
1867
+ <Head>
1868
+ <__next_root_layout_boundary__>
1869
+ <SegmentViewNode type="layout" pagePath="layout.tsx">
1870
+ <SegmentTrieNode>
1871
+ <link>
1872
+ <script>
1873
+ <script>
1874
+ <RootLayout>
1875
+ <html
1876
+ lang="en"
1877
+ - data-jetski-tab-id="11505257"
1878
+ >
1879
+ ...
1880
+
1881
+ [browser] A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR-ed Client Component used:
1882
+
1883
+ - A server/client branch `if (typeof window !== 'undefined')`.
1884
+ - Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.
1885
+ - Date formatting in a user's locale which doesn't match the server.
1886
+ - External changing data without sending a snapshot of it along with the HTML.
1887
+ - Invalid HTML tag nesting.
1888
+
1889
+ It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
1890
+
1891
+ https://react.dev/link/hydration-mismatch
1892
+
1893
+ ...
1894
+ <HotReload globalError={[...]} webSocket={WebSocket} staticIndicatorState={{pathname:null, ...}}>
1895
+ <AppDevOverlayErrorBoundary globalError={[...]}>
1896
+ <ReplaySsrOnlyErrors>
1897
+ <DevRootHTTPAccessFallbackBoundary>
1898
+ <HTTPAccessFallbackBoundary notFound={<NotAllowedRootHTTPFallbackError>}>
1899
+ <HTTPAccessFallbackErrorBoundary pathname="/" notFound={<NotAllowedRootHTTPFallbackError>} ...>
1900
+ <RedirectBoundary>
1901
+ <RedirectErrorBoundary router={{...}}>
1902
+ <Head>
1903
+ <__next_root_layout_boundary__>
1904
+ <SegmentViewNode type="layout" pagePath="layout.tsx">
1905
+ <SegmentTrieNode>
1906
+ <link>
1907
+ <script>
1908
+ <script>
1909
+ <RootLayout>
1910
+ <html
1911
+ lang="en"
1912
+ - data-jetski-tab-id="11505259"
1913
+ >
1914
+ ...
1915
+
1916
+ Γ£ô Compiled in 25ms
1917
+ [browser] The final argument passed to useEffect changed size between renders. The order and size of this array must remain constant.
1918
+
1919
+ Previous: [Ollama (Local), Hugging Face (Cloud), hf.co/BeaverAI/Anubis-Mini-8B-v1h-GGUF:Q8_0, Qwen/Qwen2.5-72B-Instruct, auto, black-forest-labs/FLUX.1-dev, auto, ]
1920
+ Incoming: [Ollama (Local), Hugging Face (Cloud), hf.co/BeaverAI/Anubis-Mini-8B-v1h-GGUF:Q8_0, Qwen/Qwen2.5-72B-Instruct, auto, black-forest-labs/FLUX.1-dev, auto]
1921
+ at ClientApp (src/components/ClientApp.tsx:61:12)
1922
+ 59 |
1923
+ 60 | // Persist Settings to LocalStorage
1924
+ > 61 | useEffect(() => {
1925
+ | ^
1926
+ 62 | const settings = {
1927
+ 63 | refinementBackend,
1928
+ 64 | imageBackend, (src/components/ClientApp.tsx:61:12)
1929
+ [browser] The final argument passed to useEffect changed size between renders. The order and size of this array must remain constant.
1930
+
1931
+ Previous: [Ollama (Local), Hugging Face (Cloud), , Qwen/Qwen2.5-72B-Instruct, auto, black-forest-labs/FLUX.1-dev, auto, ]
1932
+ Incoming: [Ollama (Local), Hugging Face (Cloud), , Qwen/Qwen2.5-72B-Instruct, auto, black-forest-labs/FLUX.1-dev, auto]
1933
+ at ClientApp (src/components/ClientApp.tsx:61:12)
1934
+ at Set.forEach (<anonymous>)
1935
+ 59 |
1936
+ 60 | // Persist Settings to LocalStorage
1937
+ > 61 | useEffect(() => {
1938
+ | ^
1939
+ 62 | const settings = {
1940
+ 63 | refinementBackend,
1941
+ 64 | imageBackend, (src/components/ClientApp.tsx:61:12)
1942
+ [browser] The final argument passed to useEffect changed size between renders. The order and size of this array must remain constant.
1943
+
1944
+ Previous: [Gemini (Cloud), Hugging Face (Cloud), , Qwen/Qwen2.5-72B-Instruct, auto, black-forest-labs/FLUX.1-dev, auto, ]
1945
+ Incoming: [Gemini (Cloud), Hugging Face (Cloud), , Qwen/Qwen2.5-72B-Instruct, auto, black-forest-labs/FLUX.1-dev, auto]
1946
+ at ClientApp (src/components/ClientApp.tsx:61:12)
1947
+ at Set.forEach (<anonymous>)
1948
+ 59 |
1949
+ 60 | // Persist Settings to LocalStorage
1950
+ > 61 | useEffect(() => {
1951
+ | ^
1952
+ 62 | const settings = {
1953
+ 63 | refinementBackend,
1954
+ 64 | imageBackend, (src/components/ClientApp.tsx:61:12)
1955
+ GET / 200 in 142ms (next.js: 68ms, application-code: 73ms)
1956
+ [browser] A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR-ed Client Component used:
1957
+
1958
+ - A server/client branch `if (typeof window !== 'undefined')`.
1959
+ - Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.
1960
+ - Date formatting in a user's locale which doesn't match the server.
1961
+ - External changing data without sending a snapshot of it along with the HTML.
1962
+ - Invalid HTML tag nesting.
1963
+
1964
+ It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
1965
+
1966
+ https://react.dev/link/hydration-mismatch
1967
+
1968
+ ...
1969
+ <HotReload globalError={[...]} webSocket={WebSocket} staticIndicatorState={{pathname:null, ...}}>
1970
+ <AppDevOverlayErrorBoundary globalError={[...]}>
1971
+ <ReplaySsrOnlyErrors>
1972
+ <DevRootHTTPAccessFallbackBoundary>
1973
+ <HTTPAccessFallbackBoundary notFound={<NotAllowedRootHTTPFallbackError>}>
1974
+ <HTTPAccessFallbackErrorBoundary pathname="/" notFound={<NotAllowedRootHTTPFallbackError>} ...>
1975
+ <RedirectBoundary>
1976
+ <RedirectErrorBoundary router={{...}}>
1977
+ <Head>
1978
+ <__next_root_layout_boundary__>
1979
+ <SegmentViewNode type="layout" pagePath="layout.tsx">
1980
+ <SegmentTrieNode>
1981
+ <link>
1982
+ <script>
1983
+ <script>
1984
+ <RootLayout>
1985
+ <html
1986
+ lang="en"
1987
+ - data-jetski-tab-id="11505259"
1988
+ >
1989
+ ...
1990
+
1991
+ GET / 200 in 24ms (next.js: 3ms, application-code: 21ms)
1992
+ [browser] A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR-ed Client Component used:
1993
+
1994
+ - A server/client branch `if (typeof window !== 'undefined')`.
1995
+ - Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.
1996
+ - Date formatting in a user's locale which doesn't match the server.
1997
+ - External changing data without sending a snapshot of it along with the HTML.
1998
+ - Invalid HTML tag nesting.
1999
+
2000
+ It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
2001
+
2002
+ https://react.dev/link/hydration-mismatch
2003
+
2004
+ ...
2005
+ <HotReload globalError={[...]} webSocket={WebSocket} staticIndicatorState={{pathname:null, ...}}>
2006
+ <AppDevOverlayErrorBoundary globalError={[...]}>
2007
+ <ReplaySsrOnlyErrors>
2008
+ <DevRootHTTPAccessFallbackBoundary>
2009
+ <HTTPAccessFallbackBoundary notFound={<NotAllowedRootHTTPFallbackError>}>
2010
+ <HTTPAccessFallbackErrorBoundary pathname="/" notFound={<NotAllowedRootHTTPFallbackError>} ...>
2011
+ <RedirectBoundary>
2012
+ <RedirectErrorBoundary router={{...}}>
2013
+ <Head>
2014
+ <__next_root_layout_boundary__>
2015
+ <SegmentViewNode type="layout" pagePath="layout.tsx">
2016
+ <SegmentTrieNode>
2017
+ <link>
2018
+ <script>
2019
+ <script>
2020
+ <RootLayout>
2021
+ <html
2022
+ lang="en"
2023
+ - data-jetski-tab-id="11505259"
2024
+ >
2025
+ ...
2026
+
2027
+ GET / 200 in 20ms (next.js: 1850┬╡s, application-code: 18ms)
2028
+ [browser] A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR-ed Client Component used:
2029
+
2030
+ - A server/client branch `if (typeof window !== 'undefined')`.
2031
+ - Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.
2032
+ - Date formatting in a user's locale which doesn't match the server.
2033
+ - External changing data without sending a snapshot of it along with the HTML.
2034
+ - Invalid HTML tag nesting.
2035
+
2036
+ It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
2037
+
2038
+ https://react.dev/link/hydration-mismatch
2039
+
2040
+ ...
2041
+ <HotReload globalError={[...]} webSocket={WebSocket} staticIndicatorState={{pathname:null, ...}}>
2042
+ <AppDevOverlayErrorBoundary globalError={[...]}>
2043
+ <ReplaySsrOnlyErrors>
2044
+ <DevRootHTTPAccessFallbackBoundary>
2045
+ <HTTPAccessFallbackBoundary notFound={<NotAllowedRootHTTPFallbackError>}>
2046
+ <HTTPAccessFallbackErrorBoundary pathname="/" notFound={<NotAllowedRootHTTPFallbackError>} ...>
2047
+ <RedirectBoundary>
2048
+ <RedirectErrorBoundary router={{...}}>
2049
+ <Head>
2050
+ <__next_root_layout_boundary__>
2051
+ <SegmentViewNode type="layout" pagePath="layout.tsx">
2052
+ <SegmentTrieNode>
2053
+ <link>
2054
+ <script>
2055
+ <script>
2056
+ <RootLayout>
2057
+ <html
2058
+ lang="en"
2059
+ - data-jetski-tab-id="11505259"
2060
+ >
2061
+ ...
2062
+
2063
+ GET / 200 in 18ms (next.js: 2ms, application-code: 16ms)
2064
+ [browser] A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR-ed Client Component used:
2065
+
2066
+ - A server/client branch `if (typeof window !== 'undefined')`.
2067
+ - Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.
2068
+ - Date formatting in a user's locale which doesn't match the server.
2069
+ - External changing data without sending a snapshot of it along with the HTML.
2070
+ - Invalid HTML tag nesting.
2071
+
2072
+ It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
2073
+
2074
+ https://react.dev/link/hydration-mismatch
2075
+
2076
+ ...
2077
+ <HotReload globalError={[...]} webSocket={WebSocket} staticIndicatorState={{pathname:null, ...}}>
2078
+ <AppDevOverlayErrorBoundary globalError={[...]}>
2079
+ <ReplaySsrOnlyErrors>
2080
+ <DevRootHTTPAccessFallbackBoundary>
2081
+ <HTTPAccessFallbackBoundary notFound={<NotAllowedRootHTTPFallbackError>}>
2082
+ <HTTPAccessFallbackErrorBoundary pathname="/" notFound={<NotAllowedRootHTTPFallbackError>} ...>
2083
+ <RedirectBoundary>
2084
+ <RedirectErrorBoundary router={{...}}>
2085
+ <Head>
2086
+ <__next_root_layout_boundary__>
2087
+ <SegmentViewNode type="layout" pagePath="layout.tsx">
2088
+ <SegmentTrieNode>
2089
+ <link>
2090
+ <script>
2091
+ <script>
2092
+ <RootLayout>
2093
+ <html
2094
+ lang="en"
2095
+ - data-jetski-tab-id="11505259"
2096
+ >
2097
+ ...
2098
+
2099
+ GET / 200 in 28ms (next.js: 3ms, application-code: 26ms)
2100
+ [browser] A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR-ed Client Component used:
2101
+
2102
+ - A server/client branch `if (typeof window !== 'undefined')`.
2103
+ - Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.
2104
+ - Date formatting in a user's locale which doesn't match the server.
2105
+ - External changing data without sending a snapshot of it along with the HTML.
2106
+ - Invalid HTML tag nesting.
2107
+
2108
+ It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
2109
+
2110
+ https://react.dev/link/hydration-mismatch
2111
+
2112
+ ...
2113
+ <HotReload globalError={[...]} webSocket={WebSocket} staticIndicatorState={{pathname:null, ...}}>
2114
+ <AppDevOverlayErrorBoundary globalError={[...]}>
2115
+ <ReplaySsrOnlyErrors>
2116
+ <DevRootHTTPAccessFallbackBoundary>
2117
+ <HTTPAccessFallbackBoundary notFound={<NotAllowedRootHTTPFallbackError>}>
2118
+ <HTTPAccessFallbackErrorBoundary pathname="/" notFound={<NotAllowedRootHTTPFallbackError>} ...>
2119
+ <RedirectBoundary>
2120
+ <RedirectErrorBoundary router={{...}}>
2121
+ <Head>
2122
+ <__next_root_layout_boundary__>
2123
+ <SegmentViewNode type="layout" pagePath="layout.tsx">
2124
+ <SegmentTrieNode>
2125
+ <link>
2126
+ <script>
2127
+ <script>
2128
+ <RootLayout>
2129
+ <html
2130
+ lang="en"
2131
+ - data-jetski-tab-id="11505259"
2132
+ >
2133
+ ...
2134
+
2135
+ Γ£ô Compiled in 33ms
2136
+ Γ£ô Compiled in 38ms
2137
+ GET / 200 in 120ms (next.js: 63ms, application-code: 58ms)
2138
+ [browser] A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR-ed Client Component used:
2139
+
2140
+ - A server/client branch `if (typeof window !== 'undefined')`.
2141
+ - Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.
2142
+ - Date formatting in a user's locale which doesn't match the server.
2143
+ - External changing data without sending a snapshot of it along with the HTML.
2144
+ - Invalid HTML tag nesting.
2145
+
2146
+ It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
2147
+
2148
+ https://react.dev/link/hydration-mismatch
2149
+
2150
+ ...
2151
+ <HotReload globalError={[...]} webSocket={WebSocket} staticIndicatorState={{pathname:null, ...}}>
2152
+ <AppDevOverlayErrorBoundary globalError={[...]}>
2153
+ <ReplaySsrOnlyErrors>
2154
+ <DevRootHTTPAccessFallbackBoundary>
2155
+ <HTTPAccessFallbackBoundary notFound={<NotAllowedRootHTTPFallbackError>}>
2156
+ <HTTPAccessFallbackErrorBoundary pathname="/" notFound={<NotAllowedRootHTTPFallbackError>} ...>
2157
+ <RedirectBoundary>
2158
+ <RedirectErrorBoundary router={{...}}>
2159
+ <Head>
2160
+ <__next_root_layout_boundary__>
2161
+ <SegmentViewNode type="layout" pagePath="layout.tsx">
2162
+ <SegmentTrieNode>
2163
+ <link>
2164
+ <script>
2165
+ <script>
2166
+ <RootLayout>
2167
+ <html
2168
+ lang="en"
2169
+ - data-jetski-tab-id="11505263"
2170
+ >
2171
+ ...
2172
+
2173
+ GET / 200 in 25ms (next.js: 2ms, application-code: 23ms)
frontend/src/components/ClientApp.tsx CHANGED
@@ -1,7 +1,7 @@
1
  "use client";
2
 
3
  import React, { useState, useEffect, useRef } from 'react';
4
- import { User, Sparkles, Sword, Globe, Palette, Settings, Image as ImageIcon, Wand2, Dices, Save, Download, Upload, Copy } from 'lucide-react';
5
 
6
  const API_URL = process.env.NODE_ENV === "development" ? "http://127.0.0.1:8000" : "";
7
 
@@ -10,12 +10,14 @@ const tabs = [
10
  { id: 'appearance', label: 'Physical Traits', icon: Sparkles },
11
  { id: 'equipment', label: 'Gear & Weapons', icon: Sword },
12
  { id: 'environment', label: 'Atmosphere', icon: Globe },
13
- { id: 'style', label: 'Render Style', icon: Palette }
 
14
  ];
15
 
16
  export default function ClientApp() {
17
  const [config, setConfig] = useState<any>(null);
18
  const [activeTab, setActiveTab] = useState('identity');
 
19
 
20
  const [characterName, setCharacterName] = useState("Unnamed Hero");
21
  const [features, setFeatures] = useState<string[]>([]);
@@ -34,7 +36,43 @@ export default function ClientApp() {
34
  const [hfImageModel, setHfImageModel] = useState("black-forest-labs/FLUX.1-dev");
35
  const [hfImageProvider, setHfImageProvider] = useState("auto");
36
  const [manualToken, setManualToken] = useState("");
 
 
37
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  const fileInputRef = useRef<HTMLInputElement>(null);
39
 
40
  useEffect(() => {
@@ -207,7 +245,7 @@ export default function ClientApp() {
207
  const res = await fetch(`${API_URL}/api/refine_prompt`, {
208
  method: 'POST',
209
  headers: { 'Content-Type': 'application/json' },
210
- body: JSON.stringify({ prompt: promptOutput, backend: refinementBackend, ollama_model: ollamaModel, hf_text_model: hfTextModel, hf_text_provider: hfTextProvider, manual_token: manualToken, character_name: characterName })
211
  });
212
  if (res.ok) {
213
  const data = await res.json();
@@ -230,7 +268,7 @@ export default function ClientApp() {
230
  const res = await fetch(`${API_URL}/api/generate_image`, {
231
  method: 'POST',
232
  headers: { 'Content-Type': 'application/json' },
233
- body: JSON.stringify({ refined_prompt: refinedOutput, technical_prompt: promptOutput, aspect_ratio: ar, backend: imageBackend, hf_image_model: hfImageModel, hf_image_provider: hfImageProvider, manual_token: manualToken, character_name: characterName })
234
  });
235
 
236
  if (res.ok) {
@@ -361,84 +399,13 @@ export default function ClientApp() {
361
  <span className="text-sm tracking-wide font-medium">Reroll Marked Traits</span>
362
  </button>
363
  </nav>
364
-
365
- {/* Backend Quick Config at Bottom */}
366
- <div className="p-6 border-t border-[#2D241A] bg-[#080604]">
367
- <div className="flex items-center gap-2 mb-4 text-[#A89880]">
368
- <Settings size={16} />
369
- <span className="text-xs uppercase tracking-wider font-semibold">Active Engines</span>
370
- </div>
371
- <div className="mb-4">
372
- <label className="text-[10px] block uppercase tracking-widest text-[#A89880] mb-1.5 flex items-center gap-1"><Sparkles size={10}/> Text Refinement</label>
373
- <select value={refinementBackend} onChange={e => setRefinementBackend(e.target.value)} className="input-alchemist text-xs" title="Text Backbone">
374
- <option value="Gemini (Cloud)" disabled={!config?.gemini_active}>Gemini (Cloud){!config?.gemini_active ? ' (Missing Key)' : ''}</option>
375
- <option value="Hugging Face (Cloud)" disabled={!config?.hf_active}>Hugging Face (Cloud){!config?.hf_active ? ' (Missing Token)' : ''}</option>
376
- <option value="Ollama (Local)" disabled={!config?.ollama_models?.length}>Ollama (Local){!config?.ollama_models?.length ? ' (Offline)' : ''}</option>
377
- </select>
378
- </div>
379
- <div className="mb-4">
380
- <label className="text-[10px] block uppercase tracking-widest text-[#A89880] mb-1.5 flex items-center gap-1"><ImageIcon size={10}/> Image Synthesis</label>
381
- <select value={imageBackend} onChange={e => setImageBackend(e.target.value)} className="input-alchemist text-xs" title="Image Engine">
382
- <option value="Gemini (Cloud)" disabled={!config?.gemini_active}>Gemini (Cloud){!config?.gemini_active ? ' (Missing Key)' : ''}</option>
383
- <option value="Hugging Face (Cloud)" disabled={!config?.hf_active}>Hugging Face (Cloud){!config?.hf_active ? ' (Missing Token)' : ''}</option>
384
- <option value="ComfyUI (Local)" disabled={!config?.comfy_active}>ComfyUI (Local){!config?.comfy_active ? ' (Offline)' : ''}</option>
385
- </select>
386
- </div>
387
-
388
- <details className="group [&_summary::-webkit-details-marker]:hidden">
389
- <summary className="flex items-center justify-between cursor-pointer py-2 text-[#A89880] hover:text-[#DAB062] transition-colors border-t border-[#2D241A] mt-2">
390
- <span className="text-[10px] uppercase tracking-widest font-semibold">Advanced Constraints</span>
391
- <span className="transition group-open:rotate-180">▼</span>
392
- </summary>
393
- <div className="pt-2 text-xs space-y-3">
394
- {refinementBackend === "Ollama (Local)" && (
395
- <div>
396
- <label className="block text-[9px] uppercase tracking-widest text-[#665D4F] mb-1">Ollama Model</label>
397
- <select value={ollamaModel} onChange={e => setOllamaModel(e.target.value)} className="input-alchemist w-full text-[10px] py-1.5 px-2 bg-[#120E0A]">
398
- <option value="">Default (llama3)</option>
399
- {config?.ollama_models?.map((m: string) => <option key={m} value={m}>{m}</option>)}
400
- </select>
401
- </div>
402
- )}
403
- {refinementBackend === "Hugging Face (Cloud)" && (
404
- <>
405
- <div>
406
- <label className="block text-[9px] uppercase tracking-widest text-[#665D4F] mb-1">HF Text Model</label>
407
- <input type="text" value={hfTextModel} onChange={e => setHfTextModel(e.target.value)} className="input-alchemist w-full text-[10px] py-1.5 px-2 bg-[#120E0A]" placeholder="e.g. meta-llama/Meta-Llama-3-8B-Instruct" />
408
- </div>
409
- </>
410
- )}
411
- {imageBackend === "Hugging Face (Cloud)" && (
412
- <>
413
- <div>
414
- <label className="block text-[9px] uppercase tracking-widest text-[#665D4F] mb-1">HF Image Model</label>
415
- <input type="text" value={hfImageModel} onChange={e => setHfImageModel(e.target.value)} className="input-alchemist w-full text-[10px] py-1.5 px-2 bg-[#120E0A]" placeholder="e.g. black-forest-labs/FLUX.1-schnell" />
416
- </div>
417
- <div>
418
- <label className="block text-[9px] uppercase tracking-widest text-[#665D4F] mb-1">Inference Provider</label>
419
- <select value={hfImageProvider} onChange={e => setHfImageProvider(e.target.value)} className="input-alchemist w-full text-[10px] py-1.5 px-2 bg-[#120E0A]">
420
- <option value="auto">Auto-Managed (Serverless)</option>
421
- <option value="fal-ai">Fal-AI (Partner)</option>
422
- <option value="replicate">Replicate (Partner)</option>
423
- <option value="hf-inference">HF Inference Endpoints</option>
424
- </select>
425
- </div>
426
- </>
427
- )}
428
- <div>
429
- <label className="block text-[9px] uppercase tracking-widest text-[#665D4F] mb-1">Manual API Token (Optional Override)</label>
430
- <input type="password" value={manualToken} onChange={e => setManualToken(e.target.value)} className="input-alchemist w-full text-[10px] py-1.5 px-2 bg-[#120E0A] font-mono placeholder:font-sans" placeholder="hf_..., fal_..." />
431
- </div>
432
- </div>
433
- </details>
434
- </div>
435
  </div>
436
 
437
- {/* 2. Main Middle Area (Form Aspects) */}
438
  <div className="flex-1 flex flex-col relative z-10 overflow-y-auto shadow-inner custom-scrollbar bg-[#0f0c08]">
439
  <div className="sticky top-0 h-12 bg-gradient-to-b from-[#080604] to-transparent z-10 pointer-events-none w-full"></div>
440
 
441
- <div className="max-w-2xl mx-auto w-full px-4 pb-24 pt-2">
442
  {/* App Logo */}
443
  <div className="w-full h-32 mb-6 relative border border-[#2D241A] rounded-xl bg-gradient-to-b from-[#0a0805] to-transparent shadow-inner overflow-hidden flex items-center justify-center">
444
  <img src="/logo.svg" alt="Chronicle Portrait Studio Logo" className="w-full h-full object-cover drop-shadow-[0_0_15px_rgba(218,176,98,0.3)]" />
@@ -454,6 +421,132 @@ export default function ClientApp() {
454
  <div className="absolute top-0 right-0 w-96 h-96 bg-[#DAB062]/5 rounded-full blur-3xl -mr-32 -mt-32 pointer-events-none transition-all duration-700 group-hover:bg-[#DAB062]/10"></div>
455
 
456
  <div className="relative z-10 w-full">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
457
  {activeTab === 'identity' && (
458
  <div className="w-full">
459
  <div className="mb-6 p-5 bg-[#0a0805] border border-[#2D241A] rounded-xl shadow-inner relative group">
@@ -558,22 +651,37 @@ export default function ClientApp() {
558
  <div className="h-[45%] p-6 border-b border-[#2D241A] relative flex items-center justify-center overflow-hidden">
559
  <div className="absolute inset-0 bg-[url('https://www.transparenttextures.com/patterns/dark-matter.png')] opacity-10 pointer-events-none"></div>
560
 
561
- {imageSrc ? (
562
- <div className="relative w-full h-full flex items-center justify-center rounded-lg overflow-hidden group">
563
- <div className="absolute inset-0 border border-[#DAB062] opacity-30 pointer-events-none z-10 rounded-lg"></div>
564
- <img src={imageSrc} alt="Portrait" className="max-w-full max-h-full object-contain drop-shadow-[0_0_20px_rgba(218,176,98,0.2)] transition-transform duration-700 ease-in-out group-hover:scale-[1.02]" />
565
-
566
- {/* Context menu mock overlay */}
567
- <div className="absolute top-3 right-3 flex gap-2 opacity-0 group-hover:opacity-100 transition-opacity">
568
- <button onClick={handleDownloadImage} title="Download Portrait" className="bg-black/60 backdrop-blur-md text-[#E2D1B3] p-2 rounded-md hover:text-[#DAB062] hover:bg-black/80 border border-[#2D241A] transition-all"><Download size={18}/></button>
569
- </div>
570
- </div>
571
- ) : (
572
- <div className="flex flex-col items-center justify-center text-center opacity-40">
573
- <ImageIcon size={56} className="text-[#A89880] mb-4 stroke-1" />
574
- <p className="font-cinzel text-[#A89880] tracking-widest text-sm">Visual Synthesis Pending</p>
575
- </div>
576
- )}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
577
  </div>
578
 
579
  {/* Action Panel */}
@@ -611,7 +719,14 @@ export default function ClientApp() {
611
  <textarea readOnly value={promptOutput} className="h-40 bg-[#080604] border border-[#1A2E38] rounded-xl p-4 text-xs text-[#E2D1B3] resize-none custom-scrollbar shadow-inner outline-none leading-relaxed"></textarea>
612
  </div>
613
 
614
- <div className="text-center text-[#DAB062] font-cinzel text-xs tracking-[0.2em] my-5 min-h-[20px]">{statusMsg}</div>
 
 
 
 
 
 
 
615
 
616
  <button
617
  onClick={handleGenerateImage}
@@ -625,6 +740,32 @@ export default function ClientApp() {
625
 
626
  </div>
627
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
628
  </div>
629
  );
630
  }
 
1
  "use client";
2
 
3
  import React, { useState, useEffect, useRef } from 'react';
4
+ import { User, Sparkles, Sword, Globe, Palette, Settings, Image as ImageIcon, Wand2, Dices, Save, Download, Upload, Copy, X } from 'lucide-react';
5
 
6
  const API_URL = process.env.NODE_ENV === "development" ? "http://127.0.0.1:8000" : "";
7
 
 
10
  { id: 'appearance', label: 'Physical Traits', icon: Sparkles },
11
  { id: 'equipment', label: 'Gear & Weapons', icon: Sword },
12
  { id: 'environment', label: 'Atmosphere', icon: Globe },
13
+ { id: 'style', label: 'Render Style', icon: Palette },
14
+ { id: 'engines', label: 'Configuration', icon: Settings }
15
  ];
16
 
17
  export default function ClientApp() {
18
  const [config, setConfig] = useState<any>(null);
19
  const [activeTab, setActiveTab] = useState('identity');
20
+ const [showLightbox, setShowLightbox] = useState(false);
21
 
22
  const [characterName, setCharacterName] = useState("Unnamed Hero");
23
  const [features, setFeatures] = useState<string[]>([]);
 
36
  const [hfImageModel, setHfImageModel] = useState("black-forest-labs/FLUX.1-dev");
37
  const [hfImageProvider, setHfImageProvider] = useState("auto");
38
  const [manualToken, setManualToken] = useState("");
39
+ const [manualTextEntry, setManualTextEntry] = useState(false);
40
+ const [manualImageEntry, setManualImageEntry] = useState(false);
41
 
42
+ // Restore Settings from LocalStorage
43
+ useEffect(() => {
44
+ const saved = localStorage.getItem('rpg_portrait_settings');
45
+ if (saved) {
46
+ try {
47
+ const data = JSON.parse(saved);
48
+ if (data.refinementBackend) setRefinementBackend(data.refinementBackend);
49
+ if (data.imageBackend) setImageBackend(data.imageBackend);
50
+ if (data.ollamaModel) setOllamaModel(data.ollamaModel);
51
+ if (data.hfTextModel) setHfTextModel(data.hfTextModel);
52
+ if (data.hfTextProvider) setHfTextProvider(data.hfTextProvider);
53
+ if (data.hfImageModel) setHfImageModel(data.hfImageModel);
54
+ if (data.hfImageProvider) setHfImageProvider(data.hfImageProvider);
55
+ if (data.manualToken) setManualToken(data.manualToken);
56
+ } catch (e) {
57
+ console.error("Failed to restore settings", e);
58
+ }
59
+ }
60
+ }, []);
61
+
62
+ // Persist Settings to LocalStorage
63
+ useEffect(() => {
64
+ const settings = {
65
+ refinementBackend,
66
+ imageBackend,
67
+ ollamaModel,
68
+ hfTextModel,
69
+ hfTextProvider,
70
+ hfImageModel,
71
+ hfImageProvider
72
+ };
73
+ localStorage.setItem('rpg_portrait_settings', JSON.stringify(settings));
74
+ }, [refinementBackend, imageBackend, ollamaModel, hfTextModel, hfTextProvider, hfImageModel, hfImageProvider]);
75
+
76
  const fileInputRef = useRef<HTMLInputElement>(null);
77
 
78
  useEffect(() => {
 
245
  const res = await fetch(`${API_URL}/api/refine_prompt`, {
246
  method: 'POST',
247
  headers: { 'Content-Type': 'application/json' },
248
+ body: JSON.stringify({ prompt: promptOutput, backend: refinementBackend, ollama_model: ollamaModel, hf_text_model: hfTextModel, hf_text_provider: hfTextProvider, manual_token: "", character_name: characterName })
249
  });
250
  if (res.ok) {
251
  const data = await res.json();
 
268
  const res = await fetch(`${API_URL}/api/generate_image`, {
269
  method: 'POST',
270
  headers: { 'Content-Type': 'application/json' },
271
+ body: JSON.stringify({ refined_prompt: refinedOutput, technical_prompt: promptOutput, aspect_ratio: ar, backend: imageBackend, hf_image_model: hfImageModel, hf_image_provider: hfImageProvider, manual_token: "", character_name: characterName })
272
  });
273
 
274
  if (res.ok) {
 
399
  <span className="text-sm tracking-wide font-medium">Reroll Marked Traits</span>
400
  </button>
401
  </nav>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
402
  </div>
403
 
404
+ {/* 2. Main Middle Area (Form Aspects) */}
405
  <div className="flex-1 flex flex-col relative z-10 overflow-y-auto shadow-inner custom-scrollbar bg-[#0f0c08]">
406
  <div className="sticky top-0 h-12 bg-gradient-to-b from-[#080604] to-transparent z-10 pointer-events-none w-full"></div>
407
 
408
+ <div className="max-w-4xl mx-auto w-full px-6 pb-24 pt-2">
409
  {/* App Logo */}
410
  <div className="w-full h-32 mb-6 relative border border-[#2D241A] rounded-xl bg-gradient-to-b from-[#0a0805] to-transparent shadow-inner overflow-hidden flex items-center justify-center">
411
  <img src="/logo.svg" alt="Chronicle Portrait Studio Logo" className="w-full h-full object-cover drop-shadow-[0_0_15px_rgba(218,176,98,0.3)]" />
 
421
  <div className="absolute top-0 right-0 w-96 h-96 bg-[#DAB062]/5 rounded-full blur-3xl -mr-32 -mt-32 pointer-events-none transition-all duration-700 group-hover:bg-[#DAB062]/10"></div>
422
 
423
  <div className="relative z-10 w-full">
424
+ {activeTab === 'engines' && (
425
+ <div className="w-full space-y-8 animate-in fade-in slide-in-from-bottom-4 duration-500">
426
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
427
+ <div className="bg-[#0a0805]/80 border border-[#2D241A] rounded-xl p-6 shadow-2xl backdrop-blur-sm">
428
+ <div className="flex items-center gap-3 mb-6">
429
+ <div className="p-2 bg-[#DAB062]/10 rounded-lg">
430
+ <Sparkles className="text-[#DAB062]" size={20} />
431
+ </div>
432
+ <h3 className="font-cinzel text-xl text-[#E2D1B3]">Text Intelligence</h3>
433
+ </div>
434
+ <div className="space-y-5">
435
+ <div>
436
+ <label className="text-[10px] block uppercase tracking-widest text-[#A89880] mb-2">Backbone Engine</label>
437
+ <select value={refinementBackend} onChange={e => setRefinementBackend(e.target.value)} className="input-alchemist w-full font-cinzel">
438
+ <option value="Gemini (Cloud)" disabled={!config?.gemini_active}>Gemini (Cloud){!config?.gemini_active ? ' (Missing Key)' : ''}</option>
439
+ <option value="Hugging Face (Cloud)" disabled={!config?.hf_active}>Hugging Face (Cloud){!config?.hf_active ? ' (Missing Token)' : ''}</option>
440
+ <option value="Ollama (Local)" disabled={!config?.ollama_models?.length}>Ollama (Local){!config?.ollama_models?.length ? ' (Offline)' : ''}</option>
441
+ </select>
442
+ </div>
443
+ {refinementBackend === "Ollama (Local)" && (
444
+ <div className="animate-in fade-in slide-in-from-top-2">
445
+ <label className="text-[10px] block uppercase tracking-widest text-[#A89880] mb-2">Local Model Identifier</label>
446
+ <select value={ollamaModel} onChange={e => setOllamaModel(e.target.value)} className="input-alchemist w-full">
447
+ <option value="">Default (llama3)</option>
448
+ {config?.ollama_models?.map((m: string) => <option key={m} value={m}>{m}</option>)}
449
+ </select>
450
+ </div>
451
+ )}
452
+ {refinementBackend === "Hugging Face (Cloud)" && (
453
+ <div className="animate-in fade-in slide-in-from-top-2">
454
+ <div className="flex items-center justify-between mb-2">
455
+ <label className="text-[10px] block uppercase tracking-widest text-[#A89880]">Refinement Model</label>
456
+ <button onClick={() => setManualTextEntry(!manualTextEntry)} className="text-[10px] uppercase text-[#DAB062] hover:underline transition-all">
457
+ {manualTextEntry ? "Standard List" : "Manual Entry"}
458
+ </button>
459
+ </div>
460
+ {manualTextEntry ? (
461
+ <input
462
+ type="text"
463
+ value={hfTextModel}
464
+ onChange={e => setHfTextModel(e.target.value)}
465
+ className="input-alchemist w-full"
466
+ placeholder="Enter model ID..."
467
+ />
468
+ ) : (
469
+ <select
470
+ value={hfTextModel}
471
+ onChange={e => setHfTextModel(e.target.value)}
472
+ className="input-alchemist w-full"
473
+ >
474
+ {config?.hf_text_models?.map((m: string) => (
475
+ <option key={m} value={m}>{m}</option>
476
+ ))}
477
+ {config?.hf_text_models && !config.hf_text_models.includes(hfTextModel) && (
478
+ <option value={hfTextModel}>{hfTextModel}</option>
479
+ )}
480
+ </select>
481
+ )}
482
+ </div>
483
+ )}
484
+ </div>
485
+ </div>
486
+ <div className="bg-[#0a0805]/80 border border-[#2D241A] rounded-xl p-6 shadow-2xl backdrop-blur-sm">
487
+ <div className="flex items-center gap-3 mb-6">
488
+ <div className="p-2 bg-[#DAB062]/10 rounded-lg">
489
+ <ImageIcon className="text-[#DAB062]" size={20} />
490
+ </div>
491
+ <h3 className="font-cinzel text-xl text-[#E2D1B3]">Visual Synthesis</h3>
492
+ </div>
493
+ <div className="space-y-5">
494
+ <div>
495
+ <label className="text-[10px] block uppercase tracking-widest text-[#A89880] mb-2">Generation Core</label>
496
+ <select value={imageBackend} onChange={e => setImageBackend(e.target.value)} className="input-alchemist w-full font-cinzel">
497
+ <option value="Gemini (Cloud)" disabled={!config?.gemini_active}>Gemini (Cloud){!config?.gemini_active ? ' (Missing Key)' : ''}</option>
498
+ <option value="Hugging Face (Cloud)" disabled={!config?.hf_active}>Hugging Face (Cloud){!config?.hf_active ? ' (Missing Token)' : ''}</option>
499
+ <option value="ComfyUI (Local)" disabled={!config?.comfy_active}>ComfyUI (Local){!config?.comfy_active ? ' (Offline)' : ''}</option>
500
+ </select>
501
+ </div>
502
+ {imageBackend === "Hugging Face (Cloud)" && (
503
+ <div className="space-y-4 animate-in fade-in slide-in-from-top-2">
504
+ <div>
505
+ <div className="flex items-center justify-between mb-2">
506
+ <label className="text-[10px] block uppercase tracking-widest text-[#A89880]">Diffusion Model</label>
507
+ <button onClick={() => setManualImageEntry(!manualImageEntry)} className="text-[10px] uppercase text-[#DAB062] hover:underline transition-all">
508
+ {manualImageEntry ? "Standard List" : "Manual Entry"}
509
+ </button>
510
+ </div>
511
+ {manualImageEntry ? (
512
+ <input
513
+ type="text"
514
+ value={hfImageModel}
515
+ onChange={e => setHfImageModel(e.target.value)}
516
+ className="input-alchemist w-full"
517
+ placeholder="Enter model ID..."
518
+ />
519
+ ) : (
520
+ <select
521
+ value={hfImageModel}
522
+ onChange={e => setHfImageModel(e.target.value)}
523
+ className="input-alchemist w-full"
524
+ >
525
+ {config?.hf_image_models?.map((m: string) => (
526
+ <option key={m} value={m}>{m}</option>
527
+ ))}
528
+ {config?.hf_image_models && !config.hf_image_models.includes(hfImageModel) && (
529
+ <option value={hfImageModel}>{hfImageModel}</option>
530
+ )}
531
+ </select>
532
+ )}
533
+ </div>
534
+ <div>
535
+ <label className="text-[10px] block uppercase tracking-widest text-[#A89880] mb-2">Inference Gateway</label>
536
+ <select value={hfImageProvider} onChange={e => setHfImageProvider(e.target.value)} className="input-alchemist w-full">
537
+ <option value="auto">Auto-Managed</option>
538
+ <option value="fal-ai">Fal-AI (Fast)</option>
539
+ <option value="replicate">Replicate</option>
540
+ <option value="hf-inference">Direct HF API</option>
541
+ </select>
542
+ </div>
543
+ </div>
544
+ )}
545
+ </div>
546
+ </div>
547
+ </div>
548
+ </div>
549
+ )}
550
  {activeTab === 'identity' && (
551
  <div className="w-full">
552
  <div className="mb-6 p-5 bg-[#0a0805] border border-[#2D241A] rounded-xl shadow-inner relative group">
 
651
  <div className="h-[45%] p-6 border-b border-[#2D241A] relative flex items-center justify-center overflow-hidden">
652
  <div className="absolute inset-0 bg-[url('https://www.transparenttextures.com/patterns/dark-matter.png')] opacity-10 pointer-events-none"></div>
653
 
654
+ {imageSrc ? (
655
+ <div className="relative w-full h-full flex items-center justify-center rounded-lg overflow-hidden group cursor-zoom-in" onClick={() => setShowLightbox(true)}>
656
+ <div className="absolute inset-0 border border-[#DAB062] opacity-30 pointer-events-none z-10 rounded-lg group-hover:opacity-60 transition-opacity"></div>
657
+ <img src={imageSrc || ""} alt="Portrait" className="max-w-full max-h-full object-contain drop-shadow-[0_0_20px_rgba(218,176,98,0.2)] transition-transform duration-700 ease-in-out group-hover:scale-[1.02]" />
658
+
659
+ <div className="absolute inset-0 bg-black/0 group-hover:bg-black/30 transition-colors pointer-events-none flex items-center justify-center">
660
+ <div className="opacity-0 group-hover:opacity-100 transition-opacity bg-[#0a0805]/80 backdrop-blur-md border border-[#DAB062]/40 p-3 rounded-full text-[#DAB062] shadow-xl">
661
+ <ImageIcon size={24} />
662
+ </div>
663
+ </div>
664
+
665
+ <div className="absolute bottom-3 right-3 flex items-center gap-2">
666
+ <button onClick={(e) => { e.stopPropagation(); handleDownloadImage(); }} title="Download Portrait" className="opacity-0 group-hover:opacity-100 bg-black/60 backdrop-blur-md text-[#E2D1B3] p-2 rounded-md hover:text-[#DAB062] hover:bg-black/80 border border-[#2D241A] transition-all"><Download size={18}/></button>
667
+ </div>
668
+ </div>
669
+ ) : statusMsg && (statusMsg.includes("Error") || statusMsg.includes("Failed")) ? (
670
+ <div className="flex flex-col items-center justify-center text-center px-8 animate-in fade-in zoom-in-95 duration-500">
671
+ <div className="p-4 bg-red-950/20 border border-red-500/30 rounded-full mb-6 relative">
672
+ <X size={48} className="text-red-500/60" />
673
+ <div className="absolute inset-0 bg-red-500/10 blur-xl rounded-full"></div>
674
+ </div>
675
+ <h4 className="font-cinzel text-red-400 tracking-[0.3em] text-sm mb-3 font-bold uppercase drop-shadow-sm">Synthesis Chamber Fault</h4>
676
+ <p className="text-red-300/60 text-xs italic font-medium leading-relaxed max-w-[280px]">"{statusMsg}"</p>
677
+ <button onClick={() => setStatusMsg("")} className="mt-6 px-4 py-1.5 border border-red-900/50 rounded-full text-[10px] uppercase tracking-widest text-red-400/50 hover:bg-red-900/10 hover:text-red-400 transition-all">Clear Error</button>
678
+ </div>
679
+ ) : (
680
+ <div className="flex flex-col items-center justify-center text-center opacity-40">
681
+ <ImageIcon size={56} className="text-[#A89880] mb-4 stroke-1 line-through opacity-20" />
682
+ <p className="font-cinzel text-[#A89880] tracking-widest text-sm italic">Visual Synthesis Pending</p>
683
+ </div>
684
+ )}
685
  </div>
686
 
687
  {/* Action Panel */}
 
719
  <textarea readOnly value={promptOutput} className="h-40 bg-[#080604] border border-[#1A2E38] rounded-xl p-4 text-xs text-[#E2D1B3] resize-none custom-scrollbar shadow-inner outline-none leading-relaxed"></textarea>
720
  </div>
721
 
722
+ <div className={`text-center font-cinzel text-[10px] tracking-[0.2em] my-4 min-h-[20px] transition-all duration-300 ${statusMsg.toLowerCase().includes('error') || statusMsg.toLowerCase().includes('failed') ? 'text-red-400 font-bold animate-pulse' : 'text-[#DAB062] font-medium'}`}>
723
+ {statusMsg && (
724
+ <span className="flex items-center justify-center gap-2">
725
+ {statusMsg.toLowerCase().includes('error') || statusMsg.toLowerCase().includes('failed') ? <X size={12}/> : <Sparkles size={12}/>}
726
+ {statusMsg}
727
+ </span>
728
+ )}
729
+ </div>
730
 
731
  <button
732
  onClick={handleGenerateImage}
 
740
 
741
  </div>
742
  </div>
743
+ {/* FULL SCREEN LIGHTBOX MODAL */}
744
+ {showLightbox && imageSrc && (
745
+ <div className="fixed inset-0 z-[100] bg-[#080604]/95 backdrop-blur-2xl flex items-center justify-center p-4 md:p-12 animate-in fade-in duration-300" onClick={() => setShowLightbox(false)}>
746
+ <div className="absolute top-8 right-8 z-[110]">
747
+ <button onClick={() => setShowLightbox(false)} className="text-[#A89880] hover:text-[#DAB062] transition-colors bg-black/40 p-3 rounded-full border border-[#2D241A] shadow-xl">
748
+ <X size={24} />
749
+ <span className="sr-only">Close</span>
750
+ </button>
751
+ </div>
752
+
753
+ <div className="relative max-w-full max-h-full flex items-center justify-center animate-in zoom-in-95 duration-500" onClick={e => e.stopPropagation()}>
754
+ <div className="absolute inset-0 border border-[#DAB062]/20 rounded-xl pointer-events-none blur-sm"></div>
755
+ <img
756
+ src={imageSrc || ""}
757
+ alt="Portrait High Resolution"
758
+ className="max-w-full max-h-full rounded-xl shadow-[0_0_100px_rgba(218,176,98,0.15)] object-contain border border-[#2D241A]"
759
+ />
760
+
761
+ <div className="absolute bottom-[-60px] flex gap-4">
762
+ <button onClick={handleDownloadImage} className="flex items-center gap-3 px-6 py-2.5 bg-[#DAB062] text-[#0a0805] rounded-full font-cinzel font-bold text-sm tracking-widest hover:bg-[#F2DAA4] transition-colors shadow-lg shadow-yellow-900/20">
763
+ <Download size={18} /> Preserve Masterpiece
764
+ </button>
765
+ </div>
766
+ </div>
767
+ </div>
768
+ )}
769
  </div>
770
  );
771
  }
modules/config.py CHANGED
@@ -2,7 +2,7 @@ import os
2
  from dotenv import load_dotenv
3
 
4
  # Load environment variables
5
- load_dotenv()
6
 
7
  # ComfyUI Settings
8
  COMFY_HOST = os.getenv("COMFY_HOST", "127.0.0.1")
@@ -28,6 +28,7 @@ HF_TEXT_MODELS = [
28
 
29
  HF_IMAGE_MODELS = [
30
  "black-forest-labs/FLUX.1-dev",
 
31
  "Tongyi-MAI/Z-Image-Turbo",
32
  "Qwen/Qwen-Image-2512"
33
  ]
 
2
  from dotenv import load_dotenv
3
 
4
  # Load environment variables
5
+ load_dotenv(override=True)
6
 
7
  # ComfyUI Settings
8
  COMFY_HOST = os.getenv("COMFY_HOST", "127.0.0.1")
 
28
 
29
  HF_IMAGE_MODELS = [
30
  "black-forest-labs/FLUX.1-dev",
31
+ "stabilityai/stable-diffusion-xl-base-1.0",
32
  "Tongyi-MAI/Z-Image-Turbo",
33
  "Qwen/Qwen-Image-2512"
34
  ]
modules/integrations.py CHANGED
@@ -30,18 +30,24 @@ if GEMINI_API_KEY:
30
  client = genai.Client(api_key=GEMINI_API_KEY)
31
  gemini_active = True
32
  except Exception as e:
33
- print(f"Error initializing Gemini: {e}")
 
 
34
 
35
  # Setup Hugging Face Router
36
  hf_client = None
 
37
  if HF_TOKEN:
38
  try:
39
  hf_client = OpenAI(
40
  base_url=HF_BASE_URL,
41
  api_key=HF_TOKEN,
42
  )
 
43
  except Exception as e:
44
- print(f"Error initializing HF Client: {e}")
 
 
45
 
46
  def load_system_prompt(key="refinement"):
47
  """Loads a system prompt from prompts.yaml."""
@@ -328,9 +334,14 @@ def generate_image_with_hf(prompt, aspect_ratio, model_id=None, provider=None, t
328
 
329
  try:
330
  client = InferenceClient(api_key=active_token, provider=active_provider)
331
- img = client.text_to_image(prompt, model=active_model, width=width, height=height)
332
-
333
- # Embed metadata
 
 
 
 
 
334
  metadata = PngInfo()
335
  metadata.add_text("Comment", prompt)
336
  metadata.add_text("CharacterName", character_name)
 
30
  client = genai.Client(api_key=GEMINI_API_KEY)
31
  gemini_active = True
32
  except Exception as e:
33
+ gemini_active = False
34
+ else:
35
+ gemini_active = False
36
 
37
  # Setup Hugging Face Router
38
  hf_client = None
39
+ hf_active = False
40
  if HF_TOKEN:
41
  try:
42
  hf_client = OpenAI(
43
  base_url=HF_BASE_URL,
44
  api_key=HF_TOKEN,
45
  )
46
+ hf_active = True
47
  except Exception as e:
48
+ hf_active = False
49
+ else:
50
+ hf_active = False
51
 
52
  def load_system_prompt(key="refinement"):
53
  """Loads a system prompt from prompts.yaml."""
 
334
 
335
  try:
336
  client = InferenceClient(api_key=active_token, provider=active_provider)
337
+ # Use InferenceClient's built-in text_to_image which is more robust
338
+ # width/height are supported by some providers (like fal-ai, replicate)
339
+ img = client.text_to_image(
340
+ prompt,
341
+ model=active_model,
342
+ width=width,
343
+ height=height
344
+ )
345
  metadata = PngInfo()
346
  metadata.add_text("Comment", prompt)
347
  metadata.add_text("CharacterName", character_name)