Spaces:
Sleeping
Sleeping
| """ | |
| Character Forge - Main Application Entry Point | |
| =============================================== | |
| License: GNU AGPL v3.0 | |
| Copyright (C) 2025 Gregor Hubert, Max Koch "cronos3k" | |
| This program is free software: you can redistribute it and/or modify | |
| it under the terms of the GNU Affero General Public License as published by | |
| the Free Software Foundation, either version 3 of the License, or | |
| (at your option) any later version. | |
| Main entry point for the Character Forge Streamlit application. | |
| Run with: streamlit run app.py | |
| """ | |
| import streamlit as st | |
| from pathlib import Path | |
| # Import configuration | |
| from config.settings import Settings | |
| # Import components | |
| from ui.components.backend_selector import render_backend_selector | |
| from ui.components.status_display import render_status_display | |
| def initialize_session_state(): | |
| """ | |
| Initialize Streamlit session state with default values. | |
| Session state is Streamlit's way of persisting data across reruns. | |
| This function sets up all the global state our app needs. | |
| """ | |
| # Backend selection | |
| if 'backend' not in st.session_state: | |
| st.session_state.backend = "Gemini API (Cloud)" | |
| # API keys | |
| if 'gemini_api_key' not in st.session_state: | |
| st.session_state.gemini_api_key = Settings.get_gemini_api_key() | |
| # Output directory | |
| if 'output_dir' not in st.session_state: | |
| st.session_state.output_dir = Settings.OUTPUT_DIR | |
| # Generation history | |
| if 'history' not in st.session_state: | |
| st.session_state.history = [] | |
| def render_header(): | |
| """Render the application header and global controls.""" | |
| st.set_page_config( | |
| page_title="Character Forge - AI Image Generation", | |
| page_icon="π₯", | |
| layout="wide", | |
| initial_sidebar_state="expanded" | |
| ) | |
| st.title("π₯ Character Forge - AI Image Generation") | |
| st.markdown( | |
| """ | |
| **Professional character sheets and multi-image composition powered by AI** | |
| *Supports Gemini API, OmniGen2, and ComfyUI backends* | |
| """ | |
| ) | |
| # Show API key warning if not configured | |
| if not st.session_state.get('gemini_api_key'): | |
| st.warning( | |
| "β οΈ **API Key Required**: Please enter your Gemini API key in the sidebar to start generating. " | |
| "Get a free API key at [Google AI Studio](https://aistudio.google.com/app/apikey).", | |
| icon="π" | |
| ) | |
| st.divider() | |
| def render_global_backend_selector(): | |
| """ | |
| Render the global backend selector that applies to all pages. | |
| This is one of the key improvements over Gradio - no parameter drilling! | |
| The backend selection is stored in session_state and accessible everywhere. | |
| """ | |
| st.subheader("π§ Generation Backend") | |
| col1, col2 = st.columns([2, 1]) | |
| with col1: | |
| # Render the backend selector component | |
| backend = render_backend_selector() | |
| st.session_state.backend = backend | |
| with col2: | |
| # Render status display | |
| if st.button("π Refresh Status"): | |
| st.rerun() | |
| st.divider() | |
| def render_sidebar(): | |
| """Render the sidebar with navigation and settings.""" | |
| with st.sidebar: | |
| st.image("https://via.placeholder.com/150x150.png?text=π", width=150) | |
| st.markdown("## Navigation") | |
| st.page_link("pages/01_π₯_Character_Forge.py", label="π₯ Character Forge") | |
| st.page_link("pages/02_π¬_Composition_Assistant.py", label="π¬ Composition Assistant") | |
| st.page_link("pages/03_πΈ_Standard_Interface.py", label="πΈ Standard Interface") | |
| st.divider() | |
| st.markdown("## Settings") | |
| # API Key input (for Gemini) | |
| st.markdown("### π API Key") | |
| st.info("Get your FREE API key at [Google AI Studio](https://aistudio.google.com/app/apikey)") | |
| api_key = st.text_input( | |
| "Gemini API Key", | |
| value=st.session_state.gemini_api_key or "", | |
| type="password", | |
| help="Enter your Google Gemini API key. Required for Gemini backend. Your key stays in YOUR session only.", | |
| placeholder="Enter your API key here..." | |
| ) | |
| if api_key != st.session_state.gemini_api_key: | |
| st.session_state.gemini_api_key = api_key | |
| # Output directory | |
| st.text_input( | |
| "Output Directory", | |
| value=str(st.session_state.output_dir), | |
| disabled=True, | |
| help="All generated images are saved here" | |
| ) | |
| st.divider() | |
| st.markdown("## About") | |
| st.markdown( | |
| """ | |
| **Character Forge** v1.0.0 | |
| Multi-backend AI image generation with specialized tools for: | |
| - Character sheet creation | |
| - Multi-image composition | |
| - Text/image-to-image generation | |
| --- | |
| **License:** | |
| GNU AGPL v3.0 | |
| **Privacy:** | |
| Your API key is stored only in YOUR session. | |
| It is never shared with other users. | |
| **Get Started:** | |
| - [Get API Key](https://aistudio.google.com/app/apikey) | |
| - [HuggingFace Space](https://huggingface.co/spaces/ghmk/character_forge) | |
| """ | |
| ) | |
| def main(): | |
| """Main application entry point.""" | |
| # Initialize session state | |
| initialize_session_state() | |
| # Render header | |
| render_header() | |
| # Render global backend selector | |
| render_global_backend_selector() | |
| # Render sidebar | |
| render_sidebar() | |
| # Main content area | |
| st.info( | |
| """ | |
| π **Select a tool from the sidebar to get started:** | |
| - **π₯ Character Forge**: Create multi-angle character sheets automatically | |
| - **π¬ Composition Assistant**: Smart multi-image composition with auto-prompts | |
| - **πΈ Standard Interface**: Direct text-to-image and image-to-image generation | |
| The backend selector above applies to all tools. | |
| """ | |
| ) | |
| # Show recent generations | |
| if st.session_state.history: | |
| st.subheader("πΈ Recent Generations") | |
| cols = st.columns(4) | |
| for idx, item in enumerate(st.session_state.history[-4:]): | |
| with cols[idx]: | |
| st.image(item['image'], caption=item['name'], use_container_width=True) | |
| if __name__ == "__main__": | |
| main() | |