Işıl Kütürüp commited on
Commit
dcd013b
Β·
1 Parent(s): 19b8945

Upgrade UI

Browse files
Files changed (1) hide show
  1. app.py +120 -6
app.py CHANGED
@@ -3,8 +3,10 @@ import os
3
  import gradio as gr
4
  from huggingface_hub import InferenceClient
5
  from engine.chat import generate_response
6
- from engine.persona import get_empty_persona, is_persona_empty, validate_persona
 
7
  from engine.prompt_builder import get_avatar_path, load_character
 
8
 
9
  logging.basicConfig(level=logging.INFO)
10
  logger = logging.getLogger(__name__)
@@ -30,6 +32,16 @@ char_name = character.get("name", CHARACTER_ID)
30
  char_role = character.get("identity", {}).get("role", "")
31
  greeting = character.get("greeting", "Hello. What do you want?")
32
 
 
 
 
 
 
 
 
 
 
 
33
  # ── Gradio respond function ────────────────────────────────────────────────────
34
  def respond(
35
  message: str,
@@ -71,29 +83,131 @@ chatbot = gr.ChatInterface(
71
  value=[{"role": "assistant", "content": greeting}],
72
  label=char_name,
73
  avatar_images=(None, avatar_path),
74
- height=500,
75
  ),
76
  additional_inputs=[
77
  gr.Slider(minimum=1, maximum=2048, value=512, step=1, label="Max new tokens"),
78
  gr.Slider(minimum=0.1, maximum=4.0, value=0.7, step=0.1, label="Temperature"),
79
  gr.Slider(minimum=0.1, maximum=1.0, value=0.95, step=0.05, label="Top-p"),
80
- gr.State(get_empty_persona()), # persona state β€” hidden until Phase 9 form is wired
81
  ],
82
  additional_inputs_accordion=gr.Accordion("βš™οΈ Settings", open=False),
83
  )
84
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  with gr.Blocks(title=f"Chat with {char_name}") as demo:
 
 
86
  with gr.Sidebar():
87
- gr.LoginButton()
 
88
  gr.Markdown(f"## {char_name}")
89
  if char_role:
90
  gr.Markdown(f"*{char_role}*")
91
  if avatar_path:
92
- gr.Image(value=avatar_path, show_label=False, height=280, container=False)
93
  else:
94
- gr.Markdown("*No avatar image found.*")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  chatbot.render()
96
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
 
98
  if __name__ == "__main__":
99
  demo.launch()
 
3
  import gradio as gr
4
  from huggingface_hub import InferenceClient
5
  from engine.chat import generate_response
6
+ from engine.memory import load_recent_messages
7
+ from engine.persona import get_empty_persona, is_persona_empty, persona_summary, validate_persona
8
  from engine.prompt_builder import get_avatar_path, load_character
9
+ from engine.suggestions import generate_suggestions
10
 
11
  logging.basicConfig(level=logging.INFO)
12
  logger = logging.getLogger(__name__)
 
32
  char_role = character.get("identity", {}).get("role", "")
33
  greeting = character.get("greeting", "Hello. What do you want?")
34
 
35
+ # ── Persona state ──────────────────────────────────────────────────────────────
36
+ # Defined before ChatInterface so it can be referenced in additional_inputs
37
+ # AND updated by the sidebar form inside gr.Blocks.
38
+ persona_state = gr.State(get_empty_persona())
39
+
40
+ # ── Suggestion text states ─────────────────────────────────────────────────────
41
+ # gr.Button value can't be read as input, so we store each suggestion's
42
+ # plain text in a separate gr.State and use that to fill the textbox.
43
+ suggestion_texts = [gr.State("") for _ in range(4)]
44
+
45
  # ── Gradio respond function ────────────────────────────────────────────────────
46
  def respond(
47
  message: str,
 
83
  value=[{"role": "assistant", "content": greeting}],
84
  label=char_name,
85
  avatar_images=(None, avatar_path),
86
+ height=480,
87
  ),
88
  additional_inputs=[
89
  gr.Slider(minimum=1, maximum=2048, value=512, step=1, label="Max new tokens"),
90
  gr.Slider(minimum=0.1, maximum=4.0, value=0.7, step=0.1, label="Temperature"),
91
  gr.Slider(minimum=0.1, maximum=1.0, value=0.95, step=0.05, label="Top-p"),
92
+ persona_state, # hidden β€” updated by the sidebar form
93
  ],
94
  additional_inputs_accordion=gr.Accordion("βš™οΈ Settings", open=False),
95
  )
96
 
97
+
98
+ # ── Event handlers ─────────────────────────────────────────────────────────────
99
+
100
+ def apply_persona_fn(name, age, gender, personality, background):
101
+ persona = validate_persona({
102
+ "name": name, "age": age, "gender": gender,
103
+ "personality": personality, "background": background,
104
+ })
105
+ if is_persona_empty(persona):
106
+ return persona, "*No persona set.*"
107
+ return persona, f"*βœ“ Active: {persona_summary(persona)}*"
108
+
109
+
110
+ def clear_persona_fn():
111
+ # Returns: persona_state, 5 form fields, status
112
+ return get_empty_persona(), "", "", "", "", "", "*Persona cleared.*"
113
+
114
+
115
+ def get_suggestions_fn():
116
+ """Generate 4 reply suggestions from recent conversation memory."""
117
+ if not HF_TOKEN:
118
+ return [gr.update(visible=False)] + [gr.update(visible=False)] * 4 + [""] * 4
119
+
120
+ recent = load_recent_messages(CHARACTER_ID, max_messages=6)
121
+ if not recent:
122
+ return [gr.update(visible=False)] + [gr.update(visible=False)] * 4 + [""] * 4
123
+
124
+ client = InferenceClient(token=HF_TOKEN)
125
+ suggestions = generate_suggestions(character, recent, client, MODEL)
126
+
127
+ group_update = gr.update(visible=True)
128
+ btn_updates = [gr.update(value=f"{s['emoji']} {s['text']}", visible=True) for s in suggestions]
129
+ text_values = [s["text"] for s in suggestions]
130
+
131
+ return [group_update] + btn_updates + text_values
132
+
133
+
134
+ # ── Blocks layout ──────────────────────────────────────────────────────────────
135
  with gr.Blocks(title=f"Chat with {char_name}") as demo:
136
+
137
+ # ── Sidebar ────────────────────────────────────────────────────────────────
138
  with gr.Sidebar():
139
+
140
+ # Character info
141
  gr.Markdown(f"## {char_name}")
142
  if char_role:
143
  gr.Markdown(f"*{char_role}*")
144
  if avatar_path:
145
+ gr.Image(value=avatar_path, show_label=False, height=220, container=False)
146
  else:
147
+ gr.Markdown("*No avatar found.*")
148
+
149
+ gr.Markdown("---")
150
+
151
+ # Persona form
152
+ gr.Markdown("### 🎭 Your Persona")
153
+ gr.Markdown("*Define who you're playing β€” all fields optional.*")
154
+
155
+ p_name = gr.Textbox(label="Name", placeholder="e.g. Alex")
156
+ p_age = gr.Textbox(label="Age", placeholder="e.g. 28")
157
+ p_gender = gr.Textbox(label="Gender", placeholder="e.g. Female")
158
+ p_personality = gr.Textbox(label="Personality", placeholder="e.g. curious, skeptical")
159
+ p_background = gr.Textbox(
160
+ label="Background", lines=2,
161
+ placeholder="e.g. A journalist investigating a disappearance",
162
+ )
163
+
164
+ with gr.Row():
165
+ apply_btn = gr.Button("Apply", variant="primary", scale=2)
166
+ clear_btn = gr.Button("Clear", scale=1)
167
+
168
+ persona_status = gr.Markdown("")
169
+
170
+ # ── Chat area ──────────────────────────────────────────────────────────────
171
  chatbot.render()
172
 
173
+ # ── Suggestion area ────────────────────────────────────────────────────────
174
+ suggest_btn = gr.Button("πŸ’‘ Suggest replies", size="sm", variant="secondary")
175
+
176
+ with gr.Group(visible=False) as suggestion_group:
177
+ with gr.Row():
178
+ s_btns = [
179
+ gr.Button("", variant="secondary", size="sm", visible=False)
180
+ for _ in range(4)
181
+ ]
182
+
183
+ # ── Events ─────────────────────────────────────────────────────────────────
184
+
185
+ apply_btn.click(
186
+ fn=apply_persona_fn,
187
+ inputs=[p_name, p_age, p_gender, p_personality, p_background],
188
+ outputs=[persona_state, persona_status],
189
+ )
190
+
191
+ clear_btn.click(
192
+ fn=clear_persona_fn,
193
+ inputs=[],
194
+ outputs=[persona_state, p_name, p_age, p_gender, p_personality, p_background, persona_status],
195
+ )
196
+
197
+ suggest_btn.click(
198
+ fn=get_suggestions_fn,
199
+ inputs=[],
200
+ outputs=[suggestion_group] + s_btns + suggestion_texts,
201
+ )
202
+
203
+ # Each suggestion button fills the chat textbox with its stored text
204
+ for btn, text_state in zip(s_btns, suggestion_texts):
205
+ btn.click(
206
+ fn=lambda t: t,
207
+ inputs=[text_state],
208
+ outputs=[chatbot.textbox],
209
+ )
210
+
211
 
212
  if __name__ == "__main__":
213
  demo.launch()