Justxd22 commited on
Commit
ee54069
Β·
1 Parent(s): 24a62ed

Update TODO and enhance game UI with tool showcase and video demo

Browse files
Files changed (2) hide show
  1. TODO.md +5 -4
  2. app.py +95 -2
TODO.md CHANGED
@@ -11,11 +11,12 @@
11
  - add ai
12
  - mode selection
13
  - numbered steps to launch game
 
 
 
14
 
15
 
16
- # Doing
17
 
 
 
18
  - sound/music
19
- - video embeded
20
- - divider
21
- - mcp showcase with title "try tools without playing"
 
11
  - add ai
12
  - mode selection
13
  - numbered steps to launch game
14
+ - video embeded
15
+ - divider
16
+ - mcp showcase with title "try tools without playing"
17
 
18
 
 
19
 
20
+ # Doing
21
+ - README
22
  - sound/music
 
 
 
app.py CHANGED
@@ -434,11 +434,19 @@ def start_game_from_ui(case_name, mode, voice):
434
 
435
  init_data = session.start(difficulty, mode_slug, voice)
436
 
 
 
 
 
 
437
  # Return visible updates
438
  return (
439
  gr.update(visible=False), # Hide selector row
440
  gr.update(visible=True), # Show game frame
441
- json.dumps(init_data) # Send init data to bridge
 
 
 
442
  )
443
 
444
  css = """
@@ -505,11 +513,96 @@ with gr.Blocks(title="Murder.Ai", fill_height=True) as demo:
505
 
506
  auto_refresh.change(fn=toggle_timer, inputs=auto_refresh, outputs=log_timer)
507
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
508
  # Start Game Event
509
  start_btn.click(
510
  fn=start_game_from_ui,
511
  inputs=[case_dropdown, game_mode, voice_toggle],
512
- outputs=[setup_col, game_group, bridge_output]
513
  )
514
 
515
  # Bridge Logic with Logging (Legacy/Fallback)
 
434
 
435
  init_data = session.start(difficulty, mode_slug, voice)
436
 
437
+ # Extract data for tools
438
+ phones = [s["phone_number"] for s in init_data["data"]["scenario"]["suspects"]]
439
+ cameras = init_data["data"]["available_cameras"]
440
+ suspects = [s["name"] for s in init_data["data"]["scenario"]["suspects"]]
441
+
442
  # Return visible updates
443
  return (
444
  gr.update(visible=False), # Hide selector row
445
  gr.update(visible=True), # Show game frame
446
+ json.dumps(init_data), # Send init data to bridge
447
+ gr.update(choices=phones, value=phones[0] if phones else None),
448
+ gr.update(choices=cameras, value=cameras[0] if cameras else None),
449
+ gr.update(choices=suspects, value=suspects[0] if suspects else None)
450
  )
451
 
452
  css = """
 
513
 
514
  auto_refresh.change(fn=toggle_timer, inputs=auto_refresh, outputs=log_timer)
515
 
516
+ # --- Footer / Showcase ---
517
+ gr.Markdown("---")
518
+ gr.Markdown("### πŸŽ₯ How to Play (Demo)")
519
+ gr.HTML('<iframe width="100%" height="400" src="https://www.youtube.com/embed/dQw4w9WgXcQ" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>')
520
+
521
+ gr.Markdown("# πŸ› οΈ Try MCP Tools Directly")
522
+ gr.Markdown("*Note: Start a game first to populate these tools.*")
523
+
524
+ with gr.Tabs():
525
+ with gr.Tab("πŸ“ Location"):
526
+ loc_phone = gr.Radio(label="Select Phone Number", choices=[], interactive=True)
527
+ loc_btn = gr.Button("Get Location")
528
+ loc_out = gr.JSON(label="Result")
529
+
530
+ with gr.Tab("πŸ“Ή Footage"):
531
+ foot_cam = gr.Radio(label="Select Camera", choices=[], interactive=True)
532
+ foot_btn = gr.Button("Get Footage")
533
+ foot_out = gr.JSON(label="Result")
534
+
535
+ with gr.Tab("🧬 DNA"):
536
+ dna_id = gr.Textbox(label="Evidence ID")
537
+ dna_btn = gr.Button("Test DNA")
538
+ dna_out = gr.JSON(label="Result")
539
+
540
+ with gr.Tab("πŸ“ž Alibi"):
541
+ alibi_id = gr.Textbox(label="Alibi ID")
542
+ alibi_q = gr.Textbox(label="Question", value="Where were they?")
543
+ alibi_btn = gr.Button("Call Alibi")
544
+ alibi_out = gr.JSON(label="Result")
545
+
546
+ with gr.Tab("πŸ’¬ Interrogate"):
547
+ int_suspect = gr.Radio(label="Select Suspect", choices=[], interactive=True)
548
+ int_q = gr.Textbox(label="Question", value="Where were you?")
549
+ int_btn = gr.Button("Interrogate")
550
+ int_out_text = gr.Markdown(label="Response")
551
+ int_out_audio = gr.Audio(label="Voice Response", autoplay=True)
552
+
553
+ # --- Event Handlers for Tools ---
554
+
555
+ def wrap_tool(tool_name, *args):
556
+ if not session.game: return {"error": "Start game first"}
557
+
558
+ kwargs = {}
559
+ if tool_name == "get_location": kwargs = {"phone_number": args[0]}
560
+ elif tool_name == "get_footage": kwargs = {"location": args[0]}
561
+ elif tool_name == "get_dna_test": kwargs = {"evidence_id": args[0]}
562
+ elif tool_name == "call_alibi": kwargs = {"alibi_id": args[0], "question": args[1]}
563
+
564
+ return session.game.use_tool(tool_name, **kwargs)
565
+
566
+ loc_btn.click(lambda p: wrap_tool("get_location", p), inputs=loc_phone, outputs=loc_out)
567
+ foot_btn.click(lambda c: wrap_tool("get_footage", c), inputs=foot_cam, outputs=foot_out)
568
+ dna_btn.click(lambda e: wrap_tool("get_dna_test", e), inputs=dna_id, outputs=dna_out)
569
+ alibi_btn.click(lambda i, q: wrap_tool("call_alibi", i, q), inputs=[alibi_id, alibi_q], outputs=alibi_out)
570
+
571
+ def wrap_chat(suspect_name, question):
572
+ if not session.game: return "Start game first", None
573
+ # Find ID from name
574
+ s_id = next((s["id"] for s in session.game.scenario["suspects"] if s["name"] == suspect_name), None)
575
+ if not s_id: return "Suspect not found", None
576
+
577
+ resp = session.game.question_suspect(s_id, question)
578
+
579
+ # Audio
580
+ audio_path = None
581
+ suspect = next((s for s in session.game.scenario["suspects"] if s["id"] == s_id), None)
582
+
583
+ # Clean text
584
+ cleaned = resp
585
+ if cleaned.strip().startswith('(') and ')' in cleaned:
586
+ cleaned = cleaned[cleaned.find(')')+1:].strip()
587
+ cleaned = cleaned.replace('*', '').strip()
588
+
589
+ if suspect and "voice_id" in suspect and cleaned:
590
+ audio_bytes = session.game.voice_manager.generate_audio(cleaned, suspect["voice_id"])
591
+ if audio_bytes:
592
+ import tempfile
593
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as fp:
594
+ fp.write(audio_bytes)
595
+ audio_path = fp.name
596
+
597
+ return resp, audio_path
598
+
599
+ int_btn.click(wrap_chat, inputs=[int_suspect, int_q], outputs=[int_out_text, int_out_audio])
600
+
601
  # Start Game Event
602
  start_btn.click(
603
  fn=start_game_from_ui,
604
  inputs=[case_dropdown, game_mode, voice_toggle],
605
+ outputs=[setup_col, game_group, bridge_output, loc_phone, foot_cam, int_suspect]
606
  )
607
 
608
  # Bridge Logic with Logging (Legacy/Fallback)