File size: 6,309 Bytes
5b6e956
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c078ea1
 
 
 
 
 
 
 
5b6e956
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c078ea1
 
 
5b6e956
 
c078ea1
5b6e956
c078ea1
 
5b6e956
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c078ea1
 
 
 
 
5b6e956
 
c078ea1
 
5b6e956
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
"""
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()