digiPal / ui /interfaces.py
BladeSzaSza's picture
Revert "Cleanup: Remove unused files, Svelte frontend, old UI, and update docs for Streamlit-only architecture"
8fa76f7
import gradio as gr
from typing import Callable, Any, Optional
import numpy as np
def create_voice_interface(pipeline: Any, game_mechanics: Any) -> gr.Column:
"""Create voice-controlled interface for monster generation"""
with gr.Column() as voice_interface:
gr.Markdown("""
### πŸŽ™οΈ Voice Control Interface
Speak your monster description or use the microphone to create your digital companion!
""")
with gr.Row():
with gr.Column(scale=1):
# Voice input
voice_input = gr.Audio(
label="🎀 Voice Description",
sources=["microphone", "upload"],
type="filepath",
elem_classes=["cyber-input"],
info="Describe your monster using voice"
)
# Voice control buttons
with gr.Row():
start_recording = gr.Button(
"πŸ”΄ Start Recording",
elem_classes=["cyber-button"],
size="sm"
)
stop_recording = gr.Button(
"⏹️ Stop Recording",
elem_classes=["cyber-button"],
size="sm"
)
# Real-time transcription display
transcription_display = gr.Textbox(
label="πŸ“ Transcription",
placeholder="Your voice will be transcribed here...",
interactive=False,
lines=3,
elem_classes=["cyber-output"]
)
# Voice commands
gr.Markdown("""
**Voice Commands:**
- "Create a [type] monster" - Generate specific type
- "Make it [color/trait]" - Add characteristics
- "Give it [ability]" - Add special abilities
""")
with gr.Column(scale=1):
# Preview and generation status
generation_status = gr.Markdown(
value="🟒 Ready for voice input",
elem_classes=["cyber-message"]
)
# Audio visualization
audio_viz = gr.HTML(
value="""
<div class="audio-visualizer">
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>
</div>
""",
elem_classes=["cyber-container"]
)
# Quick voice templates
gr.Markdown("**Quick Templates:**")
template_buttons = []
templates = [
("πŸ”₯ Fire Type", "Create a fierce fire-breathing dragon monster"),
("πŸ’§ Water Type", "Create a graceful aquatic monster"),
("⚑ Electric Type", "Create a sparking electric monster"),
("🌿 Nature Type", "Create a peaceful nature guardian monster")
]
for label, prompt in templates:
btn = gr.Button(label, size="sm", elem_classes=["cyber-button"])
template_buttons.append((btn, prompt))
# Voice interface specific styling
gr.HTML("""
<style>
.audio-visualizer {
display: flex;
justify-content: center;
align-items: center;
height: 100px;
gap: 5px;
}
.audio-visualizer .bar {
width: 10px;
height: 30px;
background: linear-gradient(to top, #00ff41, #8A2BE2);
animation: audio-wave 1s ease-in-out infinite;
border-radius: 5px;
}
.audio-visualizer .bar:nth-child(1) { animation-delay: 0s; }
.audio-visualizer .bar:nth-child(2) { animation-delay: 0.1s; }
.audio-visualizer .bar:nth-child(3) { animation-delay: 0.2s; }
.audio-visualizer .bar:nth-child(4) { animation-delay: 0.3s; }
.audio-visualizer .bar:nth-child(5) { animation-delay: 0.4s; }
@keyframes audio-wave {
0%, 100% { height: 30px; }
50% { height: 60px; }
}
</style>
""")
return voice_interface
def create_visual_interface(pipeline: Any, game_mechanics: Any) -> gr.Column:
"""Create visual/camera-based interface for monster generation"""
with gr.Column() as visual_interface:
gr.Markdown("""
### πŸ‘οΈ Visual Control Interface
Use images, drawings, or camera input to inspire your monster creation!
""")
with gr.Row():
with gr.Column(scale=1):
# Image input options
with gr.Tabs():
with gr.TabItem("πŸ“· Camera"):
camera_input = gr.Image(
label="Camera Capture",
sources=["webcam"],
type="pil",
elem_classes=["cyber-input", "camera-feed"]
)
with gr.TabItem("πŸ–ΌοΈ Upload"):
image_upload = gr.File(
label="Upload Reference Images",
file_count="multiple",
file_types=["image"],
elem_classes=["cyber-input"]
)
uploaded_gallery = gr.Gallery(
label="Uploaded References",
columns=3,
rows=1,
height="150px",
elem_classes=["cyber-container"]
)
with gr.TabItem("✏️ Draw"):
sketch_pad = gr.Sketchpad(
label="Draw Your Monster",
type="pil",
elem_classes=["cyber-input", "sketch-pad"]
)
# Visual style options
gr.Markdown("**Visual Style Options:**")
style_modifier = gr.CheckboxGroup(
choices=[
"🎨 Artistic",
"πŸ€– Mechanical",
"✨ Magical",
"🌊 Organic",
"πŸ’Ž Crystalline"
],
label="Style Modifiers",
elem_classes=["cyber-checkbox"]
)
color_palette = gr.Radio(
choices=[
"🌈 Vibrant",
"πŸŒ‘ Dark",
"❄️ Cool",
"πŸ”₯ Warm",
"🎨 Custom"
],
label="Color Palette",
value="🌈 Vibrant",
elem_classes=["cyber-radio"]
)
with gr.Column(scale=1):
# Image analysis display
image_analysis = gr.Markdown(
value="πŸ“Š Image Analysis Results",
elem_classes=["cyber-message"]
)
# Detected features
detected_features = gr.JSON(
label="πŸ” Detected Features",
elem_classes=["cyber-stats"]
)
# Generation preview
preview_placeholder = gr.HTML(
value="""
<div class="preview-container">
<div class="scanning-overlay">
<div class="scan-line"></div>
</div>
<p>Preview will appear here...</p>
</div>
""",
elem_classes=["cyber-container"]
)
# Confidence meter
confidence_display = gr.HTML(
value="""
<div class="confidence-meter">
<label>Generation Confidence:</label>
<div class="meter-bar">
<div class="meter-fill" style="width: 0%"></div>
</div>
<span class="meter-value">0%</span>
</div>
""",
elem_classes=["cyber-container"]
)
# Visual interface specific styling
gr.HTML("""
<style>
.camera-feed {
border: 3px solid #00ff41;
border-radius: 10px;
overflow: hidden;
position: relative;
}
.camera-feed::after {
content: 'LIVE';
position: absolute;
top: 10px;
right: 10px;
background: red;
color: white;
padding: 5px 10px;
border-radius: 5px;
font-size: 12px;
animation: blink 1s infinite;
}
@keyframes blink {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.sketch-pad {
background: rgba(0, 0, 0, 0.9);
border: 2px solid #8A2BE2;
}
.preview-container {
position: relative;
height: 200px;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.scanning-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
pointer-events: none;
}
.scan-line {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 2px;
background: linear-gradient(90deg, transparent, #00ff41, transparent);
animation: scan-vertical 2s linear infinite;
}
@keyframes scan-vertical {
0% { top: 0; }
100% { top: 100%; }
}
.confidence-meter {
padding: 15px;
}
.confidence-meter label {
color: #8A2BE2;
font-size: 14px;
margin-bottom: 5px;
display: block;
}
.meter-bar {
background: rgba(0, 0, 0, 0.5);
border: 1px solid #00ff41;
height: 20px;
border-radius: 10px;
overflow: hidden;
margin: 10px 0;
}
.meter-fill {
height: 100%;
background: linear-gradient(90deg, #00ff41, #8A2BE2);
transition: width 0.5s ease;
}
.meter-value {
color: #00ff41;
font-weight: bold;
font-size: 18px;
}
</style>
""")
return visual_interface
def create_monster_status_display() -> gr.Column:
"""Create monster status display component"""
with gr.Column() as status_display:
# 3D Model viewer
model_viewer = gr.Model3D(
label="Your Digital Monster",
height=400,
elem_classes=["monster-display"]
)
# Status indicators
with gr.Row():
hp_bar = gr.HTML(
value=create_status_bar("HP", 100, 100, "#ff4444"),
elem_classes=["status-bar"]
)
hunger_bar = gr.HTML(
value=create_status_bar("Hunger", 80, 100, "#ffaa44"),
elem_classes=["status-bar"]
)
happiness_bar = gr.HTML(
value=create_status_bar("Happiness", 90, 100, "#44ff44"),
elem_classes=["status-bar"]
)
# Communication display
communication = gr.Textbox(
label="Monster Says",
value="πŸ€–πŸ’š9️⃣0️⃣",
interactive=False,
elem_classes=["cyber-dialogue"]
)
# Evolution progress
evolution_display = gr.HTML(
value="""
<div class="evolution-progress">
<h4>Evolution Progress</h4>
<div class="progress-ring">
<svg width="120" height="120">
<circle cx="60" cy="60" r="50" stroke="#333" stroke-width="10" fill="none"/>
<circle cx="60" cy="60" r="50" stroke="#8A2BE2" stroke-width="10" fill="none"
stroke-dasharray="314" stroke-dashoffset="157"
transform="rotate(-90 60 60)"/>
</svg>
<div class="progress-text">50%</div>
</div>
</div>
""",
elem_classes=["evolution-display"]
)
return status_display
def create_status_bar(label: str, current: int, max_val: int, color: str) -> str:
"""Create HTML status bar"""
percentage = (current / max_val) * 100
return f"""
<div class="status-bar-container">
<label>{label}</label>
<div class="status-bar-bg">
<div class="status-bar-fill" style="width: {percentage}%; background: {color};"></div>
</div>
<span class="status-value">{current}/{max_val}</span>
</div>
"""
def create_training_interface() -> gr.Column:
"""Create training interface component"""
with gr.Column() as training_interface:
gr.Markdown("""
### πŸ’ͺ Training Center
Train your monster to improve its stats and prepare for evolution!
""")
# Training schedule
with gr.Row():
with gr.Column():
training_schedule = gr.DataFrame(
headers=["Time", "Activity", "Stat Focus", "Intensity"],
datatype=["str", "str", "str", "number"],
value=[
["Morning", "Strength Training", "Attack", 7],
["Afternoon", "Agility Course", "Speed", 5],
["Evening", "Meditation", "Special", 3]
],
elem_classes=["cyber-table"]
)
with gr.Column():
# Training mini-game
training_game = gr.HTML(
value="""
<div class="training-game">
<h4>Quick Training</h4>
<div class="game-area">
<div class="target" id="training-target"></div>
</div>
<p>Click the targets to train!</p>
</div>
""",
elem_classes=["cyber-container"]
)
# Training rewards
rewards_display = gr.Markdown(
"""
**Today's Rewards:**
- πŸ† +15 Attack
- πŸ›‘οΈ +10 Defense
- ⚑ +5 Speed
""",
elem_classes=["cyber-message"]
)
return training_interface