exaucengarti commited on
Commit
ee62ce4
·
verified ·
1 Parent(s): f741540

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +158 -158
app.py CHANGED
@@ -1,158 +1,158 @@
1
- import os
2
- import sys
3
- import time
4
- from typing import Dict
5
- import gradio as gr
6
-
7
- # Ensure submodules are importable
8
- sys.path.append(os.path.dirname(__file__))
9
-
10
- from common import PoetryModel
11
-
12
- # Try to import sub-app factories
13
- APPS: Dict[str, callable] = {}
14
- try:
15
- from poem_generator.app import create_app as create_poem_generator
16
- APPS["Poem Generator"] = create_poem_generator
17
- except Exception:
18
- pass
19
-
20
- try:
21
- from collaborative_writer.app import create_app as create_collaborative_writer
22
- APPS["Collaborative Writer"] = create_collaborative_writer
23
- except Exception:
24
- pass
25
-
26
- try:
27
- from poem_tutor.app import create_app as create_poem_tutor
28
- APPS["Poem Tutor"] = create_poem_tutor
29
- except Exception:
30
- pass
31
-
32
- try:
33
- from vocabulary_game.app import create_app as create_vocabulary_game
34
- APPS["Vocabulary Game"] = create_vocabulary_game
35
- except Exception:
36
- pass
37
-
38
-
39
- def create_launcher(model: PoetryModel):
40
- """Create the main launcher with a simple login and rate limiting."""
41
-
42
- VALID_USER = os.getenv("APP_USERNAME", "demo")
43
- VALID_PASS = os.getenv("APP_PASSWORD", "demo123")
44
-
45
- # basic per-session rate limiting: max N actions per T seconds
46
- MAX_ACTIONS = int(os.getenv("RATE_LIMIT_MAX_ACTIONS", "30"))
47
- WINDOW_SEC = int(os.getenv("RATE_LIMIT_WINDOW_SEC", "300")) # 5 minutes
48
-
49
- def check_login(username, password, state):
50
- if not isinstance(state, dict):
51
- state = {}
52
- ok = (username or "").strip() == VALID_USER and (password or "").strip() == VALID_PASS
53
- if ok:
54
- state.update({"authed": True, "actions": [], "username": username.strip()})
55
- return {
56
- login_status: gr.update(value="✅ Login successful", visible=True),
57
- login_row: gr.update(visible=False),
58
- app_tabs: gr.update(visible=True),
59
- session_state: state,
60
- }
61
- else:
62
- return {
63
- login_status: gr.update(value="❌ Invalid credentials", visible=True),
64
- session_state: state,
65
- }
66
-
67
- def rate_gate(state):
68
- # Called before tab loads and occasionally via a button to enforce limits
69
- if not isinstance(state, dict) or not state.get("authed"):
70
- return {
71
- login_row: gr.update(visible=True),
72
- app_tabs: gr.update(visible=False),
73
- login_status: gr.update(value="🔒 Please log in", visible=True),
74
- session_state: state if isinstance(state, dict) else {},
75
- }
76
- now = time.time()
77
- actions = [t for t in state.get("actions", []) if now - t < WINDOW_SEC]
78
- state["actions"] = actions
79
- if len(actions) >= MAX_ACTIONS:
80
- remaining = int(WINDOW_SEC - (now - actions[0])) if actions else WINDOW_SEC
81
- msg = f"⏱️ Rate limit exceeded. Try again in ~{remaining}s."
82
- return {
83
- limit_status: gr.update(value=msg, visible=True),
84
- app_tabs: gr.update(visible=False),
85
- session_state: state,
86
- }
87
- # allow access
88
- return {
89
- limit_status: gr.update(visible=False),
90
- app_tabs: gr.update(visible=True),
91
- session_state: state,
92
- }
93
-
94
- def record_action(state):
95
- if isinstance(state, dict) and state.get("authed"):
96
- now = time.time()
97
- actions = [t for t in state.get("actions", []) if now - t < WINDOW_SEC]
98
- actions.append(now)
99
- state["actions"] = actions
100
- return {session_state: state}
101
-
102
- with gr.Blocks(title="AI Poetry Apps Launcher") as demo:
103
- gr.Markdown("# 🎭 AI Poetry Apps Launcher")
104
- gr.Markdown("Login to access the apps. Basic rate limiting protects API usage.")
105
-
106
- login_status = gr.Markdown("", visible=False)
107
- limit_status = gr.Markdown("", visible=False)
108
-
109
- with gr.Row(visible=True) as login_row:
110
- username_in = gr.Textbox(label="Username", placeholder="Enter username", lines=1)
111
- password_in = gr.Textbox(label="Password", placeholder="Enter password", type="password", lines=1)
112
- login_btn = gr.Button("Login", variant="primary")
113
-
114
- session_state = gr.State({})
115
-
116
- with gr.Tabs(visible=False) as app_tabs:
117
- # Render each available sub-app as a tab
118
- for title, factory in APPS.items():
119
- with gr.Tab(title):
120
- try:
121
- subapp = factory(model)
122
- # Add a lightweight "ping" button to count actions when user triggers generation
123
- gr.Markdown("Accessing app… actions are rate-limited.")
124
- ping_btn = gr.Button("Record Action")
125
- ping_btn.click(record_action, inputs=[session_state], outputs=[session_state])
126
- # Mount the existing Blocks app inside
127
- gr.HTML("<hr>")
128
- subapp.render()
129
- except Exception as e:
130
- gr.Markdown(f"⚠️ Failed to load {title}: {e}")
131
-
132
- login_btn.click(
133
- check_login,
134
- inputs=[username_in, password_in, session_state],
135
- outputs=[login_status, login_row, app_tabs, session_state],
136
- ).then(
137
- rate_gate,
138
- inputs=[session_state],
139
- outputs=[limit_status, app_tabs, session_state],
140
- )
141
-
142
- # Gate access on load as well
143
- gr.Button("Re-check Access").click(
144
- rate_gate,
145
- inputs=[session_state],
146
- outputs=[limit_status, app_tabs, session_state],
147
- )
148
-
149
- return demo
150
-
151
-
152
- if __name__ == "__main__":
153
- from dotenv import load_dotenv
154
- load_dotenv()
155
- model = PoetryModel()
156
- app = create_launcher(model)
157
- # Spaces expects `app.py` to launch
158
- app.launch()
 
1
+ import os
2
+ import sys
3
+ import time
4
+ from typing import Dict
5
+ import gradio as gr
6
+
7
+ # Ensure submodules are importable
8
+ sys.path.append(os.path.dirname(__file__))
9
+
10
+ from common import PoetryModel
11
+
12
+ # Try to import sub-app factories
13
+ APPS: Dict[str, callable] = {}
14
+ try:
15
+ from poem_generator.app import create_app as create_poem_generator
16
+ APPS["Poem Generator"] = create_poem_generator
17
+ except Exception:
18
+ pass
19
+
20
+ try:
21
+ from collaborative_writer.app import create_app as create_collaborative_writer
22
+ APPS["Collaborative Writer"] = create_collaborative_writer
23
+ except Exception:
24
+ pass
25
+
26
+ try:
27
+ from poem_tutor.app import create_app as create_poem_tutor
28
+ APPS["Poem Tutor"] = create_poem_tutor
29
+ except Exception:
30
+ pass
31
+
32
+ try:
33
+ from vocabulary_game.app import create_app as create_vocabulary_game
34
+ APPS["Vocabulary Game"] = create_vocabulary_game
35
+ except Exception:
36
+ pass
37
+
38
+
39
+ def create_launcher(model: PoetryModel):
40
+ """Create the main launcher with a simple login and rate limiting."""
41
+
42
+ VALID_USER = os.getenv("APP_USERNAME", "demo")
43
+ VALID_PASS = os.getenv("APP_PASSWORD", "demo123")
44
+
45
+ # basic per-session rate limiting: max N actions per T seconds
46
+ MAX_ACTIONS = int(os.getenv("RATE_LIMIT_MAX_ACTIONS", "30"))
47
+ WINDOW_SEC = int(os.getenv("RATE_LIMIT_WINDOW_SEC", "300")) # 5 minutes
48
+
49
+ def check_login(username, password, state):
50
+ if not isinstance(state, dict):
51
+ state = {}
52
+ ok = (username or "").strip() == VALID_USER and (password or "").strip() == VALID_PASS
53
+ if ok:
54
+ state.update({"authed": True, "actions": [], "username": username.strip()})
55
+ return {
56
+ login_status: gr.update(value="✅ Login successful", visible=True),
57
+ login_row: gr.update(visible=False),
58
+ app_tabs: gr.update(visible=True),
59
+ session_state: state,
60
+ }
61
+ else:
62
+ return {
63
+ login_status: gr.update(value="❌ Invalid credentials", visible=True),
64
+ session_state: state,
65
+ }
66
+
67
+ def rate_gate(state):
68
+ # Called before tab loads and occasionally via a button to enforce limits
69
+ if not isinstance(state, dict) or not state.get("authed"):
70
+ return {
71
+ login_row: gr.update(visible=True),
72
+ app_tabs: gr.update(visible=False),
73
+ login_status: gr.update(value="🔒 Please log in", visible=True),
74
+ session_state: state if isinstance(state, dict) else {},
75
+ }
76
+ now = time.time()
77
+ actions = [t for t in state.get("actions", []) if now - t < WINDOW_SEC]
78
+ state["actions"] = actions
79
+ if len(actions) >= MAX_ACTIONS:
80
+ remaining = int(WINDOW_SEC - (now - actions[0])) if actions else WINDOW_SEC
81
+ msg = f"⏱️ Rate limit exceeded. Try again in ~{remaining}s."
82
+ return {
83
+ limit_status: gr.update(value=msg, visible=True),
84
+ app_tabs: gr.update(visible=False),
85
+ session_state: state,
86
+ }
87
+ # allow access
88
+ return {
89
+ limit_status: gr.update(visible=False),
90
+ app_tabs: gr.update(visible=True),
91
+ session_state: state,
92
+ }
93
+
94
+ def record_action(state):
95
+ if isinstance(state, dict) and state.get("authed"):
96
+ now = time.time()
97
+ actions = [t for t in state.get("actions", []) if now - t < WINDOW_SEC]
98
+ actions.append(now)
99
+ state["actions"] = actions
100
+ return {session_state: state}
101
+
102
+ with gr.Blocks(title="AI Poetry Apps Launcher") as demo:
103
+ gr.Markdown("# 🎭 AI Poetry Apps Launcher")
104
+ gr.Markdown("Login to access the apps.")
105
+
106
+ login_status = gr.Markdown("", visible=False)
107
+ limit_status = gr.Markdown("", visible=False)
108
+
109
+ with gr.Row(visible=True) as login_row:
110
+ username_in = gr.Textbox(label="Username", placeholder="Enter username", lines=1)
111
+ password_in = gr.Textbox(label="Password", placeholder="Enter password", type="password", lines=1)
112
+ login_btn = gr.Button("Login", variant="primary")
113
+
114
+ session_state = gr.State({})
115
+
116
+ with gr.Tabs(visible=False) as app_tabs:
117
+ # Render each available sub-app as a tab
118
+ for title, factory in APPS.items():
119
+ with gr.Tab(title):
120
+ try:
121
+ subapp = factory(model)
122
+ # Add a lightweight "ping" button to count actions when user triggers generation
123
+ gr.Markdown("Accessing app… actions are rate-limited.")
124
+ ping_btn = gr.Button("Record Action")
125
+ ping_btn.click(record_action, inputs=[session_state], outputs=[session_state])
126
+ # Mount the existing Blocks app inside
127
+ gr.HTML("<hr>")
128
+ subapp.render()
129
+ except Exception as e:
130
+ gr.Markdown(f"⚠️ Failed to load {title}: {e}")
131
+
132
+ login_btn.click(
133
+ check_login,
134
+ inputs=[username_in, password_in, session_state],
135
+ outputs=[login_status, login_row, app_tabs, session_state],
136
+ ).then(
137
+ rate_gate,
138
+ inputs=[session_state],
139
+ outputs=[limit_status, app_tabs, session_state],
140
+ )
141
+
142
+ # Gate access on load as well
143
+ gr.Button("Re-check Access").click(
144
+ rate_gate,
145
+ inputs=[session_state],
146
+ outputs=[limit_status, app_tabs, session_state],
147
+ )
148
+
149
+ return demo
150
+
151
+
152
+ if __name__ == "__main__":
153
+ from dotenv import load_dotenv
154
+ load_dotenv()
155
+ model = PoetryModel()
156
+ app = create_launcher(model)
157
+ # Spaces expects `app.py` to launch
158
+ app.launch()