Spaces:
Paused
Paused
init
Browse files- .gitignore +3 -0
- README.md +5 -4
- app.py +191 -0
- dialogs/gemini-2.5-flash/primary/hospital_00_agent_dialog.json +0 -0
- dialogs/gemini-2.5-flash/primary/hospital_01_agent_dialog.json +0 -0
- dialogs/gemini-2.5-flash/primary/hospital_02_agent_dialog.json +0 -0
- dialogs/gemini-2.5-flash/secondary/hospital_0_agent_dialog.json +0 -0
- dialogs/gemini-2.5-flash/secondary/hospital_1_agent_dialog.json +0 -0
- dialogs/gemini-2.5-flash/secondary/hospital_2_agent_dialog.json +0 -0
- dialogs/gpt-5-mini/primary/hospital_00_agent_dialog.json +0 -0
- dialogs/gpt-5-mini/primary/hospital_01_agent_dialog.json +0 -0
- dialogs/gpt-5-mini/primary/hospital_02_agent_dialog.json +0 -0
- dialogs/gpt-5-mini/secondary/hospital_0_agent_dialog.json +0 -0
- dialogs/gpt-5-mini/secondary/hospital_1_agent_dialog.json +0 -0
- dialogs/gpt-5-mini/secondary/hospital_2_agent_dialog.json +0 -0
- dialogs/gpt-5-nano/primary/hospital_00_agent_dialog.json +0 -0
- dialogs/gpt-5-nano/primary/hospital_01_agent_dialog.json +0 -0
- dialogs/gpt-5-nano/primary/hospital_02_agent_dialog.json +0 -0
- dialogs/gpt-5-nano/sencondary/hospital_0_agent_dialog.json +0 -0
- dialogs/gpt-5-nano/sencondary/hospital_1_agent_dialog.json +0 -0
- dialogs/gpt-5-nano/sencondary/hospital_2_agent_dialog.json +0 -0
- requirements.txt +3 -0
- utils/__init__.py +127 -0
- utils/common.py +25 -0
- utils/filesys_utils.py +45 -0
- utils/postprocess.py +71 -0
- version.txt +1 -0
.gitignore
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
__pycache__/
|
| 2 |
+
simulation_arena/
|
| 3 |
+
.env
|
README.md
CHANGED
|
@@ -1,13 +1,14 @@
|
|
| 1 |
---
|
| 2 |
-
title: Adminsim
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
sdk: gradio
|
| 7 |
sdk_version: 5.49.1
|
| 8 |
app_file: app.py
|
| 9 |
pinned: false
|
| 10 |
license: apache-2.0
|
|
|
|
| 11 |
---
|
| 12 |
|
| 13 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
| 1 |
---
|
| 2 |
+
title: Adminsim-arena
|
| 3 |
+
emoji: 🏟️
|
| 4 |
+
colorFrom: yellow
|
| 5 |
+
colorTo: red
|
| 6 |
sdk: gradio
|
| 7 |
sdk_version: 5.49.1
|
| 8 |
app_file: app.py
|
| 9 |
pinned: false
|
| 10 |
license: apache-2.0
|
| 11 |
+
short_description: ' Model simulation arena'
|
| 12 |
---
|
| 13 |
|
| 14 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
app.py
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import random
|
| 3 |
+
import datetime
|
| 4 |
+
import gradio as gr
|
| 5 |
+
from typing import Tuple, Optional
|
| 6 |
+
|
| 7 |
+
from utils import log
|
| 8 |
+
from utils.common import upload_to_github
|
| 9 |
+
from utils.postprocess import make_dialog_dict
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def sample_pair(dialog_dict: dict) -> Tuple[str, str, str, str]:
|
| 14 |
+
"""
|
| 15 |
+
Sample two different models and one dialog from each.
|
| 16 |
+
|
| 17 |
+
Args:
|
| 18 |
+
dialog_dict (dict): Dictionary of dialogs per model.
|
| 19 |
+
|
| 20 |
+
Returns:
|
| 21 |
+
Tuple[str, str, str, str]: (model1 name, dialog1, model2 name, dialog2)
|
| 22 |
+
"""
|
| 23 |
+
model1, model2 = random.sample(list(dialog_dict.keys()), 2)
|
| 24 |
+
dialog1 = random.choice(dialog_dict[model1])
|
| 25 |
+
dialog2 = random.choice(dialog_dict[model2])
|
| 26 |
+
return model1, dialog1, model2, dialog2
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def new_comparison(dialog_dict: dict) -> Tuple[str, str, str, str, gr.Row, gr.Row, gr.Row]:
|
| 31 |
+
"""
|
| 32 |
+
Generate a new comparison pair and make the arena row visible.
|
| 33 |
+
|
| 34 |
+
Args:
|
| 35 |
+
dialog_dict (dict): Dictionary of dialogs per model.
|
| 36 |
+
|
| 37 |
+
Returns:
|
| 38 |
+
Tuple[str, str, str, str, gr.Row]:
|
| 39 |
+
(model1 name, dialog1, model2 name, dialog2,
|
| 40 |
+
arena row visibility update, submit button visibility update, new comparison button visibility update)
|
| 41 |
+
"""
|
| 42 |
+
m1, d1, m2, d2 = sample_pair(dialog_dict)
|
| 43 |
+
return m1, d1, m2, d2, gr.update(visible=True), gr.update(visible=True), gr.update(visible=False)
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def record_vote(choice: str,
|
| 48 |
+
m1: str,
|
| 49 |
+
m2: str,
|
| 50 |
+
d1: str,
|
| 51 |
+
d2: str,
|
| 52 |
+
dialog_dict: dict,
|
| 53 |
+
is_dev: bool,
|
| 54 |
+
result_file_path: Optional[str] = None) -> Tuple[str, str, str, str, gr.Row, str, gr.Button]:
|
| 55 |
+
"""
|
| 56 |
+
Record the user's vote and generate a new comparison.
|
| 57 |
+
|
| 58 |
+
Args:
|
| 59 |
+
choice (str): User's choice ('A' or 'B').
|
| 60 |
+
m1 (str): Model 1 name.
|
| 61 |
+
m2 (str): Model 2 name.
|
| 62 |
+
d1 (str): Dialog 1.
|
| 63 |
+
d2 (str): Dialog 2.
|
| 64 |
+
dialog_dict (dict): Dictionary of dialogs per model.
|
| 65 |
+
is_dev (bool): Flag indicating if in development mode.
|
| 66 |
+
result_file_path (str, optional): Path to save the results.
|
| 67 |
+
|
| 68 |
+
Returns:
|
| 69 |
+
Tuple[str, str, str, str, gr.Row, str, gr.Button]:
|
| 70 |
+
(New model1 name, new dialog1, new model2 name, new dialog2, arena row visibility update, message)
|
| 71 |
+
"""
|
| 72 |
+
log(f"{choice=} | A: {m1} vs B: {m2}")
|
| 73 |
+
|
| 74 |
+
# Vote data saving
|
| 75 |
+
if not is_dev:
|
| 76 |
+
with open(result_file_path, "a") as f:
|
| 77 |
+
if choice == "A":
|
| 78 |
+
f.write(f"1\t0\t{m1}\t{m2}\n")
|
| 79 |
+
else:
|
| 80 |
+
f.write(f"0\t1\t{m1}\t{m2}\n")
|
| 81 |
+
|
| 82 |
+
# New pair sampling
|
| 83 |
+
new_m1, new_d1, new_m2, new_d2 = sample_pair(dialog_dict)
|
| 84 |
+
|
| 85 |
+
return new_m1, new_d1, new_m2, new_d2, gr.update(visible=True), "✅ Vote recorded! Next comparison ready!"
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
def save_data(path: str) -> str:
|
| 90 |
+
"""
|
| 91 |
+
Save the human evaluation data.
|
| 92 |
+
|
| 93 |
+
Args:
|
| 94 |
+
path (str): Path to save the results.
|
| 95 |
+
|
| 96 |
+
Returns:
|
| 97 |
+
str: Message of the result submission.
|
| 98 |
+
"""
|
| 99 |
+
try:
|
| 100 |
+
upload_to_github(path, open(path).read())
|
| 101 |
+
return "✅ Results successfully uploaded to GitHub!"
|
| 102 |
+
except Exception as e:
|
| 103 |
+
return f"❌ Upload failed: {e}"
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
def set_result_path() -> str:
|
| 108 |
+
"""
|
| 109 |
+
Set the result saving path.
|
| 110 |
+
|
| 111 |
+
Returns:
|
| 112 |
+
str: Path to save the results.
|
| 113 |
+
"""
|
| 114 |
+
timestamp = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
|
| 115 |
+
unique_id = os.urandom(4).hex()
|
| 116 |
+
result_file = os.path.join("simulation_arena", f"result_{timestamp}_{unique_id}.txt")
|
| 117 |
+
os.makedirs(os.path.dirname(result_file), exist_ok=True)
|
| 118 |
+
return result_file
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
css = """
|
| 123 |
+
.dialog-box {
|
| 124 |
+
height: 600px;
|
| 125 |
+
overflow-y: auto;
|
| 126 |
+
}
|
| 127 |
+
"""
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
|
| 131 |
+
# Arena GUI
|
| 132 |
+
is_dev = False
|
| 133 |
+
result_save_path = set_result_path()
|
| 134 |
+
dialog_dict = make_dialog_dict()
|
| 135 |
+
with gr.Blocks(title="1:1 Outpatient Model Simulation Arena", css=css) as demo:
|
| 136 |
+
gr.Markdown("# 🤖 Model Arena Evaluation")
|
| 137 |
+
gr.Markdown("### Compare two model simulations and choose the better one!")
|
| 138 |
+
gr.Markdown("### This scenario assumes that the patient called the hospital's administrative office for an outpatient inquiry.")
|
| 139 |
+
|
| 140 |
+
# New comparison button
|
| 141 |
+
btn_new = gr.Button("🥊 Start Arena!! 🥊")
|
| 142 |
+
msg = gr.Markdown("")
|
| 143 |
+
state_dict = gr.State(dialog_dict)
|
| 144 |
+
|
| 145 |
+
# Showing two model simulations side by side
|
| 146 |
+
with gr.Row(visible=False) as arena_row:
|
| 147 |
+
with gr.Column():
|
| 148 |
+
model1_name = gr.Textbox(label="Model A", interactive=False, visible=is_dev)
|
| 149 |
+
dialog1_box = gr.Markdown(label="Simulation A", elem_classes="dialog-box") # Textbox → Markdown
|
| 150 |
+
vote1 = gr.Button("👍 Choose A")
|
| 151 |
+
|
| 152 |
+
with gr.Column():
|
| 153 |
+
model2_name = gr.Textbox(label="Model B", interactive=False, visible=is_dev)
|
| 154 |
+
dialog2_box = gr.Markdown(label="Simulation B", elem_classes="dialog-box") # Textbox → Markdown
|
| 155 |
+
vote2 = gr.Button("👍 Choose B")
|
| 156 |
+
|
| 157 |
+
# Submit button
|
| 158 |
+
with gr.Row(visible=False) as submit_row:
|
| 159 |
+
submit_btn = gr.Button("📤 Submit All Results")
|
| 160 |
+
submit_msg = gr.Markdown("")
|
| 161 |
+
|
| 162 |
+
# Button actions
|
| 163 |
+
btn_new.click(
|
| 164 |
+
fn=new_comparison,
|
| 165 |
+
inputs=[state_dict],
|
| 166 |
+
outputs=[model1_name, dialog1_box, model2_name, dialog2_box, arena_row, submit_row, btn_new],
|
| 167 |
+
)
|
| 168 |
+
|
| 169 |
+
vote1.click(
|
| 170 |
+
fn=lambda m1, m2, d1, d2, state, is_dev=is_dev, result_file_path=result_save_path: record_vote("A", m1, m2, d1, d2, state, is_dev, result_file_path),
|
| 171 |
+
inputs=[model1_name, model2_name, dialog1_box, dialog2_box, state_dict],
|
| 172 |
+
outputs=[model1_name, dialog1_box, model2_name, dialog2_box, arena_row, msg],
|
| 173 |
+
)
|
| 174 |
+
|
| 175 |
+
vote2.click(
|
| 176 |
+
fn=lambda m1, m2, d1, d2, state, is_dev=is_dev, result_file_path=result_save_path: record_vote("B", m1, m2, d1, d2, state, is_dev, result_file_path),
|
| 177 |
+
inputs=[model1_name, model2_name, dialog1_box, dialog2_box, state_dict],
|
| 178 |
+
outputs=[model1_name, dialog1_box, model2_name, dialog2_box, arena_row, msg],
|
| 179 |
+
)
|
| 180 |
+
|
| 181 |
+
submit_btn.click(
|
| 182 |
+
fn=save_data,
|
| 183 |
+
inputs=[gr.State(result_save_path)],
|
| 184 |
+
outputs=[submit_msg],
|
| 185 |
+
)
|
| 186 |
+
|
| 187 |
+
# Launch the app
|
| 188 |
+
if is_dev:
|
| 189 |
+
demo.launch(server_port=7860)
|
| 190 |
+
else:
|
| 191 |
+
demo.launch()
|
dialogs/gemini-2.5-flash/primary/hospital_00_agent_dialog.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
dialogs/gemini-2.5-flash/primary/hospital_01_agent_dialog.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
dialogs/gemini-2.5-flash/primary/hospital_02_agent_dialog.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
dialogs/gemini-2.5-flash/secondary/hospital_0_agent_dialog.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
dialogs/gemini-2.5-flash/secondary/hospital_1_agent_dialog.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
dialogs/gemini-2.5-flash/secondary/hospital_2_agent_dialog.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
dialogs/gpt-5-mini/primary/hospital_00_agent_dialog.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
dialogs/gpt-5-mini/primary/hospital_01_agent_dialog.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
dialogs/gpt-5-mini/primary/hospital_02_agent_dialog.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
dialogs/gpt-5-mini/secondary/hospital_0_agent_dialog.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
dialogs/gpt-5-mini/secondary/hospital_1_agent_dialog.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
dialogs/gpt-5-mini/secondary/hospital_2_agent_dialog.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
dialogs/gpt-5-nano/primary/hospital_00_agent_dialog.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
dialogs/gpt-5-nano/primary/hospital_01_agent_dialog.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
dialogs/gpt-5-nano/primary/hospital_02_agent_dialog.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
dialogs/gpt-5-nano/sencondary/hospital_0_agent_dialog.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
dialogs/gpt-5-nano/sencondary/hospital_1_agent_dialog.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
dialogs/gpt-5-nano/sencondary/hospital_2_agent_dialog.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
requirements.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
gradio==5.49.1
|
| 2 |
+
dotenv==0.9.9
|
| 3 |
+
PyGithub==2.8.1
|
utils/__init__.py
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import logging.config
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
base_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
| 7 |
+
try:
|
| 8 |
+
version_file_path = os.path.join(base_path, 'version.txt')
|
| 9 |
+
LOGGING_NAME = f"Simulation_Arena_{open(version_file_path).read().strip()}"
|
| 10 |
+
except:
|
| 11 |
+
version_file_path = os.path.join(base_path, 'app', 'version.txt')
|
| 12 |
+
LOGGING_NAME = f"Simulation_Arena_{open(version_file_path).read().strip()}"
|
| 13 |
+
VERBOSE = True
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def set_logging(name=LOGGING_NAME, verbose=True):
|
| 17 |
+
"""Sets up logging for the given name."""
|
| 18 |
+
rank = int(os.getenv('RANK', -1)) # rank in world for Multi-GPU trainings
|
| 19 |
+
level = logging.INFO if verbose and rank in {-1, 0} else logging.ERROR
|
| 20 |
+
|
| 21 |
+
class ColorFormatter(logging.Formatter):
|
| 22 |
+
"""Custom formatter to add colors to log messages using colorstr."""
|
| 23 |
+
def format(self, record):
|
| 24 |
+
if record.levelname == "ERROR":
|
| 25 |
+
record.msg = colorstr("red", record.msg)
|
| 26 |
+
elif record.levelname == "WARNING":
|
| 27 |
+
record.msg = colorstr("yellow", record.msg)
|
| 28 |
+
# elif record.levelname == "INFO":
|
| 29 |
+
# record.msg = colorstr("green", record.msg)
|
| 30 |
+
elif record.levelname == "DEBUG":
|
| 31 |
+
record.msg = colorstr("blue", record.msg)
|
| 32 |
+
return super().format(record)
|
| 33 |
+
|
| 34 |
+
logging.config.dictConfig({
|
| 35 |
+
'version': 1,
|
| 36 |
+
'disable_existing_loggers': False,
|
| 37 |
+
'formatters': {
|
| 38 |
+
name: {
|
| 39 |
+
'()': ColorFormatter, # Use the custom formatter
|
| 40 |
+
'format': '[%(asctime)s] [%(levelname)s] [%(name)s] %(message)s'
|
| 41 |
+
}
|
| 42 |
+
},
|
| 43 |
+
'handlers': {
|
| 44 |
+
name: {
|
| 45 |
+
'class': 'logging.StreamHandler',
|
| 46 |
+
'formatter': name,
|
| 47 |
+
'level': level
|
| 48 |
+
}
|
| 49 |
+
},
|
| 50 |
+
'loggers': {
|
| 51 |
+
name: {
|
| 52 |
+
'level': level,
|
| 53 |
+
'handlers': [name],
|
| 54 |
+
'propagate': False
|
| 55 |
+
}
|
| 56 |
+
}
|
| 57 |
+
})
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
set_logging(LOGGING_NAME, verbose=VERBOSE)
|
| 61 |
+
LOGGER = logging.getLogger(LOGGING_NAME)
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
def colorstr(*input):
|
| 66 |
+
"""
|
| 67 |
+
Colors a string based on the provided color and style arguments. Utilizes ANSI escape codes.
|
| 68 |
+
See https://en.wikipedia.org/wiki/ANSI_escape_code for more details.
|
| 69 |
+
|
| 70 |
+
This function can be called in two ways:
|
| 71 |
+
- colorstr('color', 'style', 'your string')
|
| 72 |
+
- colorstr('your string')
|
| 73 |
+
|
| 74 |
+
In the second form, 'blue' and 'bold' will be applied by default.
|
| 75 |
+
|
| 76 |
+
Args:
|
| 77 |
+
*input (str): A sequence of strings where the first n-1 strings are color and style arguments,
|
| 78 |
+
and the last string is the one to be colored.
|
| 79 |
+
|
| 80 |
+
Supported Colors and Styles:
|
| 81 |
+
Basic Colors: 'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'
|
| 82 |
+
Bright Colors: 'bright_black', 'bright_red', 'bright_green', 'bright_yellow',
|
| 83 |
+
'bright_blue', 'bright_magenta', 'bright_cyan', 'bright_white'
|
| 84 |
+
Misc: 'end', 'bold', 'underline'
|
| 85 |
+
|
| 86 |
+
Returns:
|
| 87 |
+
(str): The input string wrapped with ANSI escape codes for the specified color and style.
|
| 88 |
+
|
| 89 |
+
Examples:
|
| 90 |
+
>>> colorstr('blue', 'bold', 'hello world')
|
| 91 |
+
>>> '\033[34m\033[1mhello world\033[0m'
|
| 92 |
+
"""
|
| 93 |
+
*args, string = input if len(input) > 1 else ('blue', 'bold', input[0]) # color arguments, string
|
| 94 |
+
colors = {
|
| 95 |
+
'black': '\033[30m', # basic colors
|
| 96 |
+
'red': '\033[31m',
|
| 97 |
+
'green': '\033[32m',
|
| 98 |
+
'yellow': '\033[33m',
|
| 99 |
+
'blue': '\033[34m',
|
| 100 |
+
'magenta': '\033[35m',
|
| 101 |
+
'cyan': '\033[36m',
|
| 102 |
+
'white': '\033[37m',
|
| 103 |
+
'bright_black': '\033[90m', # bright colors
|
| 104 |
+
'bright_red': '\033[91m',
|
| 105 |
+
'bright_green': '\033[92m',
|
| 106 |
+
'bright_yellow': '\033[93m',
|
| 107 |
+
'bright_blue': '\033[94m',
|
| 108 |
+
'bright_magenta': '\033[95m',
|
| 109 |
+
'bright_cyan': '\033[96m',
|
| 110 |
+
'bright_white': '\033[97m',
|
| 111 |
+
'end': '\033[0m', # misc
|
| 112 |
+
'bold': '\033[1m',
|
| 113 |
+
'underline': '\033[4m'}
|
| 114 |
+
return ''.join(colors[x] for x in args) + f'{string}' + colors['end']
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
|
| 118 |
+
def log(message, level='info', color=False):
|
| 119 |
+
if level.lower() == 'warning':
|
| 120 |
+
LOGGER.warning(message)
|
| 121 |
+
elif level.lower() == 'error':
|
| 122 |
+
LOGGER.error(message)
|
| 123 |
+
else:
|
| 124 |
+
if color:
|
| 125 |
+
LOGGER.info(colorstr(message))
|
| 126 |
+
else:
|
| 127 |
+
LOGGER.info(message)
|
utils/common.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from github import Github
|
| 3 |
+
from dotenv import load_dotenv
|
| 4 |
+
|
| 5 |
+
from utils import log
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def upload_to_github(file_path, content):
|
| 10 |
+
load_dotenv(override=True)
|
| 11 |
+
g = Github(os.getenv("GITHUB_TOKEN"))
|
| 12 |
+
repo = g.get_repo("ljm565/adminsim-human-eval")
|
| 13 |
+
try:
|
| 14 |
+
contents = None
|
| 15 |
+
try:
|
| 16 |
+
contents = repo.get_contents(file_path, ref="main")
|
| 17 |
+
except Exception:
|
| 18 |
+
if contents is None:
|
| 19 |
+
repo.create_file(file_path, "feat: Add new results", content, branch="main")
|
| 20 |
+
log(f"File created successfully at {file_path}!")
|
| 21 |
+
else:
|
| 22 |
+
repo.update_file(file_path, "feat: Update the results", content, contents.sha, branch="main")
|
| 23 |
+
log(f"File updated successfully at {file_path}!")
|
| 24 |
+
except Exception as e:
|
| 25 |
+
log(f"An error occurred: {e}", level="error")
|
utils/filesys_utils.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import json
|
| 3 |
+
from typing import Any
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def json_load(path: str) -> Any:
|
| 8 |
+
"""
|
| 9 |
+
Load and parse a JSON file.
|
| 10 |
+
|
| 11 |
+
Args:
|
| 12 |
+
path (str): Path to the JSON file.
|
| 13 |
+
|
| 14 |
+
Returns:
|
| 15 |
+
Any: The parsed Python object (usually a dict or list) from the JSON file.
|
| 16 |
+
"""
|
| 17 |
+
with open(path, 'r') as f:
|
| 18 |
+
return json.load(f)
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def get_files(path: str, ext: str = None) -> list[str]:
|
| 23 |
+
"""
|
| 24 |
+
Get all files in a directory with a specific extension.
|
| 25 |
+
|
| 26 |
+
Args:
|
| 27 |
+
path (str): Folder path to search for files.
|
| 28 |
+
ext (str, optional): Extension that you want to filter. Defaults to None.
|
| 29 |
+
|
| 30 |
+
Raises:
|
| 31 |
+
ValueError: If file does not exist.
|
| 32 |
+
|
| 33 |
+
Returns:
|
| 34 |
+
list[str]: List of file paths that match the given extension.
|
| 35 |
+
"""
|
| 36 |
+
if not os.path.isdir(path):
|
| 37 |
+
raise ValueError(f"Path {path} is not a directory.")
|
| 38 |
+
|
| 39 |
+
files = []
|
| 40 |
+
for root, _, filenames in os.walk(path):
|
| 41 |
+
for filename in filenames:
|
| 42 |
+
if ext is None or filename.endswith(ext):
|
| 43 |
+
files.append(os.path.join(root, filename))
|
| 44 |
+
|
| 45 |
+
return files
|
utils/postprocess.py
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os, re
|
| 2 |
+
from utils.filesys_utils import json_load, get_files
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
def make_dialog_dict(dir_path: str = './dialogs') -> dict:
|
| 7 |
+
"""
|
| 8 |
+
Create a dictionary of dialogs from JSON files in the specified directory.
|
| 9 |
+
|
| 10 |
+
Args:
|
| 11 |
+
dir_path (str, optional): Path to the directory containing dialog JSON files. Defaults to './dialogs'.
|
| 12 |
+
|
| 13 |
+
Returns:
|
| 14 |
+
dict: A dictionary where keys are model name and values are the parsed JSON content.
|
| 15 |
+
"""
|
| 16 |
+
dialog_dict = {}
|
| 17 |
+
|
| 18 |
+
for model in os.listdir(dir_path):
|
| 19 |
+
model_path = os.path.join(dir_path, model)
|
| 20 |
+
dialog_files = get_files(model_path, ext='.json')
|
| 21 |
+
if not dialog_files:
|
| 22 |
+
continue
|
| 23 |
+
|
| 24 |
+
dialogues = [content
|
| 25 |
+
for file in dialog_files
|
| 26 |
+
for content in map(dialog_postprocessing, json_load(file).values())
|
| 27 |
+
if content
|
| 28 |
+
]
|
| 29 |
+
|
| 30 |
+
if dialogues:
|
| 31 |
+
dialog_dict[model] = dialogues
|
| 32 |
+
|
| 33 |
+
return dialog_dict
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def dialog_postprocessing(dialog: str) -> str:
|
| 38 |
+
"""
|
| 39 |
+
Postprocess a dialog string by removing unwanted tokens.
|
| 40 |
+
|
| 41 |
+
Args:
|
| 42 |
+
dialog (str): The dialog string to be processed.
|
| 43 |
+
|
| 44 |
+
Returns:
|
| 45 |
+
str: The cleaned dialog string.
|
| 46 |
+
"""
|
| 47 |
+
department_candidates = ["gastroenterology", "cardiology", "pulmonary", "endocrinology/metabolism", "nephrology", "hematology/oncology", "allergy", "infectious diseases", "rheumatology"]
|
| 48 |
+
try:
|
| 49 |
+
answer_pattern = re.compile(r'Answer:\s*\d+\.\s*(.+)')
|
| 50 |
+
split_pattern = re.compile(r'\bAnswer:')
|
| 51 |
+
|
| 52 |
+
department = answer_pattern.search(dialog).group(1)
|
| 53 |
+
for candidate in department_candidates:
|
| 54 |
+
if department.lower().startswith(candidate):
|
| 55 |
+
department = candidate
|
| 56 |
+
break
|
| 57 |
+
assert department.lower() in department_candidates
|
| 58 |
+
|
| 59 |
+
before_answer = re.split(split_pattern, dialog)[0].strip()
|
| 60 |
+
before_answer += f' I will introduce you to a physician who work in the {department}.'
|
| 61 |
+
|
| 62 |
+
before_answer = before_answer.replace("Staff:", "<span style='color:rgb(0,102,204); font-weight:bold'>Staff</span> :")
|
| 63 |
+
before_answer = before_answer.replace("Patient:", "<span style='color:rgb(204,0,102); font-weight:bold'>Patient</span>:")
|
| 64 |
+
before_answer = before_answer.replace("\n", "<br>")
|
| 65 |
+
|
| 66 |
+
except:
|
| 67 |
+
before_answer = ''
|
| 68 |
+
|
| 69 |
+
return before_answer
|
| 70 |
+
|
| 71 |
+
|
version.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
1.0.0
|