Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -46,7 +46,7 @@ LOCAL_LOG_DIR.mkdir(exist_ok=True)
|
|
| 46 |
IMAGE_PATH = "beer_game_diagram.png"
|
| 47 |
LEADERBOARD_FILE = "leaderboard.json"
|
| 48 |
|
| 49 |
-
#
|
| 50 |
EXPERIMENT_SETTINGS = [
|
| 51 |
('human_like', 'local'),
|
| 52 |
('human_like', 'full'),
|
|
@@ -55,7 +55,6 @@ EXPERIMENT_SETTINGS = [
|
|
| 55 |
]
|
| 56 |
# --- API & Secrets Configuration ---
|
| 57 |
try:
|
| 58 |
-
# 注意:在多Space部署中,每个Space的secrets中只放一个API KEY
|
| 59 |
client = openai.OpenAI(api_key=st.secrets["OPENAI_API_KEY"])
|
| 60 |
HF_TOKEN = st.secrets.get("HF_TOKEN")
|
| 61 |
HF_REPO_ID = st.secrets.get("HF_REPO_ID")
|
|
@@ -105,7 +104,6 @@ def init_game_state(llm_personality: str, info_sharing: str, participant_id: str
|
|
| 105 |
# ==============================================================================
|
| 106 |
def get_llm_order_decision(prompt: str, echelon_name: str) -> (int, str):
|
| 107 |
# This function remains correct.
|
| 108 |
-
# 注意:client 现在是全局的,所有用户的API请求都通过它进行。
|
| 109 |
if not client: return 8, "NO_API_KEY_DEFAULT"
|
| 110 |
with st.spinner(f"Getting AI decision for {echelon_name}..."):
|
| 111 |
try:
|
|
@@ -541,7 +539,6 @@ def save_logs_and_upload(state: dict):
|
|
| 541 |
logs_df = pd.json_normalize(state['logs'])
|
| 542 |
safe_participant_id = re.sub(r'[^a-zA-Z0-9_-]', '_', participant_id)
|
| 543 |
fname = LOCAL_LOG_DIR / f"log_{safe_participant_id}_{int(time.time())}.csv"
|
| 544 |
-
# [修改点 4]: 在 logs_df 中添加实验结束时间戳和同意时间戳
|
| 545 |
logs_df['experiment_end_timestamp'] = datetime.utcnow().isoformat() + "Z"
|
| 546 |
if st.session_state.get('consent_timestamp'):
|
| 547 |
logs_df['consent_given_timestamp'] = st.session_state['consent_timestamp']
|
|
@@ -605,6 +602,11 @@ def save_logs_and_upload(state: dict):
|
|
| 605 |
# -----------------------------------------------------------------------------
|
| 606 |
# 4. Streamlit UI (Applying v4.22 + v4.23 fixes)
|
| 607 |
# -----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 608 |
st.title("🍺 The Beer Game: A Human-AI Collaboration Challenge")
|
| 609 |
|
| 610 |
# --- NEW: Check for Consent ---
|
|
@@ -653,7 +655,6 @@ elif not st.session_state['consent_given']:
|
|
| 653 |
key='consent_radio'
|
| 654 |
)
|
| 655 |
submit_button = st.form_submit_button("Continue")
|
| 656 |
-
|
| 657 |
if submit_button:
|
| 658 |
if consent_choice == 'Yes, I agree to participate in this study.':
|
| 659 |
# [修正点 2]: 记录时间戳并允许进入
|
|
@@ -688,15 +689,6 @@ else:
|
|
| 688 |
else:
|
| 689 |
# 默认值,如果未输入ID
|
| 690 |
llm_personality, info_sharing = ('human_like', 'local')
|
| 691 |
-
|
| 692 |
-
# [修改点 2.2]: 移除启动时显示实验条件的提示
|
| 693 |
-
# st.info(f"You will be automatically assigned to the condition: **{llm_personality.replace('_', ' ').title()} / {info_sharing.title()}**.")
|
| 694 |
-
# =================================================================
|
| 695 |
-
|
| 696 |
-
# 移除原有的 c1, c2 和 selectbox
|
| 697 |
-
# c1, c2 = st.columns(2)
|
| 698 |
-
# with c1:
|
| 699 |
-
# with c2:
|
| 700 |
|
| 701 |
# =============== MODIFIED: Start Game Button ===============
|
| 702 |
if st.button("🚀 Start Game", type="primary", disabled=(client is None)):
|
|
@@ -731,12 +723,7 @@ else:
|
|
| 731 |
week, human_role, echelons, info_sharing = state['week'], state['human_role'], state['echelons'], state['info_sharing']
|
| 732 |
echelon_order = ["Retailer", "Wholesaler", "Distributor", "Factory"] # Define here for UI
|
| 733 |
|
| 734 |
-
# [修改点 1.1]: 移除 st.columns,恢复主内容到左侧,侧边栏不变
|
| 735 |
-
# col_main, col_sidebar_image = st.columns([4, 1]) 移除
|
| 736 |
-
|
| 737 |
-
# with col_main: 移除
|
| 738 |
st.header(f"Week {week} / {WEEKS}")
|
| 739 |
-
# [修改点 2.3]: 移除 subheader 中 AI Mode 和 Information 的提示
|
| 740 |
st.subheader(f"Your Role: **{human_role}** ({state['participant_id']})")
|
| 741 |
st.markdown("---")
|
| 742 |
st.subheader("Supply Chain Status (Start of Week State)")
|
|
@@ -900,6 +887,30 @@ else:
|
|
| 900 |
if 'game_state' in st.session_state and not st.session_state.game_state.get('game_running', False) and st.session_state.game_state['week'] > WEEKS:
|
| 901 |
st.header("🎉 Game Over!")
|
| 902 |
state = st.session_state.game_state
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 903 |
try:
|
| 904 |
logs_df = pd.json_normalize(state['logs'])
|
| 905 |
fig = plot_results(
|
|
|
|
| 46 |
IMAGE_PATH = "beer_game_diagram.png"
|
| 47 |
LEADERBOARD_FILE = "leaderboard.json"
|
| 48 |
|
| 49 |
+
# ------
|
| 50 |
EXPERIMENT_SETTINGS = [
|
| 51 |
('human_like', 'local'),
|
| 52 |
('human_like', 'full'),
|
|
|
|
| 55 |
]
|
| 56 |
# --- API & Secrets Configuration ---
|
| 57 |
try:
|
|
|
|
| 58 |
client = openai.OpenAI(api_key=st.secrets["OPENAI_API_KEY"])
|
| 59 |
HF_TOKEN = st.secrets.get("HF_TOKEN")
|
| 60 |
HF_REPO_ID = st.secrets.get("HF_REPO_ID")
|
|
|
|
| 104 |
# ==============================================================================
|
| 105 |
def get_llm_order_decision(prompt: str, echelon_name: str) -> (int, str):
|
| 106 |
# This function remains correct.
|
|
|
|
| 107 |
if not client: return 8, "NO_API_KEY_DEFAULT"
|
| 108 |
with st.spinner(f"Getting AI decision for {echelon_name}..."):
|
| 109 |
try:
|
|
|
|
| 539 |
logs_df = pd.json_normalize(state['logs'])
|
| 540 |
safe_participant_id = re.sub(r'[^a-zA-Z0-9_-]', '_', participant_id)
|
| 541 |
fname = LOCAL_LOG_DIR / f"log_{safe_participant_id}_{int(time.time())}.csv"
|
|
|
|
| 542 |
logs_df['experiment_end_timestamp'] = datetime.utcnow().isoformat() + "Z"
|
| 543 |
if st.session_state.get('consent_timestamp'):
|
| 544 |
logs_df['consent_given_timestamp'] = st.session_state['consent_timestamp']
|
|
|
|
| 602 |
# -----------------------------------------------------------------------------
|
| 603 |
# 4. Streamlit UI (Applying v4.22 + v4.23 fixes)
|
| 604 |
# -----------------------------------------------------------------------------
|
| 605 |
+
# --- Qualtrics Configuration ---
|
| 606 |
+
QUALTRICS_BASE_URL = "https://durhambs.az1.qualtrics.com/jfe/form/SV_2sqnVhOUrNdaG3k"
|
| 607 |
+
PID_FIELD_NAME = "PID" # 必须与 Qualtrics Embedded Data 字段名一致
|
| 608 |
+
# -------------------------------
|
| 609 |
+
|
| 610 |
st.title("🍺 The Beer Game: A Human-AI Collaboration Challenge")
|
| 611 |
|
| 612 |
# --- NEW: Check for Consent ---
|
|
|
|
| 655 |
key='consent_radio'
|
| 656 |
)
|
| 657 |
submit_button = st.form_submit_button("Continue")
|
|
|
|
| 658 |
if submit_button:
|
| 659 |
if consent_choice == 'Yes, I agree to participate in this study.':
|
| 660 |
# [修正点 2]: 记录时间戳并允许进入
|
|
|
|
| 689 |
else:
|
| 690 |
# 默认值,如果未输入ID
|
| 691 |
llm_personality, info_sharing = ('human_like', 'local')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 692 |
|
| 693 |
# =============== MODIFIED: Start Game Button ===============
|
| 694 |
if st.button("🚀 Start Game", type="primary", disabled=(client is None)):
|
|
|
|
| 723 |
week, human_role, echelons, info_sharing = state['week'], state['human_role'], state['echelons'], state['info_sharing']
|
| 724 |
echelon_order = ["Retailer", "Wholesaler", "Distributor", "Factory"] # Define here for UI
|
| 725 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 726 |
st.header(f"Week {week} / {WEEKS}")
|
|
|
|
| 727 |
st.subheader(f"Your Role: **{human_role}** ({state['participant_id']})")
|
| 728 |
st.markdown("---")
|
| 729 |
st.subheader("Supply Chain Status (Start of Week State)")
|
|
|
|
| 887 |
if 'game_state' in st.session_state and not st.session_state.game_state.get('game_running', False) and st.session_state.game_state['week'] > WEEKS:
|
| 888 |
st.header("🎉 Game Over!")
|
| 889 |
state = st.session_state.game_state
|
| 890 |
+
participant_id = state['participant_id'] # 获取ID
|
| 891 |
+
|
| 892 |
+
# --------------------------------------------------------------------------
|
| 893 |
+
# [新增部分]: 问卷链接生成
|
| 894 |
+
personalized_survey_url = f"{QUALTRICS_BASE_URL}?{PID_FIELD_NAME}={participant_id}"
|
| 895 |
+
|
| 896 |
+
st.markdown("---")
|
| 897 |
+
st.header("📋 Experiment Wrap-up: Please Complete the Survey")
|
| 898 |
+
st.warning(f"Your Experiment ID is: **{participant_id}**. Please click the link below to complete the final survey. **This survey will automatically link to your experiment data.**")
|
| 899 |
+
|
| 900 |
+
st.markdown(
|
| 901 |
+
f"""
|
| 902 |
+
<a href="{personalized_survey_url}" target="_blank">
|
| 903 |
+
<button style="background-color: #4CAF50; color: white; padding: 15px 32px; text-align: center; text-decoration: none; display: inline-block; font-size: 16px; margin: 4px 2px; cursor: pointer; border: none; border-radius: 8px;">
|
| 904 |
+
Click Here to Start the Survey
|
| 905 |
+
</button>
|
| 906 |
+
</a>
|
| 907 |
+
""",
|
| 908 |
+
unsafe_allow_html=True
|
| 909 |
+
)
|
| 910 |
+
|
| 911 |
+
st.markdown("---")
|
| 912 |
+
# --------------------------------------------------------------------------
|
| 913 |
+
|
| 914 |
try:
|
| 915 |
logs_df = pd.json_normalize(state['logs'])
|
| 916 |
fig = plot_results(
|