Spaces:
Sleeping
Sleeping
ping98k commited on
Commit ·
c0bf2b8
1
Parent(s): c29b692
Update main.py
Browse files
main.py
CHANGED
|
@@ -18,37 +18,35 @@ def generate_players(instruction, n):
|
|
| 18 |
)
|
| 19 |
return [c.message.content.strip() for c in response.choices]
|
| 20 |
|
| 21 |
-
def run_tournament(instruction_input, criteria_input, n_gen,
|
| 22 |
-
num_top_picks, pool_size, max_workers):
|
| 23 |
instruction = instruction_input.strip()
|
| 24 |
-
criteria_list = [c.strip() for c in criteria_input.split(",") if c.strip()] or [
|
| 25 |
-
"Factuality", "Instruction Following", "Precision"
|
| 26 |
-
]
|
| 27 |
n_gen = int(n_gen)
|
| 28 |
num_top_picks = int(num_top_picks)
|
| 29 |
pool_size = int(pool_size)
|
| 30 |
max_workers = int(max_workers)
|
| 31 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
def criteria_block():
|
| 33 |
return "\n".join(f"{i + 1}) {c}" for i, c in enumerate(criteria_list))
|
| 34 |
-
|
| 35 |
def prompt_score(player):
|
| 36 |
prompt = f"""Evaluate the output below on the following criteria:
|
| 37 |
{criteria_block()}
|
| 38 |
|
| 39 |
-
Return JSON exactly like: {{"score": [{', '.join(['1-10'] * len(criteria_list))}]}}.
|
| 40 |
|
| 41 |
Instruction:
|
| 42 |
{instruction}
|
| 43 |
|
| 44 |
Output:
|
| 45 |
{player}"""
|
| 46 |
-
response = completion(
|
| 47 |
-
model="gpt-4o-mini",
|
| 48 |
-
messages=[{"role": "system", "content": prompt}]
|
| 49 |
-
)
|
| 50 |
return response.choices[0].message.content.strip()
|
| 51 |
-
|
| 52 |
def score(player):
|
| 53 |
try:
|
| 54 |
data = json.loads(prompt_score(player))
|
|
@@ -56,12 +54,16 @@ Output:
|
|
| 56 |
data = eval(prompt_score(player))
|
| 57 |
lst = data.get("score", data.get("scores", []))
|
| 58 |
return sum(lst) / len(lst) if lst else 0.0
|
| 59 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
def prompt_play(a, b):
|
| 61 |
prompt = f"""Compare the two players below using:
|
| 62 |
{criteria_block()}
|
| 63 |
|
| 64 |
-
Return ONLY JSON {{"winner": "A"}} or {{"winner": "B"}}.
|
| 65 |
|
| 66 |
Instruction:
|
| 67 |
{instruction}
|
|
@@ -69,26 +71,14 @@ Instruction:
|
|
| 69 |
Players:
|
| 70 |
<A>{a}</A>
|
| 71 |
<B>{b}</B>"""
|
| 72 |
-
response = completion(
|
| 73 |
-
model="gpt-4o-mini",
|
| 74 |
-
messages=[{"role": "system", "content": prompt}]
|
| 75 |
-
)
|
| 76 |
return response.choices[0].message.content.strip()
|
| 77 |
-
|
| 78 |
def play(a, b):
|
| 79 |
try:
|
| 80 |
winner_label = json.loads(prompt_play(a, b))["winner"]
|
| 81 |
except json.JSONDecodeError:
|
| 82 |
winner_label = eval(prompt_play(a, b)).get("winner", "A")
|
| 83 |
return a if winner_label == "A" else b
|
| 84 |
-
|
| 85 |
-
def precompute_scores(players, executor):
|
| 86 |
-
futures = {executor.submit(score, p): p for p in players}
|
| 87 |
-
scores = {}
|
| 88 |
-
for fut in tqdm(as_completed(futures), total=len(futures)):
|
| 89 |
-
scores[futures[fut]] = fut.result()
|
| 90 |
-
return scores
|
| 91 |
-
|
| 92 |
def tournament_round(pairs, executor):
|
| 93 |
futures = {executor.submit(play, a, b): (a, b) for a, b in pairs}
|
| 94 |
results = []
|
|
@@ -98,7 +88,6 @@ Players:
|
|
| 98 |
loser = b if winner == a else a
|
| 99 |
results.append((winner, loser))
|
| 100 |
return results
|
| 101 |
-
|
| 102 |
def tournament(players, executor):
|
| 103 |
lost_to = {}
|
| 104 |
current = players[:]
|
|
@@ -110,36 +99,26 @@ Players:
|
|
| 110 |
if len(players) % 2 == 1:
|
| 111 |
current.append(players[-1])
|
| 112 |
return current[0], lost_to
|
| 113 |
-
|
| 114 |
def get_candidates(champion, lost_to):
|
| 115 |
return [p for p, o in lost_to.items() if o == champion] + [champion]
|
| 116 |
-
|
| 117 |
def playoff(candidates, executor):
|
| 118 |
wins = {p: 0 for p in candidates}
|
| 119 |
-
pairs = [(candidates[i], candidates[j])
|
| 120 |
-
for i in range(len(candidates))
|
| 121 |
-
for j in range(i + 1, len(candidates))]
|
| 122 |
futures = {executor.submit(play, a, b): (a, b) for a, b in pairs}
|
| 123 |
for fut in tqdm(as_completed(futures), total=len(futures)):
|
| 124 |
wins[fut.result()] += 1
|
| 125 |
return sorted(candidates, key=lambda p: wins[p], reverse=True)
|
| 126 |
-
|
| 127 |
def get_top(players, executor):
|
| 128 |
champion, lost_to = tournament(players, executor)
|
| 129 |
runner_up = lost_to.get(champion)
|
| 130 |
finalists = [champion] + ([runner_up] if runner_up else [])
|
| 131 |
-
semifinalists = [p for p, o in lost_to.items()
|
| 132 |
-
|
| 133 |
-
candidates = set(finalists + semifinalists +
|
| 134 |
-
get_candidates(champion, lost_to))
|
| 135 |
return playoff(list(candidates), executor)[:num_top_picks]
|
| 136 |
-
|
| 137 |
-
all_players = generate_players(instruction, n_gen)
|
| 138 |
with ThreadPoolExecutor(max_workers=max_workers) as ex:
|
| 139 |
-
scores = precompute_scores(all_players, ex)
|
| 140 |
-
top_players = sorted(all_players, key=scores.get, reverse=True)[:pool_size]
|
| 141 |
top_k = get_top(top_players, ex)
|
| 142 |
-
|
| 143 |
|
| 144 |
demo = gr.Interface(
|
| 145 |
fn=run_tournament,
|
|
@@ -151,7 +130,10 @@ demo = gr.Interface(
|
|
| 151 |
gr.Number(value=POOL_SIZE_DEFAULT, label="Filter Size"),
|
| 152 |
gr.Number(value=MAX_WORKERS_DEFAULT, label="Max Workers")
|
| 153 |
],
|
| 154 |
-
outputs=
|
|
|
|
|
|
|
|
|
|
| 155 |
)
|
| 156 |
|
| 157 |
if __name__ == "__main__":
|
|
|
|
| 18 |
)
|
| 19 |
return [c.message.content.strip() for c in response.choices]
|
| 20 |
|
| 21 |
+
def run_tournament(instruction_input, criteria_input, n_gen, num_top_picks, pool_size, max_workers):
|
|
|
|
| 22 |
instruction = instruction_input.strip()
|
| 23 |
+
criteria_list = [c.strip() for c in criteria_input.split(",") if c.strip()] or ["Factuality", "Instruction Following", "Precision"]
|
|
|
|
|
|
|
| 24 |
n_gen = int(n_gen)
|
| 25 |
num_top_picks = int(num_top_picks)
|
| 26 |
pool_size = int(pool_size)
|
| 27 |
max_workers = int(max_workers)
|
| 28 |
+
process_log = []
|
| 29 |
+
def log(msg):
|
| 30 |
+
process_log.append(msg)
|
| 31 |
+
yield "\n".join(process_log), ""
|
| 32 |
+
yield from log("Generating players …")
|
| 33 |
+
all_players = generate_players(instruction, n_gen)
|
| 34 |
+
yield from log(f"{len(all_players)} players generated")
|
| 35 |
def criteria_block():
|
| 36 |
return "\n".join(f"{i + 1}) {c}" for i, c in enumerate(criteria_list))
|
|
|
|
| 37 |
def prompt_score(player):
|
| 38 |
prompt = f"""Evaluate the output below on the following criteria:
|
| 39 |
{criteria_block()}
|
| 40 |
|
| 41 |
+
Return JSON exactly like: {{\"score\": [{', '.join(['1-10'] * len(criteria_list))}]}}.
|
| 42 |
|
| 43 |
Instruction:
|
| 44 |
{instruction}
|
| 45 |
|
| 46 |
Output:
|
| 47 |
{player}"""
|
| 48 |
+
response = completion(model="gpt-4o-mini", messages=[{"role": "system", "content": prompt}])
|
|
|
|
|
|
|
|
|
|
| 49 |
return response.choices[0].message.content.strip()
|
|
|
|
| 50 |
def score(player):
|
| 51 |
try:
|
| 52 |
data = json.loads(prompt_score(player))
|
|
|
|
| 54 |
data = eval(prompt_score(player))
|
| 55 |
lst = data.get("score", data.get("scores", []))
|
| 56 |
return sum(lst) / len(lst) if lst else 0.0
|
| 57 |
+
yield from log("Scoring players …")
|
| 58 |
+
with ThreadPoolExecutor(max_workers=max_workers) as ex:
|
| 59 |
+
scores = {p: s for p, s in zip(all_players, list(tqdm(ex.map(score, all_players), total=len(all_players))))}
|
| 60 |
+
top_players = sorted(all_players, key=scores.get, reverse=True)[:pool_size]
|
| 61 |
+
yield from log(f"Filtered to {len(top_players)} players with best scores")
|
| 62 |
def prompt_play(a, b):
|
| 63 |
prompt = f"""Compare the two players below using:
|
| 64 |
{criteria_block()}
|
| 65 |
|
| 66 |
+
Return ONLY JSON {{\"winner\": \"A\"}} or {{\"winner\": \"B\"}}.
|
| 67 |
|
| 68 |
Instruction:
|
| 69 |
{instruction}
|
|
|
|
| 71 |
Players:
|
| 72 |
<A>{a}</A>
|
| 73 |
<B>{b}</B>"""
|
| 74 |
+
response = completion(model="gpt-4o-mini", messages=[{"role": "system", "content": prompt}])
|
|
|
|
|
|
|
|
|
|
| 75 |
return response.choices[0].message.content.strip()
|
|
|
|
| 76 |
def play(a, b):
|
| 77 |
try:
|
| 78 |
winner_label = json.loads(prompt_play(a, b))["winner"]
|
| 79 |
except json.JSONDecodeError:
|
| 80 |
winner_label = eval(prompt_play(a, b)).get("winner", "A")
|
| 81 |
return a if winner_label == "A" else b
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 82 |
def tournament_round(pairs, executor):
|
| 83 |
futures = {executor.submit(play, a, b): (a, b) for a, b in pairs}
|
| 84 |
results = []
|
|
|
|
| 88 |
loser = b if winner == a else a
|
| 89 |
results.append((winner, loser))
|
| 90 |
return results
|
|
|
|
| 91 |
def tournament(players, executor):
|
| 92 |
lost_to = {}
|
| 93 |
current = players[:]
|
|
|
|
| 99 |
if len(players) % 2 == 1:
|
| 100 |
current.append(players[-1])
|
| 101 |
return current[0], lost_to
|
|
|
|
| 102 |
def get_candidates(champion, lost_to):
|
| 103 |
return [p for p, o in lost_to.items() if o == champion] + [champion]
|
|
|
|
| 104 |
def playoff(candidates, executor):
|
| 105 |
wins = {p: 0 for p in candidates}
|
| 106 |
+
pairs = [(candidates[i], candidates[j]) for i in range(len(candidates)) for j in range(i + 1, len(candidates))]
|
|
|
|
|
|
|
| 107 |
futures = {executor.submit(play, a, b): (a, b) for a, b in pairs}
|
| 108 |
for fut in tqdm(as_completed(futures), total=len(futures)):
|
| 109 |
wins[fut.result()] += 1
|
| 110 |
return sorted(candidates, key=lambda p: wins[p], reverse=True)
|
|
|
|
| 111 |
def get_top(players, executor):
|
| 112 |
champion, lost_to = tournament(players, executor)
|
| 113 |
runner_up = lost_to.get(champion)
|
| 114 |
finalists = [champion] + ([runner_up] if runner_up else [])
|
| 115 |
+
semifinalists = [p for p, o in lost_to.items() if o in finalists and p not in finalists]
|
| 116 |
+
candidates = set(finalists + semifinalists + get_candidates(champion, lost_to))
|
|
|
|
|
|
|
| 117 |
return playoff(list(candidates), executor)[:num_top_picks]
|
| 118 |
+
yield from log("Running tournament …")
|
|
|
|
| 119 |
with ThreadPoolExecutor(max_workers=max_workers) as ex:
|
|
|
|
|
|
|
| 120 |
top_k = get_top(top_players, ex)
|
| 121 |
+
yield "\n".join(process_log + ["Done"]), ", ".join(top_k)
|
| 122 |
|
| 123 |
demo = gr.Interface(
|
| 124 |
fn=run_tournament,
|
|
|
|
| 130 |
gr.Number(value=POOL_SIZE_DEFAULT, label="Filter Size"),
|
| 131 |
gr.Number(value=MAX_WORKERS_DEFAULT, label="Max Workers")
|
| 132 |
],
|
| 133 |
+
outputs=[
|
| 134 |
+
gr.Textbox(lines=10, label="Process"),
|
| 135 |
+
gr.Textbox(label="Top picks")
|
| 136 |
+
]
|
| 137 |
)
|
| 138 |
|
| 139 |
if __name__ == "__main__":
|