Lilli98 commited on
Commit
4ecc417
·
verified ·
1 Parent(s): 2dd72e3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +32 -14
app.py CHANGED
@@ -1,5 +1,5 @@
1
  # app.py
2
- # @title Beer Game Final Version (Verbatim Restore with Manual Settings)
3
 
4
  # -----------------------------------------------------------------------------
5
  # 1. Import Libraries
@@ -129,7 +129,7 @@ def init_game_state(llm_personality: str, info_sharing: str, participant_id: str
129
  'incoming_order': 0, 'order_placed': 0, 'shipment_sent': 0,
130
  'weekly_cost': 0, 'total_cost': 0, 'upstream_name': upstream, 'downstream_name': downstream,
131
  }
132
- st.info(f"New game started for **{participant_id}**! You are the **{human_role}**.")
133
 
134
  def get_llm_order_decision(prompt: str, echelon_name: str) -> (int, str):
135
  if not client: return 8, "NO_API_KEY_DEFAULT"
@@ -331,7 +331,7 @@ def plot_results(df: pd.DataFrame, title: str, human_role: str):
331
  inventory_pivot = plot_df.pivot(index='week', columns='echelon', values='inventory').reindex(columns=echelons)
332
  inventory_pivot.plot(ax=axes[0], kind='line', marker='o', markersize=4); axes[0].set_title('Inventory Levels (End of Week)'); axes[0].grid(True, linestyle='--'); axes[0].set_ylabel('Stock (Units)')
333
  order_pivot = plot_df.pivot(index='week', columns='echelon', values='order_placed').reindex(columns=echelons)
334
- order_pivot.plot(ax=axes[1], style='--'); axes[1].plot(range(1, WEEKS + 1), [get_customer_demand(week) for week in range(1, WEEKS + 1)], label='Customer Demand', color='black', lw=2.5); axes[1].set_title('Order Quantities / Production Decisions'); axes[1].grid(True, linestyle='--'); axes[1].legend(); axes[1].set_ylabel('Ordered/Produced (Units)')
335
  total_costs = plot_df.loc[plot_df.groupby('echelon')['week'].idxmax()]
336
  total_costs = total_costs.set_index('echelon')['total_cost'].reindex(echelons, fill_value=0)
337
  total_costs.plot(kind='bar', ax=axes[2], rot=0); axes[2].set_title('Total Cumulative Cost'); axes[2].set_ylabel('Cost ($)')
@@ -485,13 +485,23 @@ if 'comprehension_passed' not in st.session_state: st.session_state['comprehensi
485
 
486
  if st.session_state.get('initialization_error'):
487
  st.error(st.session_state.initialization_error)
 
488
  elif not st.session_state['consent_given']:
489
  st.header("📝 Participant Consent Form")
490
- st.markdown("""**Lead Researcher:** Xinyu Li...""") # (Long text same as before)
 
 
 
 
 
 
 
 
 
491
  with st.form("consent_form"):
492
- consent_choice = st.radio("**Do you agree?**", ('Yes', 'No'), index=None)
493
  if st.form_submit_button("Continue"):
494
- if consent_choice == 'Yes':
495
  st.session_state['consent_given'] = True
496
  st.session_state['consent_timestamp'] = datetime.utcnow().isoformat() + "Z"
497
  st.rerun()
@@ -503,13 +513,16 @@ elif not st.session_state['comprehension_passed']:
503
  user_answers = {}
504
  for i, q_data in enumerate(COMPREHENSION_QUESTIONS):
505
  st.subheader(q_data['q'])
506
- user_answers[i] = st.radio("Select:", q_data['options'], key=f"comp_q_{i}", index=None)
 
507
  if st.form_submit_button("Submit Answers"):
508
  all_correct = True
509
  for i, q_data in enumerate(COMPREHENSION_QUESTIONS):
510
  if user_answers.get(i) != q_data['options'][q_data['correct_index']]:
511
  all_correct = False
512
- if all_correct: st.session_state['comprehension_passed'] = True; st.rerun()
 
 
513
  else: st.error("Incorrect answers.")
514
 
515
  else:
@@ -522,7 +535,8 @@ else:
522
  state = st.session_state.game_state
523
  participant_id = state['participant_id']
524
  url = f"{QUALTRICS_BASE_URL}?{PID_FIELD_NAME}={participant_id}"
525
- st.markdown(f'<a href="{url}" target="_blank"><button style="...">Click Start Survey</button></a>', unsafe_allow_html=True)
 
526
  try:
527
  logs_df = pd.json_normalize(state['logs'])
528
  st.pyplot(plot_results(logs_df, f"Beer Game (Human: {state['human_role']})", state['human_role']))
@@ -557,10 +571,9 @@ else:
557
  c1, c2, c3 = st.columns(3)
558
  with c1: st.metric("Inventory", e['inventory']); st.metric("Backlog", e['backlog'])
559
  with c2: st.write(f"**Incoming Order:**\n# {e['incoming_order']}")
560
- with c3: st.write(f"**Arriving Next:**\n# {list(e['incoming_shipments'])[0] if e['incoming_shipments'] else 0}")
561
 
562
  st.markdown("---")
563
- st.header("Your Decision")
564
  if state['decision_step'] == 'initial_order':
565
  with st.form(key="initial_order_form"):
566
  initial_order = st.number_input("Your Initial Order Quantity:", min_value=0, step=1, value=None)
@@ -581,11 +594,16 @@ else:
581
  step_game(int(final_order) if final_order is not None else 0, state['human_initial_order'], ai_suggestion)
582
  st.rerun()
583
 
 
 
 
 
 
584
  else:
585
  st.header("⚙️ Game Configuration")
586
  participant_id = st.text_input("Enter Your Name or Team ID:", key="participant_id_input")
587
 
588
- # --- 恢复手动选择配置 ---
589
  c1, c2 = st.columns(2)
590
  with c1:
591
  llm_personality = st.selectbox("AI Agent Personality", ('human_like', 'perfect_rational'), format_func=lambda x: x.replace('_', ' ').title())
@@ -596,11 +614,11 @@ else:
596
  if participant_id:
597
  init_game_state(llm_personality, info_sharing, participant_id)
598
  st.rerun()
599
- else: st.error("Please enter an ID.")
600
  show_leaderboard_ui()
601
 
602
  # --- Instructor Zone ---
603
  st.sidebar.markdown("---")
604
  with st.sidebar.expander("🔐 Instructor Zone"):
605
- if st.text_input("Admin Password:", type="password") == ADMIN_PASSWORD:
606
  if st.checkbox("Show Global Leaderboard"): show_leaderboard_ui()
 
1
  # app.py
2
+ # @title Beer Game Final Version (v4.27 - STRICT VERBATIM RESTORE - MANUAL SELECTION)
3
 
4
  # -----------------------------------------------------------------------------
5
  # 1. Import Libraries
 
129
  'incoming_order': 0, 'order_placed': 0, 'shipment_sent': 0,
130
  'weekly_cost': 0, 'total_cost': 0, 'upstream_name': upstream, 'downstream_name': downstream,
131
  }
132
+ st.info(f"New game started for **{participant_id}**! AI Mode: **{llm_personality} / {info_sharing}**. You are the **{human_role}**.")
133
 
134
  def get_llm_order_decision(prompt: str, echelon_name: str) -> (int, str):
135
  if not client: return 8, "NO_API_KEY_DEFAULT"
 
331
  inventory_pivot = plot_df.pivot(index='week', columns='echelon', values='inventory').reindex(columns=echelons)
332
  inventory_pivot.plot(ax=axes[0], kind='line', marker='o', markersize=4); axes[0].set_title('Inventory Levels (End of Week)'); axes[0].grid(True, linestyle='--'); axes[0].set_ylabel('Stock (Units)')
333
  order_pivot = plot_df.pivot(index='week', columns='echelon', values='order_placed').reindex(columns=echelons)
334
+ order_pivot.plot(ax=axes[1], style='--'); axes[1].plot(range(1, WEEKS + 1), [get_customer_demand(w) for w in range(1, WEEKS + 1)], label='Customer Demand', color='black', lw=2.5); axes[1].set_title('Order Quantities / Production Decisions'); axes[1].grid(True, linestyle='--'); axes[1].legend(); axes[1].set_ylabel('Ordered/Produced (Units)')
335
  total_costs = plot_df.loc[plot_df.groupby('echelon')['week'].idxmax()]
336
  total_costs = total_costs.set_index('echelon')['total_cost'].reindex(echelons, fill_value=0)
337
  total_costs.plot(kind='bar', ax=axes[2], rot=0); axes[2].set_title('Total Cumulative Cost'); axes[2].set_ylabel('Cost ($)')
 
485
 
486
  if st.session_state.get('initialization_error'):
487
  st.error(st.session_state.initialization_error)
488
+
489
  elif not st.session_state['consent_given']:
490
  st.header("📝 Participant Consent Form")
491
+ st.markdown("""
492
+ **Lead Researcher:** Xinyu Li
493
+ **Supervisor:** Professor Li Ding & Dr Yanlu Zhao
494
+ **Contact Email:** xinyu.li3@durham.ac.uk
495
+
496
+ Please read the following statements carefully. By agreeing to participate, you are confirming that you understand all of the following:
497
+ - Your participation is voluntary.
498
+ - Your participation is anonymous.
499
+ - You confirm that you are **18 years of age or older**.
500
+ """)
501
  with st.form("consent_form"):
502
+ choice = st.radio("**Do you agree to take part in this study?**", ('Yes, I agree to participate in this study.', 'No, I do not agree to participate in this study.'), index=None)
503
  if st.form_submit_button("Continue"):
504
+ if choice == 'Yes, I agree to participate in this study.':
505
  st.session_state['consent_given'] = True
506
  st.session_state['consent_timestamp'] = datetime.utcnow().isoformat() + "Z"
507
  st.rerun()
 
513
  user_answers = {}
514
  for i, q_data in enumerate(COMPREHENSION_QUESTIONS):
515
  st.subheader(q_data['q'])
516
+ user_answers[i] = st.radio("Select an option:", q_data['options'], key=f"comp_q_{i}", index=None, label_visibility="collapsed")
517
+ st.markdown("---")
518
  if st.form_submit_button("Submit Answers"):
519
  all_correct = True
520
  for i, q_data in enumerate(COMPREHENSION_QUESTIONS):
521
  if user_answers.get(i) != q_data['options'][q_data['correct_index']]:
522
  all_correct = False
523
+ if all_correct:
524
+ st.session_state['comprehension_passed'] = True
525
+ st.rerun()
526
  else: st.error("Incorrect answers.")
527
 
528
  else:
 
535
  state = st.session_state.game_state
536
  participant_id = state['participant_id']
537
  url = f"{QUALTRICS_BASE_URL}?{PID_FIELD_NAME}={participant_id}"
538
+ st.warning(f"Your ID: **{participant_id}**. Please click below to start the survey.")
539
+ st.markdown(f'<a href="{url}" target="_blank"><button style="background-color: #4CAF50; color: white; padding: 15px 32px; font-size: 16px; cursor: pointer; border: none; border-radius: 8px;">Click Here to Start the Survey</button></a>', unsafe_allow_html=True)
540
  try:
541
  logs_df = pd.json_normalize(state['logs'])
542
  st.pyplot(plot_results(logs_df, f"Beer Game (Human: {state['human_role']})", state['human_role']))
 
571
  c1, c2, c3 = st.columns(3)
572
  with c1: st.metric("Inventory", e['inventory']); st.metric("Backlog", e['backlog'])
573
  with c2: st.write(f"**Incoming Order:**\n# {e['incoming_order']}")
574
+ with c3: st.write(f"**Shipment Arriving Next:**\n# {list(e['incoming_shipments'])[0] if e['incoming_shipments'] else 0}")
575
 
576
  st.markdown("---")
 
577
  if state['decision_step'] == 'initial_order':
578
  with st.form(key="initial_order_form"):
579
  initial_order = st.number_input("Your Initial Order Quantity:", min_value=0, step=1, value=None)
 
594
  step_game(int(final_order) if final_order is not None else 0, state['human_initial_order'], ai_suggestion)
595
  st.rerun()
596
 
597
+ if Path(IMAGE_PATH).exists(): st.sidebar.image(IMAGE_PATH, use_column_width=True)
598
+ if st.sidebar.button("🔄 Reset Game"):
599
+ if 'game_state' in st.session_state: del st.session_state.game_state
600
+ st.rerun()
601
+
602
  else:
603
  st.header("⚙️ Game Configuration")
604
  participant_id = st.text_input("Enter Your Name or Team ID:", key="participant_id_input")
605
 
606
+ # --- MANUAL SELECTION ADDED BACK ---
607
  c1, c2 = st.columns(2)
608
  with c1:
609
  llm_personality = st.selectbox("AI Agent Personality", ('human_like', 'perfect_rational'), format_func=lambda x: x.replace('_', ' ').title())
 
614
  if participant_id:
615
  init_game_state(llm_personality, info_sharing, participant_id)
616
  st.rerun()
617
+ else: st.error("Please enter a Name or Team ID.")
618
  show_leaderboard_ui()
619
 
620
  # --- Instructor Zone ---
621
  st.sidebar.markdown("---")
622
  with st.sidebar.expander("🔐 Instructor Zone"):
623
+ if st.text_input("Admin Password:", type="password", key="admin_pwd") == ADMIN_PASSWORD:
624
  if st.checkbox("Show Global Leaderboard"): show_leaderboard_ui()