akhaliq HF Staff commited on
Commit
f4523d4
·
1 Parent(s): ef8c514

beta chat ui

Browse files
Files changed (1) hide show
  1. app.py +359 -18
app.py CHANGED
@@ -4640,6 +4640,14 @@ with gr.Blocks(
4640
  margin: 8px 0;
4641
  text-align: center;
4642
  }
 
 
 
 
 
 
 
 
4643
  """
4644
  ) as demo:
4645
  history = gr.State([])
@@ -4652,6 +4660,57 @@ with gr.Blocks(
4652
 
4653
  with gr.Sidebar() as sidebar:
4654
  login_button = gr.LoginButton()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4655
 
4656
  # Theme Selector (hidden for end users, developers can modify code)
4657
  with gr.Column(visible=False):
@@ -4671,8 +4730,8 @@ with gr.Blocks(
4671
  label="Project URL",
4672
  placeholder="https://huggingface.co/spaces/user/space OR https://huggingface.co/user/model OR https://github.com/owner/repo",
4673
  lines=1
4674
- )
4675
- load_project_btn = gr.Button("Import Project", variant="secondary", size="sm")
4676
  load_project_status = gr.Markdown(visible=False)
4677
 
4678
  input = gr.Textbox(
@@ -4794,34 +4853,37 @@ with gr.Blocks(
4794
  visible=False
4795
  )
4796
 
4797
- def on_image_to_image_toggle(toggled):
4798
- # Show generation image input and its prompt when image-to-image is enabled
4799
- return gr.update(visible=bool(toggled)), gr.update(visible=bool(toggled))
 
4800
 
4801
- def on_text_to_image_toggle(toggled):
4802
- return gr.update(visible=bool(toggled))
 
4803
 
4804
  image_to_image_toggle.change(
4805
  on_image_to_image_toggle,
4806
- inputs=[image_to_image_toggle],
4807
  outputs=[generation_image_input, image_to_image_prompt]
4808
  )
4809
- def on_image_to_video_toggle(toggled):
4810
- return gr.update(visible=bool(toggled)), gr.update(visible=bool(toggled))
 
4811
 
4812
  image_to_video_toggle.change(
4813
  on_image_to_video_toggle,
4814
- inputs=[image_to_video_toggle],
4815
  outputs=[generation_image_input, image_to_video_prompt]
4816
  )
4817
  image_generation_toggle.change(
4818
  on_text_to_image_toggle,
4819
- inputs=[image_generation_toggle],
4820
  outputs=[text_to_image_prompt]
4821
  )
4822
  text_to_video_toggle.change(
4823
  on_text_to_image_toggle,
4824
- inputs=[text_to_video_toggle],
4825
  outputs=[text_to_video_prompt]
4826
  )
4827
  model_dropdown = gr.Dropdown(
@@ -4831,7 +4893,7 @@ with gr.Blocks(
4831
  visible=True
4832
  )
4833
  provider_state = gr.State("auto")
4834
- gr.Markdown("**Quick start**", visible=True)
4835
  with gr.Column(visible=True) as quick_examples_col:
4836
  for i, demo_item in enumerate(DEMO_LIST[:3]):
4837
  demo_card = gr.Button(
@@ -5060,12 +5122,12 @@ with gr.Blocks(
5060
  )
5061
 
5062
  def begin_generation_ui():
5063
- # Hide only the sidebar; keep main UI visible; do not show any status text
5064
- return [gr.update(visible=False), gr.update(visible=False)]
5065
 
5066
  def end_generation_ui():
5067
- # Keep sidebar visible but collapsed; hide the status
5068
- return [gr.update(visible=True, open=False), gr.update(visible=False)]
5069
 
5070
  btn.click(
5071
  begin_generation_ui,
@@ -5089,6 +5151,285 @@ with gr.Blocks(
5089
  inputs=[history],
5090
  outputs=[space_name_input, deploy_btn]
5091
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5092
  # Update preview when code or language changes
5093
  code_output.change(preview_logic, inputs=[code_output, language_dropdown], outputs=sandbox)
5094
  language_dropdown.change(preview_logic, inputs=[code_output, language_dropdown], outputs=sandbox)
 
4640
  margin: 8px 0;
4641
  text-align: center;
4642
  }
4643
+ /* Darker chat bubbles for better contrast in dark theme */
4644
+ #beta_chat .message.user, #beta_chat .message.assistant {
4645
+ background: rgba(60, 60, 60, 0.85);
4646
+ color: #f5f5f5;
4647
+ }
4648
+ #beta_chat .message.user {
4649
+ background: rgba(70, 70, 70, 0.95);
4650
+ }
4651
  """
4652
  ) as demo:
4653
  history = gr.State([])
 
4660
 
4661
  with gr.Sidebar() as sidebar:
4662
  login_button = gr.LoginButton()
4663
+ beta_toggle = gr.Checkbox(
4664
+ value=False,
4665
+ label="Beta: Chat UI",
4666
+ info="Switch to the new chat-based sidebar interface"
4667
+ )
4668
+
4669
+ # Simple chat-based controller for sidebar
4670
+ sidebar_chatbot = gr.Chatbot(
4671
+ type="messages",
4672
+ show_label=False,
4673
+ height=320,
4674
+ layout="bubble",
4675
+ bubble_full_width=True,
4676
+ group_consecutive_messages=True,
4677
+ visible=False,
4678
+ elem_id="beta_chat"
4679
+ )
4680
+ sidebar_msg = gr.MultimodalTextbox(
4681
+ placeholder=(
4682
+ "Describe what to build. Examples: 'use streamlit', 'text to video: <prompt>'. "
4683
+ "See Advanced Commands below for the full list."
4684
+ ),
4685
+ submit_btn=True,
4686
+ stop_btn=False,
4687
+ show_label=False,
4688
+ sources=["upload", "microphone"],
4689
+ visible=False
4690
+ )
4691
+ chat_clear_btn = gr.ClearButton([sidebar_msg, sidebar_chatbot], visible=False)
4692
+
4693
+ # Collapsed Advanced Commands reference
4694
+ with gr.Accordion(label="Advanced Commands", open=False, visible=False) as advanced_commands:
4695
+ gr.Markdown(
4696
+ value=(
4697
+ "### Command Reference\n"
4698
+ "- **Language**: 'use streamlit' | 'use gradio' | 'use html'\n"
4699
+ "- **Web search**: 'enable web search' | 'disable web search'\n"
4700
+ "- **Model**: 'model <name>' (exact match to items in the Model dropdown)\n"
4701
+ "- **Website redesign**: include a URL in your message (e.g., 'https://example.com')\n"
4702
+ "- **Text → Image**: 'generate images: <prompt>' or 'text to image: <prompt>'\n"
4703
+ "- **Image → Image**: 'image to image: <prompt>' (attach an image)\n"
4704
+ "- **Image → Video**: 'image to video: <prompt>' (attach an image)\n"
4705
+ "- **Text → Video**: 'text to video: <prompt>' or 'generate video: <prompt>'\n"
4706
+ "- **Files & media**: attach documents or images directly; the first image is used for generation, the first non-image is treated as a reference file\n"
4707
+ "- **Multiple directives**: separate with commas. The first segment is the main build prompt.\n\n"
4708
+ "Examples:\n"
4709
+ "- anycoder coffee shop, text to video: coffee pouring into cup\n"
4710
+ "- redesign https://example.com, use streamlit, enable web search\n"
4711
+ "- dashboard ui, generate images: minimalist pastel hero"
4712
+ )
4713
+ )
4714
 
4715
  # Theme Selector (hidden for end users, developers can modify code)
4716
  with gr.Column(visible=False):
 
4730
  label="Project URL",
4731
  placeholder="https://huggingface.co/spaces/user/space OR https://huggingface.co/user/model OR https://github.com/owner/repo",
4732
  lines=1
4733
+ , visible=True)
4734
+ load_project_btn = gr.Button("Import Project", variant="secondary", size="sm", visible=True)
4735
  load_project_status = gr.Markdown(visible=False)
4736
 
4737
  input = gr.Textbox(
 
4853
  visible=False
4854
  )
4855
 
4856
+ def on_image_to_image_toggle(toggled, beta_enabled):
4857
+ # Only show in classic mode (beta disabled)
4858
+ vis = bool(toggled) and not bool(beta_enabled)
4859
+ return gr.update(visible=vis), gr.update(visible=vis)
4860
 
4861
+ def on_text_to_image_toggle(toggled, beta_enabled):
4862
+ vis = bool(toggled) and not bool(beta_enabled)
4863
+ return gr.update(visible=vis)
4864
 
4865
  image_to_image_toggle.change(
4866
  on_image_to_image_toggle,
4867
+ inputs=[image_to_image_toggle, beta_toggle],
4868
  outputs=[generation_image_input, image_to_image_prompt]
4869
  )
4870
+ def on_image_to_video_toggle(toggled, beta_enabled):
4871
+ vis = bool(toggled) and not bool(beta_enabled)
4872
+ return gr.update(visible=vis), gr.update(visible=vis)
4873
 
4874
  image_to_video_toggle.change(
4875
  on_image_to_video_toggle,
4876
+ inputs=[image_to_video_toggle, beta_toggle],
4877
  outputs=[generation_image_input, image_to_video_prompt]
4878
  )
4879
  image_generation_toggle.change(
4880
  on_text_to_image_toggle,
4881
+ inputs=[image_generation_toggle, beta_toggle],
4882
  outputs=[text_to_image_prompt]
4883
  )
4884
  text_to_video_toggle.change(
4885
  on_text_to_image_toggle,
4886
+ inputs=[text_to_video_toggle, beta_toggle],
4887
  outputs=[text_to_video_prompt]
4888
  )
4889
  model_dropdown = gr.Dropdown(
 
4893
  visible=True
4894
  )
4895
  provider_state = gr.State("auto")
4896
+ quick_start_md = gr.Markdown("**Quick start**", visible=True)
4897
  with gr.Column(visible=True) as quick_examples_col:
4898
  for i, demo_item in enumerate(DEMO_LIST[:3]):
4899
  demo_card = gr.Button(
 
5122
  )
5123
 
5124
  def begin_generation_ui():
5125
+ # If beta chat UI is active, keep sidebar visible; otherwise, default behavior
5126
+ return [gr.update(), gr.update(visible=False)]
5127
 
5128
  def end_generation_ui():
5129
+ # Keep sidebar as is; hide the status
5130
+ return [gr.update(), gr.update(visible=False)]
5131
 
5132
  btn.click(
5133
  begin_generation_ui,
 
5151
  inputs=[history],
5152
  outputs=[space_name_input, deploy_btn]
5153
  )
5154
+
5155
+ # --- Chat-based sidebar controller logic ---
5156
+ def _find_model_by_name(name: str):
5157
+ for m in AVAILABLE_MODELS:
5158
+ if m["name"].lower() == name.lower():
5159
+ return m
5160
+ return None
5161
+
5162
+ def _extract_url(text: str) -> str | None:
5163
+ import re
5164
+ match = re.search(r"https?://[^\s]+", text or "")
5165
+ return match.group(0) if match else None
5166
+
5167
+ def apply_chat_command(message, chat_messages):
5168
+ # Support plain text or dict from MultimodalTextbox
5169
+ text = message if isinstance(message, str) else (message.get("text", "") if isinstance(message, dict) else "")
5170
+ files = []
5171
+ if isinstance(message, dict):
5172
+ files = message.get("files", []) or []
5173
+
5174
+ # Defaults to skip updates where unchanged
5175
+ upd_input = gr.skip()
5176
+ upd_language = gr.skip()
5177
+ upd_url = gr.skip()
5178
+ upd_file = gr.skip()
5179
+ upd_image_for_gen = gr.skip()
5180
+ upd_search = gr.skip()
5181
+ upd_img_gen = gr.skip()
5182
+ upd_t2i_prompt = gr.skip()
5183
+ upd_i2i_toggle = gr.skip()
5184
+ upd_i2i_prompt = gr.skip()
5185
+ upd_i2v_toggle = gr.skip()
5186
+ upd_i2v_prompt = gr.skip()
5187
+ upd_t2v_toggle = gr.skip()
5188
+ upd_t2v_prompt = gr.skip()
5189
+ upd_model_dropdown = gr.skip()
5190
+ upd_current_model = gr.skip()
5191
+
5192
+ # Split by comma to separate main prompt and directives
5193
+ segments = [seg.strip() for seg in (text or "").split(",") if seg.strip()]
5194
+ main_prompt = segments[0] if segments else text
5195
+
5196
+ # Helper to get text after ':' in original casing
5197
+ def after_colon(original_segment: str) -> str:
5198
+ parts = original_segment.split(":", 1)
5199
+ return parts[1].strip() if len(parts) == 2 else ""
5200
+
5201
+ # Process directives from all segments (including first if user puts directives there),
5202
+ # but always set the main build prompt from the first segment only
5203
+ for seg in segments:
5204
+ seg_norm = seg.lower()
5205
+ # Language
5206
+ if "use streamlit" in seg_norm:
5207
+ upd_language = gr.update(value="streamlit")
5208
+ elif "use gradio" in seg_norm:
5209
+ upd_language = gr.update(value="gradio")
5210
+ elif "use html" in seg_norm or "as html" in seg_norm:
5211
+ upd_language = gr.update(value="html")
5212
+
5213
+ # Web search
5214
+ if (
5215
+ "enable web search" in seg_norm
5216
+ or "web search on" in seg_norm
5217
+ or "with web search" in seg_norm
5218
+ or "search the web" in seg_norm
5219
+ ):
5220
+ upd_search = gr.update(value=True)
5221
+ if (
5222
+ "disable web search" in seg_norm
5223
+ or "no web search" in seg_norm
5224
+ or "web search off" in seg_norm
5225
+ ):
5226
+ upd_search = gr.update(value=False)
5227
+
5228
+ # Text-to-image
5229
+ if ("generate images" in seg_norm) or ("text to image" in seg_norm) or ("text-to-image" in seg_norm):
5230
+ upd_img_gen = gr.update(value=True)
5231
+ p = after_colon(seg)
5232
+ if p:
5233
+ upd_t2i_prompt = gr.update(value=p)
5234
+
5235
+ # Image-to-image
5236
+ if ("image to image" in seg_norm) or ("image-to-image" in seg_norm) or ("transform image" in seg_norm):
5237
+ upd_i2i_toggle = gr.update(value=True)
5238
+ p = after_colon(seg)
5239
+ if p:
5240
+ upd_i2i_prompt = gr.update(value=p)
5241
+
5242
+ # Image-to-video
5243
+ if ("image to video" in seg_norm) or ("image-to-video" in seg_norm):
5244
+ upd_i2v_toggle = gr.update(value=True)
5245
+ p = after_colon(seg)
5246
+ if p:
5247
+ upd_i2v_prompt = gr.update(value=p)
5248
+
5249
+ # Text-to-video
5250
+ if ("text to video" in seg_norm) or ("text-to-video" in seg_norm) or ("generate video" in seg_norm):
5251
+ upd_t2v_toggle = gr.update(value=True)
5252
+ p = after_colon(seg)
5253
+ if p:
5254
+ upd_t2v_prompt = gr.update(value=p)
5255
+
5256
+ # URL (website redesign)
5257
+ url = _extract_url(seg)
5258
+ if url:
5259
+ upd_url = gr.update(value=url)
5260
+
5261
+ # Model selection
5262
+ if "model " in seg_norm:
5263
+ try:
5264
+ model_name = seg.split("model", 1)[1].strip()
5265
+ except Exception:
5266
+ model_name = ""
5267
+ if model_name:
5268
+ model_obj = _find_model_by_name(model_name)
5269
+ if model_obj is not None:
5270
+ upd_model_dropdown = gr.update(value=model_obj["name"]) # keep dropdown in sync
5271
+ upd_current_model = model_obj # pass directly to State for immediate effect
5272
+
5273
+ # Files: attach first non-image to file_input; image to generation_image_input
5274
+ img_assigned = False
5275
+ non_img_assigned = False
5276
+ for f in files:
5277
+ try:
5278
+ path = f["path"] if isinstance(f, dict) and "path" in f else f
5279
+ except Exception:
5280
+ path = None
5281
+ if not path:
5282
+ continue
5283
+ if not img_assigned and any(str(path).lower().endswith(ext) for ext in [".png", ".jpg", ".jpeg", ".bmp", ".gif", ".webp", ".tiff", ".tif"]):
5284
+ upd_image_for_gen = gr.update(value=path)
5285
+ img_assigned = True
5286
+ elif not non_img_assigned:
5287
+ upd_file = gr.update(value=path)
5288
+ non_img_assigned = True
5289
+
5290
+ # Set main build intent from first segment (if present), otherwise full text
5291
+ if main_prompt:
5292
+ upd_input = gr.update(value=main_prompt)
5293
+
5294
+ # Build assistant acknowledgement
5295
+ ack = "Configured. Running generation with your latest instructions."
5296
+ if not chat_messages:
5297
+ chat_messages = []
5298
+ chat_messages.append({"role": "user", "content": text})
5299
+ chat_messages.append({"role": "assistant", "content": ack})
5300
+
5301
+ return (
5302
+ "",
5303
+ gr.update(value=chat_messages, visible=True),
5304
+ upd_input,
5305
+ upd_language,
5306
+ upd_url,
5307
+ upd_file,
5308
+ upd_image_for_gen,
5309
+ upd_search,
5310
+ upd_img_gen,
5311
+ upd_t2i_prompt,
5312
+ upd_i2i_toggle,
5313
+ upd_i2i_prompt,
5314
+ upd_i2v_toggle,
5315
+ upd_i2v_prompt,
5316
+ upd_t2v_toggle,
5317
+ upd_t2v_prompt,
5318
+ upd_model_dropdown,
5319
+ upd_current_model,
5320
+ )
5321
+
5322
+ # Wire chat submit -> apply settings -> run generation
5323
+ sidebar_msg.submit(
5324
+ apply_chat_command,
5325
+ inputs=[sidebar_msg, sidebar_chatbot],
5326
+ outputs=[
5327
+ sidebar_msg,
5328
+ sidebar_chatbot,
5329
+ input,
5330
+ language_dropdown,
5331
+ website_url_input,
5332
+ file_input,
5333
+ generation_image_input,
5334
+ search_toggle,
5335
+ image_generation_toggle,
5336
+ text_to_image_prompt,
5337
+ image_to_image_toggle,
5338
+ image_to_image_prompt,
5339
+ image_to_video_toggle,
5340
+ image_to_video_prompt,
5341
+ text_to_video_toggle,
5342
+ text_to_video_prompt,
5343
+ model_dropdown,
5344
+ current_model,
5345
+ ],
5346
+ queue=False,
5347
+ ).then(
5348
+ begin_generation_ui,
5349
+ inputs=None,
5350
+ outputs=[sidebar, generating_status],
5351
+ show_progress="hidden",
5352
+ ).then(
5353
+ generation_code,
5354
+ inputs=[input, image_input, generation_image_input, file_input, website_url_input, setting, history, current_model, search_toggle, language_dropdown, provider_state, image_generation_toggle, image_to_image_toggle, image_to_image_prompt, text_to_image_prompt, image_to_video_toggle, image_to_video_prompt, text_to_video_toggle, text_to_video_prompt],
5355
+ outputs=[code_output, history, sandbox, history_output]
5356
+ ).then(
5357
+ end_generation_ui,
5358
+ inputs=None,
5359
+ outputs=[sidebar, generating_status]
5360
+ ).then(
5361
+ show_deploy_components,
5362
+ None,
5363
+ [space_name_input, sdk_dropdown, deploy_btn]
5364
+ ).then(
5365
+ preserve_space_info_for_followup,
5366
+ inputs=[history],
5367
+ outputs=[space_name_input, deploy_btn]
5368
+ )
5369
+
5370
+ # Toggle between classic controls and beta chat UI
5371
+ def toggle_beta(checked: bool, t2i: bool, i2i: bool, i2v: bool, t2v: bool):
5372
+ # Prompts only visible in classic mode and when their toggles are on
5373
+ t2i_vis = (not checked) and bool(t2i)
5374
+ i2i_vis = (not checked) and bool(i2i)
5375
+ i2v_vis = (not checked) and bool(i2v)
5376
+ t2v_vis = (not checked) and bool(t2v)
5377
+
5378
+ return (
5379
+ # Chat UI group
5380
+ gr.update(visible=checked), # sidebar_chatbot
5381
+ gr.update(visible=checked), # sidebar_msg
5382
+ gr.update(visible=checked), # advanced_commands
5383
+ gr.update(visible=checked), # chat_clear_btn
5384
+ # Classic controls
5385
+ gr.update(visible=not checked), # input
5386
+ gr.update(visible=not checked), # language_dropdown
5387
+ gr.update(visible=not checked), # website_url_input
5388
+ gr.update(visible=not checked), # file_input
5389
+ gr.update(visible=not checked), # btn
5390
+ gr.update(visible=not checked), # clear_btn
5391
+ gr.update(visible=not checked), # search_toggle
5392
+ gr.update(visible=not checked), # image_generation_toggle
5393
+ gr.update(visible=t2i_vis), # text_to_image_prompt
5394
+ gr.update(visible=not checked), # image_to_image_toggle
5395
+ gr.update(visible=i2i_vis), # image_to_image_prompt
5396
+ gr.update(visible=not checked), # image_to_video_toggle
5397
+ gr.update(visible=i2v_vis), # image_to_video_prompt
5398
+ gr.update(visible=not checked), # text_to_video_toggle
5399
+ gr.update(visible=t2v_vis), # text_to_video_prompt
5400
+ gr.update(visible=not checked), # model_dropdown
5401
+ gr.update(visible=not checked), # quick_start_md
5402
+ gr.update(visible=not checked), # quick_examples_col
5403
+ )
5404
+
5405
+ beta_toggle.change(
5406
+ toggle_beta,
5407
+ inputs=[beta_toggle, image_generation_toggle, image_to_image_toggle, image_to_video_toggle, text_to_video_toggle],
5408
+ outputs=[
5409
+ sidebar_chatbot,
5410
+ sidebar_msg,
5411
+ advanced_commands,
5412
+ chat_clear_btn,
5413
+ input,
5414
+ language_dropdown,
5415
+ website_url_input,
5416
+ file_input,
5417
+ btn,
5418
+ clear_btn,
5419
+ search_toggle,
5420
+ image_generation_toggle,
5421
+ text_to_image_prompt,
5422
+ image_to_image_toggle,
5423
+ image_to_image_prompt,
5424
+ image_to_video_toggle,
5425
+ image_to_video_prompt,
5426
+ text_to_video_toggle,
5427
+ text_to_video_prompt,
5428
+ model_dropdown,
5429
+ quick_start_md,
5430
+ quick_examples_col,
5431
+ ],
5432
+ )
5433
  # Update preview when code or language changes
5434
  code_output.change(preview_logic, inputs=[code_output, language_dropdown], outputs=sandbox)
5435
  language_dropdown.change(preview_logic, inputs=[code_output, language_dropdown], outputs=sandbox)