Spaces:
Paused
Paused
Commit ·
5459ec8
1
Parent(s): 21edd7d
update
Browse files- inference.py +3 -3
- run-output/training/train_grpo.executed.ipynb +33 -33
- server/dashboard.html +3 -4
- server/training.html +5 -7
- server/viraltest_environment.py +5 -10
- training/run_llm_training.py +4 -7
- training/run_training_evidence.py +2 -5
- training/train_grpo.ipynb +313 -19
- training/train_grpo_smoke.ipynb +21 -21
inference.py
CHANGED
|
@@ -46,9 +46,9 @@ NEAR_ZERO_ENERGY_THRESHOLD = 0.25
|
|
| 46 |
|
| 47 |
# The agent is NOT told peak hours, fatigue rules, or content type tips.
|
| 48 |
# It must discover these via the tool catalog.
|
| 49 |
-
SYSTEM_PROMPT = textwrap.dedent(
|
| 50 |
You are an Instagram content strategy agent. Each step is one full day (24 hours).
|
| 51 |
-
You manage a creator account over a
|
| 52 |
|
| 53 |
You receive a SPARSE observation (energy, followers, last reward, notes echo).
|
| 54 |
To learn about the world, you MUST use TOOLS before planning your day.
|
|
@@ -85,7 +85,7 @@ RULES:
|
|
| 85 |
- Empty scheduled_actions = rest all day
|
| 86 |
- Use notes to track hypotheses and observations across days
|
| 87 |
- Tool calls cost API budget (starts at 100). Use wisely.
|
| 88 |
-
- Max 2 collaborations per
|
| 89 |
|
| 90 |
Think strategically: use tools to discover what works, then exploit what you learn.""")
|
| 91 |
|
|
|
|
| 46 |
|
| 47 |
# The agent is NOT told peak hours, fatigue rules, or content type tips.
|
| 48 |
# It must discover these via the tool catalog.
|
| 49 |
+
SYSTEM_PROMPT = textwrap.dedent("""\
|
| 50 |
You are an Instagram content strategy agent. Each step is one full day (24 hours).
|
| 51 |
+
You manage a creator account over a 30-day monthly cycle.
|
| 52 |
|
| 53 |
You receive a SPARSE observation (energy, followers, last reward, notes echo).
|
| 54 |
To learn about the world, you MUST use TOOLS before planning your day.
|
|
|
|
| 85 |
- Empty scheduled_actions = rest all day
|
| 86 |
- Use notes to track hypotheses and observations across days
|
| 87 |
- Tool calls cost API budget (starts at 100). Use wisely.
|
| 88 |
+
- Max 2 collaborations per month
|
| 89 |
|
| 90 |
Think strategically: use tools to discover what works, then exploit what you learn.""")
|
| 91 |
|
run-output/training/train_grpo.executed.ipynb
CHANGED
|
@@ -803,7 +803,7 @@
|
|
| 803 |
},
|
| 804 |
{
|
| 805 |
"cell_type": "code",
|
| 806 |
-
"execution_count":
|
| 807 |
"id": "62b45537",
|
| 808 |
"metadata": {
|
| 809 |
"execution": {
|
|
@@ -834,7 +834,7 @@
|
|
| 834 |
"# Cell 8: LLM agent functions\n",
|
| 835 |
"SYSTEM_PROMPT = textwrap.dedent(\"\"\"\\\n",
|
| 836 |
"You are an Instagram content strategy agent. Each step is one day.\n",
|
| 837 |
-
"You manage a creator account over a
|
| 838 |
"\n",
|
| 839 |
"RESPONSE FORMAT — return ONLY valid JSON, no markdown:\n",
|
| 840 |
"{\n",
|
|
@@ -4619,13 +4619,13 @@
|
|
| 4619 |
"description": "",
|
| 4620 |
"description_allow_html": false,
|
| 4621 |
"layout": "IPY_MODEL_92572de3c8bd4340920bd41041fa3677",
|
| 4622 |
-
"max": 4
|
| 4623 |
-
"min": 0
|
| 4624 |
"orientation": "horizontal",
|
| 4625 |
"style": "IPY_MODEL_461954ccde12450b884a5d88d99f78cc",
|
| 4626 |
"tabbable": null,
|
| 4627 |
"tooltip": null,
|
| 4628 |
-
"value": 4
|
| 4629 |
}
|
| 4630 |
},
|
| 4631 |
"12cd3cee31124f45a49c0b1f6b6dabc2": {
|
|
@@ -5082,13 +5082,13 @@
|
|
| 5082 |
"description": "",
|
| 5083 |
"description_allow_html": false,
|
| 5084 |
"layout": "IPY_MODEL_da32983d4d164c4a942e1fff2b234113",
|
| 5085 |
-
"max": 4
|
| 5086 |
-
"min": 0
|
| 5087 |
"orientation": "horizontal",
|
| 5088 |
"style": "IPY_MODEL_24e1b952b30a4266bae74d029c52d7f6",
|
| 5089 |
"tabbable": null,
|
| 5090 |
"tooltip": null,
|
| 5091 |
-
"value": 4
|
| 5092 |
}
|
| 5093 |
},
|
| 5094 |
"330301478152410481945768d907f057": {
|
|
@@ -5232,13 +5232,13 @@
|
|
| 5232 |
"description": "",
|
| 5233 |
"description_allow_html": false,
|
| 5234 |
"layout": "IPY_MODEL_4f783474f1204d358c36ef52457d3d64",
|
| 5235 |
-
"max": 7305
|
| 5236 |
-
"min": 0
|
| 5237 |
"orientation": "horizontal",
|
| 5238 |
"style": "IPY_MODEL_8999ebf7ab524d72aa6508e2d027ecc1",
|
| 5239 |
"tabbable": null,
|
| 5240 |
"tooltip": null,
|
| 5241 |
-
"value": 7305
|
| 5242 |
}
|
| 5243 |
},
|
| 5244 |
"37f812ce5e2347479778ffccab06cb54": {
|
|
@@ -5329,13 +5329,13 @@
|
|
| 5329 |
"description": "",
|
| 5330 |
"description_allow_html": false,
|
| 5331 |
"layout": "IPY_MODEL_e6bf97b928c240afa63326920624d9f8",
|
| 5332 |
-
"max": 1671839
|
| 5333 |
-
"min": 0
|
| 5334 |
"orientation": "horizontal",
|
| 5335 |
"style": "IPY_MODEL_4a50b585075b49399513484981060fef",
|
| 5336 |
"tabbable": null,
|
| 5337 |
"tooltip": null,
|
| 5338 |
-
"value": 1671839
|
| 5339 |
}
|
| 5340 |
},
|
| 5341 |
"3adecb27e83942588088da579cb170b2": {
|
|
@@ -6039,13 +6039,13 @@
|
|
| 6039 |
"description": "",
|
| 6040 |
"description_allow_html": false,
|
| 6041 |
"layout": "IPY_MODEL_48800cfb03424a28a0b37c1c9fd075b6",
|
| 6042 |
-
"max": 3087467144
|
| 6043 |
-
"min": 0
|
| 6044 |
"orientation": "horizontal",
|
| 6045 |
"style": "IPY_MODEL_12cd3cee31124f45a49c0b1f6b6dabc2",
|
| 6046 |
"tabbable": null,
|
| 6047 |
"tooltip": null,
|
| 6048 |
-
"value": 3087467144
|
| 6049 |
}
|
| 6050 |
},
|
| 6051 |
"73b47cd92e754d7e8ace7cbef0a5cb1c": {
|
|
@@ -6134,13 +6134,13 @@
|
|
| 6134 |
"description": "",
|
| 6135 |
"description_allow_html": false,
|
| 6136 |
"layout": "IPY_MODEL_27d193479919478abccf42607a6b3032",
|
| 6137 |
-
"max": 338
|
| 6138 |
-
"min": 0
|
| 6139 |
"orientation": "horizontal",
|
| 6140 |
"style": "IPY_MODEL_4965af7bb8c74cb186d30e37d36ad8bd",
|
| 6141 |
"tabbable": null,
|
| 6142 |
"tooltip": null,
|
| 6143 |
-
"value": 338
|
| 6144 |
}
|
| 6145 |
},
|
| 6146 |
"7bd060f8373645e5aa91681002f1ed23": {
|
|
@@ -6572,13 +6572,13 @@
|
|
| 6572 |
"description": "",
|
| 6573 |
"description_allow_html": false,
|
| 6574 |
"layout": "IPY_MODEL_e042f5aea57943cdab80001c763cd0b1",
|
| 6575 |
-
"max": 2776833
|
| 6576 |
-
"min": 0
|
| 6577 |
"orientation": "horizontal",
|
| 6578 |
"style": "IPY_MODEL_b5392d04a1714872b50ac74beb849411",
|
| 6579 |
"tabbable": null,
|
| 6580 |
"tooltip": null,
|
| 6581 |
-
"value": 2776833
|
| 6582 |
}
|
| 6583 |
},
|
| 6584 |
"a4cc2830308b440bac5f69e757e5d511": {
|
|
@@ -6887,13 +6887,13 @@
|
|
| 6887 |
"description": "",
|
| 6888 |
"description_allow_html": false,
|
| 6889 |
"layout": "IPY_MODEL_37f812ce5e2347479778ffccab06cb54",
|
| 6890 |
-
"max": 7031645
|
| 6891 |
-
"min": 0
|
| 6892 |
"orientation": "horizontal",
|
| 6893 |
"style": "IPY_MODEL_74899c00e43a4c4a9bb48656931d8fa0",
|
| 6894 |
"tabbable": null,
|
| 6895 |
"tooltip": null,
|
| 6896 |
-
"value": 7031645
|
| 6897 |
}
|
| 6898 |
},
|
| 6899 |
"b5392d04a1714872b50ac74beb849411": {
|
|
@@ -7801,13 +7801,13 @@
|
|
| 7801 |
"description": "",
|
| 7802 |
"description_allow_html": false,
|
| 7803 |
"layout": "IPY_MODEL_dcd14169f60b488ab3d3fcd58ed29b27",
|
| 7804 |
-
"max": 660
|
| 7805 |
-
"min": 0
|
| 7806 |
"orientation": "horizontal",
|
| 7807 |
"style": "IPY_MODEL_443cc98027db4b7d88e561a442945c2d",
|
| 7808 |
"tabbable": null,
|
| 7809 |
"tooltip": null,
|
| 7810 |
-
"value": 660
|
| 7811 |
}
|
| 7812 |
},
|
| 7813 |
"ebb37c4d91bf4a42a7aef1e8186062e9": {
|
|
@@ -7827,13 +7827,13 @@
|
|
| 7827 |
"description": "",
|
| 7828 |
"description_allow_html": false,
|
| 7829 |
"layout": "IPY_MODEL_330301478152410481945768d907f057",
|
| 7830 |
-
"max": 242
|
| 7831 |
-
"min": 0
|
| 7832 |
"orientation": "horizontal",
|
| 7833 |
"style": "IPY_MODEL_28fbc46f8dc44a6c9c2e71ab97d58c02",
|
| 7834 |
"tabbable": null,
|
| 7835 |
"tooltip": null,
|
| 7836 |
-
"value": 242
|
| 7837 |
}
|
| 7838 |
},
|
| 7839 |
"ef27ba1ee51a46d6a5790f9623d59ac6": {
|
|
@@ -8151,4 +8151,4 @@
|
|
| 8151 |
},
|
| 8152 |
"nbformat": 4,
|
| 8153 |
"nbformat_minor": 5
|
| 8154 |
-
}
|
|
|
|
| 803 |
},
|
| 804 |
{
|
| 805 |
"cell_type": "code",
|
| 806 |
+
"execution_count": null,
|
| 807 |
"id": "62b45537",
|
| 808 |
"metadata": {
|
| 809 |
"execution": {
|
|
|
|
| 834 |
"# Cell 8: LLM agent functions\n",
|
| 835 |
"SYSTEM_PROMPT = textwrap.dedent(\"\"\"\\\n",
|
| 836 |
"You are an Instagram content strategy agent. Each step is one day.\n",
|
| 837 |
+
"You manage a creator account over a 15-day cycle.\n",
|
| 838 |
"\n",
|
| 839 |
"RESPONSE FORMAT — return ONLY valid JSON, no markdown:\n",
|
| 840 |
"{\n",
|
|
|
|
| 4619 |
"description": "",
|
| 4620 |
"description_allow_html": false,
|
| 4621 |
"layout": "IPY_MODEL_92572de3c8bd4340920bd41041fa3677",
|
| 4622 |
+
"max": 4,
|
| 4623 |
+
"min": 0,
|
| 4624 |
"orientation": "horizontal",
|
| 4625 |
"style": "IPY_MODEL_461954ccde12450b884a5d88d99f78cc",
|
| 4626 |
"tabbable": null,
|
| 4627 |
"tooltip": null,
|
| 4628 |
+
"value": 4
|
| 4629 |
}
|
| 4630 |
},
|
| 4631 |
"12cd3cee31124f45a49c0b1f6b6dabc2": {
|
|
|
|
| 5082 |
"description": "",
|
| 5083 |
"description_allow_html": false,
|
| 5084 |
"layout": "IPY_MODEL_da32983d4d164c4a942e1fff2b234113",
|
| 5085 |
+
"max": 4,
|
| 5086 |
+
"min": 0,
|
| 5087 |
"orientation": "horizontal",
|
| 5088 |
"style": "IPY_MODEL_24e1b952b30a4266bae74d029c52d7f6",
|
| 5089 |
"tabbable": null,
|
| 5090 |
"tooltip": null,
|
| 5091 |
+
"value": 4
|
| 5092 |
}
|
| 5093 |
},
|
| 5094 |
"330301478152410481945768d907f057": {
|
|
|
|
| 5232 |
"description": "",
|
| 5233 |
"description_allow_html": false,
|
| 5234 |
"layout": "IPY_MODEL_4f783474f1204d358c36ef52457d3d64",
|
| 5235 |
+
"max": 7305,
|
| 5236 |
+
"min": 0,
|
| 5237 |
"orientation": "horizontal",
|
| 5238 |
"style": "IPY_MODEL_8999ebf7ab524d72aa6508e2d027ecc1",
|
| 5239 |
"tabbable": null,
|
| 5240 |
"tooltip": null,
|
| 5241 |
+
"value": 7305
|
| 5242 |
}
|
| 5243 |
},
|
| 5244 |
"37f812ce5e2347479778ffccab06cb54": {
|
|
|
|
| 5329 |
"description": "",
|
| 5330 |
"description_allow_html": false,
|
| 5331 |
"layout": "IPY_MODEL_e6bf97b928c240afa63326920624d9f8",
|
| 5332 |
+
"max": 1671839,
|
| 5333 |
+
"min": 0,
|
| 5334 |
"orientation": "horizontal",
|
| 5335 |
"style": "IPY_MODEL_4a50b585075b49399513484981060fef",
|
| 5336 |
"tabbable": null,
|
| 5337 |
"tooltip": null,
|
| 5338 |
+
"value": 1671839
|
| 5339 |
}
|
| 5340 |
},
|
| 5341 |
"3adecb27e83942588088da579cb170b2": {
|
|
|
|
| 6039 |
"description": "",
|
| 6040 |
"description_allow_html": false,
|
| 6041 |
"layout": "IPY_MODEL_48800cfb03424a28a0b37c1c9fd075b6",
|
| 6042 |
+
"max": 3087467144,
|
| 6043 |
+
"min": 0,
|
| 6044 |
"orientation": "horizontal",
|
| 6045 |
"style": "IPY_MODEL_12cd3cee31124f45a49c0b1f6b6dabc2",
|
| 6046 |
"tabbable": null,
|
| 6047 |
"tooltip": null,
|
| 6048 |
+
"value": 3087467144
|
| 6049 |
}
|
| 6050 |
},
|
| 6051 |
"73b47cd92e754d7e8ace7cbef0a5cb1c": {
|
|
|
|
| 6134 |
"description": "",
|
| 6135 |
"description_allow_html": false,
|
| 6136 |
"layout": "IPY_MODEL_27d193479919478abccf42607a6b3032",
|
| 6137 |
+
"max": 338,
|
| 6138 |
+
"min": 0,
|
| 6139 |
"orientation": "horizontal",
|
| 6140 |
"style": "IPY_MODEL_4965af7bb8c74cb186d30e37d36ad8bd",
|
| 6141 |
"tabbable": null,
|
| 6142 |
"tooltip": null,
|
| 6143 |
+
"value": 338
|
| 6144 |
}
|
| 6145 |
},
|
| 6146 |
"7bd060f8373645e5aa91681002f1ed23": {
|
|
|
|
| 6572 |
"description": "",
|
| 6573 |
"description_allow_html": false,
|
| 6574 |
"layout": "IPY_MODEL_e042f5aea57943cdab80001c763cd0b1",
|
| 6575 |
+
"max": 2776833,
|
| 6576 |
+
"min": 0,
|
| 6577 |
"orientation": "horizontal",
|
| 6578 |
"style": "IPY_MODEL_b5392d04a1714872b50ac74beb849411",
|
| 6579 |
"tabbable": null,
|
| 6580 |
"tooltip": null,
|
| 6581 |
+
"value": 2776833
|
| 6582 |
}
|
| 6583 |
},
|
| 6584 |
"a4cc2830308b440bac5f69e757e5d511": {
|
|
|
|
| 6887 |
"description": "",
|
| 6888 |
"description_allow_html": false,
|
| 6889 |
"layout": "IPY_MODEL_37f812ce5e2347479778ffccab06cb54",
|
| 6890 |
+
"max": 7031645,
|
| 6891 |
+
"min": 0,
|
| 6892 |
"orientation": "horizontal",
|
| 6893 |
"style": "IPY_MODEL_74899c00e43a4c4a9bb48656931d8fa0",
|
| 6894 |
"tabbable": null,
|
| 6895 |
"tooltip": null,
|
| 6896 |
+
"value": 7031645
|
| 6897 |
}
|
| 6898 |
},
|
| 6899 |
"b5392d04a1714872b50ac74beb849411": {
|
|
|
|
| 7801 |
"description": "",
|
| 7802 |
"description_allow_html": false,
|
| 7803 |
"layout": "IPY_MODEL_dcd14169f60b488ab3d3fcd58ed29b27",
|
| 7804 |
+
"max": 660,
|
| 7805 |
+
"min": 0,
|
| 7806 |
"orientation": "horizontal",
|
| 7807 |
"style": "IPY_MODEL_443cc98027db4b7d88e561a442945c2d",
|
| 7808 |
"tabbable": null,
|
| 7809 |
"tooltip": null,
|
| 7810 |
+
"value": 660
|
| 7811 |
}
|
| 7812 |
},
|
| 7813 |
"ebb37c4d91bf4a42a7aef1e8186062e9": {
|
|
|
|
| 7827 |
"description": "",
|
| 7828 |
"description_allow_html": false,
|
| 7829 |
"layout": "IPY_MODEL_330301478152410481945768d907f057",
|
| 7830 |
+
"max": 242,
|
| 7831 |
+
"min": 0,
|
| 7832 |
"orientation": "horizontal",
|
| 7833 |
"style": "IPY_MODEL_28fbc46f8dc44a6c9c2e71ab97d58c02",
|
| 7834 |
"tabbable": null,
|
| 7835 |
"tooltip": null,
|
| 7836 |
+
"value": 242
|
| 7837 |
}
|
| 7838 |
},
|
| 7839 |
"ef27ba1ee51a46d6a5790f9623d59ac6": {
|
|
|
|
| 8151 |
},
|
| 8152 |
"nbformat": 4,
|
| 8153 |
"nbformat_minor": 5
|
| 8154 |
+
}
|
server/dashboard.html
CHANGED
|
@@ -35,7 +35,7 @@ body{background:#0b1326;color:#dae2fd;font-family:'Inter',sans-serif}
|
|
| 35 |
<aside class="flex flex-col sticky top-0 h-screen w-64 border-r border-white/5 bg-surface-lowest shadow-2xl shadow-slate-950/50 shrink-0 z-50">
|
| 36 |
<div class="p-6 pb-4">
|
| 37 |
<div class="text-xl font-black tracking-tighter text-transparent bg-clip-text bg-gradient-to-br from-primary to-primary-ctr mb-1">Growth Copilot</div>
|
| 38 |
-
<div class="text-[9px] font-label uppercase tracking-[.2em] text-on-surface-dim/50">
|
| 39 |
</div>
|
| 40 |
<nav class="flex-1 px-3 space-y-1">
|
| 41 |
<a href="/dashboard" class="flex items-center gap-3 px-4 py-2.5 rounded-lg text-primary font-bold border-r-2 border-primary bg-gradient-to-r from-primary/10 to-transparent transition-all">
|
|
@@ -361,7 +361,7 @@ body{background:#0b1326;color:#dae2fd;font-family:'Inter',sans-serif}
|
|
| 361 |
<div class="flex flex-col items-end gap-0.5">
|
| 362 |
<div class="flex items-center gap-2">
|
| 363 |
<span id="scenarioCount" class="text-[9px] font-label text-primary font-bold">…</span>
|
| 364 |
-
<span class="text-[9px] font-label text-on-surface-dim">
|
| 365 |
</div>
|
| 366 |
<span class="text-[8px] font-label text-on-surface-dim/70 max-w-[16rem] text-right leading-tight">All strategies below — scroll the grid or search. Count updates after load.</span>
|
| 367 |
</div>
|
|
@@ -492,8 +492,7 @@ body{background:#0b1326;color:#dae2fd;font-family:'Inter',sans-serif}
|
|
| 492 |
|
| 493 |
<script>
|
| 494 |
const API=window.location.origin;
|
| 495 |
-
|
| 496 |
-
const EPISODE_DAYS=15;
|
| 497 |
const DAYS=["Mon","Tue","Wed","Thu","Fri","Sat","Sun"];
|
| 498 |
function fmtAxisNum(v){
|
| 499 |
const a=Math.abs(v);
|
|
|
|
| 35 |
<aside class="flex flex-col sticky top-0 h-screen w-64 border-r border-white/5 bg-surface-lowest shadow-2xl shadow-slate-950/50 shrink-0 z-50">
|
| 36 |
<div class="p-6 pb-4">
|
| 37 |
<div class="text-xl font-black tracking-tighter text-transparent bg-clip-text bg-gradient-to-br from-primary to-primary-ctr mb-1">Growth Copilot</div>
|
| 38 |
+
<div class="text-[9px] font-label uppercase tracking-[.2em] text-on-surface-dim/50">30-day creator simulation</div>
|
| 39 |
</div>
|
| 40 |
<nav class="flex-1 px-3 space-y-1">
|
| 41 |
<a href="/dashboard" class="flex items-center gap-3 px-4 py-2.5 rounded-lg text-primary font-bold border-r-2 border-primary bg-gradient-to-r from-primary/10 to-transparent transition-all">
|
|
|
|
| 361 |
<div class="flex flex-col items-end gap-0.5">
|
| 362 |
<div class="flex items-center gap-2">
|
| 363 |
<span id="scenarioCount" class="text-[9px] font-label text-primary font-bold">…</span>
|
| 364 |
+
<span class="text-[9px] font-label text-on-surface-dim">30-day episode</span>
|
| 365 |
</div>
|
| 366 |
<span class="text-[8px] font-label text-on-surface-dim/70 max-w-[16rem] text-right leading-tight">All strategies below — scroll the grid or search. Count updates after load.</span>
|
| 367 |
</div>
|
|
|
|
| 492 |
|
| 493 |
<script>
|
| 494 |
const API=window.location.origin;
|
| 495 |
+
const EPISODE_DAYS=30;
|
|
|
|
| 496 |
const DAYS=["Mon","Tue","Wed","Thu","Fri","Sat","Sun"];
|
| 497 |
function fmtAxisNum(v){
|
| 498 |
const a=Math.abs(v);
|
server/training.html
CHANGED
|
@@ -105,7 +105,7 @@ body{background:#0b1326;color:#dae2fd;font-family:'Inter',sans-serif}
|
|
| 105 |
<div class="glass-solid p-5 rounded-xl overflow-hidden">
|
| 106 |
<h3 class="text-sm font-bold mb-1 flex items-center gap-2">
|
| 107 |
<span class="material-symbols-outlined text-secondary text-lg">show_chart</span>
|
| 108 |
-
Reward Trajectories (
|
| 109 |
</h3>
|
| 110 |
<p class="text-[9px] font-label text-on-surface-dim mb-3">Daily reward over the episode for each agent × task. Shows that smart strategies maintain higher rewards throughout.</p>
|
| 111 |
<div class="grid grid-cols-1 lg:grid-cols-3 gap-4">
|
|
@@ -169,8 +169,6 @@ const API=window.location.origin;
|
|
| 169 |
const COLORS={"always_rest":"#E53935","spam":"#FF9800","random":"#9E9E9E","minimal":"#42A5F5","smart":"#4CAF50"};
|
| 170 |
const TASK_MAP={"monthly_engage":"engage","monthly_strategic":"strategic","monthly_competitive":"competitive"};
|
| 171 |
const TASK_LABELS={"monthly_engage":"Engage","monthly_strategic":"Strategic","monthly_competitive":"Competitive"};
|
| 172 |
-
/** Must match server.viraltest_environment.TASK_HORIZON */
|
| 173 |
-
const EPISODE_DAYS=15;
|
| 174 |
|
| 175 |
let allData=null;
|
| 176 |
|
|
@@ -276,7 +274,7 @@ function renderTrajectories(){
|
|
| 276 |
html+=`<line x1="${pL}" y1="${pT}" x2="${pL}" y2="${H-pB}" stroke="#cbc3d7" stroke-width="0.7"/>`;
|
| 277 |
html+=`<line x1="${pL}" y1="${H-pB}" x2="${W-pR}" y2="${H-pB}" stroke="#cbc3d7" stroke-width="0.7"/>`;
|
| 278 |
html+=`<text x="${pL}" y="${H-10}" fill="#958ea0" font-size="8" font-family="Space Grotesk,sans-serif">Day 1</text>`;
|
| 279 |
-
html+=`<text x="${W-pR}" y="${H-10}" text-anchor="end" fill="#958ea0" font-size="8" font-family="Space Grotesk,sans-serif">Day
|
| 280 |
html+=`<text x="${pL+plotW/2}" y="${H-2}" text-anchor="middle" fill="#958ea0" font-size="7" font-family="Space Grotesk,sans-serif" opacity="0.75">day</text>`;
|
| 281 |
|
| 282 |
taskResults.forEach(r=>{
|
|
@@ -319,7 +317,7 @@ function renderTable(){
|
|
| 319 |
const scoreColor=r.grader_score>=0.5?"text-primary":r.grader_score>=0.2?"text-secondary":"text-tertiary";
|
| 320 |
const energyColor=r.final_energy>=0.5?"text-secondary":r.final_energy>0?"text-tertiary":"text-error";
|
| 321 |
const deltaColor=r.follower_delta>0?"text-secondary":r.follower_delta<0?"text-tertiary":"text-on-surface-dim";
|
| 322 |
-
const status=r.burned_out?'<span class="text-tertiary font-bold">BURNED</span>':r.steps>=
|
| 323 |
return `<tr class="border-b border-white/5 hover:bg-white/[.02]">
|
| 324 |
<td class="px-4 py-2"><div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full" style="background:${color}"></span><span class="text-on-surface font-bold">${r.scenario}</span></div></td>
|
| 325 |
<td class="px-4 py-2 text-on-surface-dim">${TASK_LABELS[r.task]||r.task}</td>
|
|
@@ -353,13 +351,13 @@ function renderTakeaways(){
|
|
| 353 |
const ratio=worst.avg>0?(best.avg/worst.avg).toFixed(1):"∞";
|
| 354 |
|
| 355 |
const burnedOut=allData.results.filter(r=>r.burned_out);
|
| 356 |
-
const completed=allData.results.filter(r=>!r.burned_out&&r.steps>=
|
| 357 |
|
| 358 |
const points=[
|
| 359 |
`<span class="text-on-surface font-bold">Best agent: ${best.label}</span> (avg score ${best.avg.toFixed(4)}) — ${ratio}× better than worst (${worst.label}, avg ${worst.avg.toFixed(4)}).`,
|
| 360 |
`<span class="text-on-surface font-bold">Score spread:</span> The environment produces a ${(avgs[0].avg-avgs[avgs.length-1].avg).toFixed(4)} spread between best and worst agents, proving the reward is informative and not flat.`,
|
| 361 |
`<span class="text-on-surface font-bold">${burnedOut.length} burnout events</span> across ${allData.results.length} runs — the burnout penalty correctly punishes unsustainable strategies (spam, no-rest).`,
|
| 362 |
-
`<span class="text-on-surface font-bold">${completed.length}/${allData.results.length} episodes completed</span> all
|
| 363 |
`<span class="text-on-surface font-bold">Reward is hard to game:</span> Spamming posts burns out immediately (score ≈ 0). Always resting loses followers. The optimal strategy requires balancing multiple objectives.`,
|
| 364 |
`<span class="text-on-surface font-bold">Grader difficulty scales correctly:</span> All agents score lower on Competitive than on Engage, confirming the three-tier difficulty progression works.`,
|
| 365 |
];
|
|
|
|
| 105 |
<div class="glass-solid p-5 rounded-xl overflow-hidden">
|
| 106 |
<h3 class="text-sm font-bold mb-1 flex items-center gap-2">
|
| 107 |
<span class="material-symbols-outlined text-secondary text-lg">show_chart</span>
|
| 108 |
+
Reward Trajectories (30-day episodes)
|
| 109 |
</h3>
|
| 110 |
<p class="text-[9px] font-label text-on-surface-dim mb-3">Daily reward over the episode for each agent × task. Shows that smart strategies maintain higher rewards throughout.</p>
|
| 111 |
<div class="grid grid-cols-1 lg:grid-cols-3 gap-4">
|
|
|
|
| 169 |
const COLORS={"always_rest":"#E53935","spam":"#FF9800","random":"#9E9E9E","minimal":"#42A5F5","smart":"#4CAF50"};
|
| 170 |
const TASK_MAP={"monthly_engage":"engage","monthly_strategic":"strategic","monthly_competitive":"competitive"};
|
| 171 |
const TASK_LABELS={"monthly_engage":"Engage","monthly_strategic":"Strategic","monthly_competitive":"Competitive"};
|
|
|
|
|
|
|
| 172 |
|
| 173 |
let allData=null;
|
| 174 |
|
|
|
|
| 274 |
html+=`<line x1="${pL}" y1="${pT}" x2="${pL}" y2="${H-pB}" stroke="#cbc3d7" stroke-width="0.7"/>`;
|
| 275 |
html+=`<line x1="${pL}" y1="${H-pB}" x2="${W-pR}" y2="${H-pB}" stroke="#cbc3d7" stroke-width="0.7"/>`;
|
| 276 |
html+=`<text x="${pL}" y="${H-10}" fill="#958ea0" font-size="8" font-family="Space Grotesk,sans-serif">Day 1</text>`;
|
| 277 |
+
html+=`<text x="${W-pR}" y="${H-10}" text-anchor="end" fill="#958ea0" font-size="8" font-family="Space Grotesk,sans-serif">Day 30</text>`;
|
| 278 |
html+=`<text x="${pL+plotW/2}" y="${H-2}" text-anchor="middle" fill="#958ea0" font-size="7" font-family="Space Grotesk,sans-serif" opacity="0.75">day</text>`;
|
| 279 |
|
| 280 |
taskResults.forEach(r=>{
|
|
|
|
| 317 |
const scoreColor=r.grader_score>=0.5?"text-primary":r.grader_score>=0.2?"text-secondary":"text-tertiary";
|
| 318 |
const energyColor=r.final_energy>=0.5?"text-secondary":r.final_energy>0?"text-tertiary":"text-error";
|
| 319 |
const deltaColor=r.follower_delta>0?"text-secondary":r.follower_delta<0?"text-tertiary":"text-on-surface-dim";
|
| 320 |
+
const status=r.burned_out?'<span class="text-tertiary font-bold">BURNED</span>':r.steps>=30?'<span class="text-secondary">DONE</span>':'<span class="text-on-surface-dim">EARLY</span>';
|
| 321 |
return `<tr class="border-b border-white/5 hover:bg-white/[.02]">
|
| 322 |
<td class="px-4 py-2"><div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full" style="background:${color}"></span><span class="text-on-surface font-bold">${r.scenario}</span></div></td>
|
| 323 |
<td class="px-4 py-2 text-on-surface-dim">${TASK_LABELS[r.task]||r.task}</td>
|
|
|
|
| 351 |
const ratio=worst.avg>0?(best.avg/worst.avg).toFixed(1):"∞";
|
| 352 |
|
| 353 |
const burnedOut=allData.results.filter(r=>r.burned_out);
|
| 354 |
+
const completed=allData.results.filter(r=>!r.burned_out&&r.steps>=30);
|
| 355 |
|
| 356 |
const points=[
|
| 357 |
`<span class="text-on-surface font-bold">Best agent: ${best.label}</span> (avg score ${best.avg.toFixed(4)}) — ${ratio}× better than worst (${worst.label}, avg ${worst.avg.toFixed(4)}).`,
|
| 358 |
`<span class="text-on-surface font-bold">Score spread:</span> The environment produces a ${(avgs[0].avg-avgs[avgs.length-1].avg).toFixed(4)} spread between best and worst agents, proving the reward is informative and not flat.`,
|
| 359 |
`<span class="text-on-surface font-bold">${burnedOut.length} burnout events</span> across ${allData.results.length} runs — the burnout penalty correctly punishes unsustainable strategies (spam, no-rest).`,
|
| 360 |
+
`<span class="text-on-surface font-bold">${completed.length}/${allData.results.length} episodes completed</span> all 30 days — agents that manage energy survive; those that don't burn out early.`,
|
| 361 |
`<span class="text-on-surface font-bold">Reward is hard to game:</span> Spamming posts burns out immediately (score ≈ 0). Always resting loses followers. The optimal strategy requires balancing multiple objectives.`,
|
| 362 |
`<span class="text-on-surface font-bold">Grader difficulty scales correctly:</span> All agents score lower on Competitive than on Engage, confirming the three-tier difficulty progression works.`,
|
| 363 |
];
|
server/viraltest_environment.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
"""
|
| 2 |
Viraltest Environment v2 — Theme #3.1 World-Modeling Simulation.
|
| 3 |
|
| 4 |
-
|
| 5 |
- Mosseri-aligned engagement signals (watch_time, sends, saves, likes)
|
| 6 |
- Discoverable tool catalog (partial observability)
|
| 7 |
- Piecewise-linear sleep model (Van Dongen 2003)
|
|
@@ -92,12 +92,7 @@ _HEATMAP_GRID: Dict[int, List[float]] = {
|
|
| 92 |
# Constants (research-backed, Tier 1-3 sources)
|
| 93 |
# ---------------------------------------------------------------------------
|
| 94 |
|
| 95 |
-
|
| 96 |
-
TASK_HORIZON = 15
|
| 97 |
-
|
| 98 |
-
# Distinct positive tags for full tag_discovery score in strategic/competitive graders.
|
| 99 |
-
# Caps at 30 (original month-scale bar); scales down only for very short horizons.
|
| 100 |
-
TAG_DISCOVERY_POSITIVE_TARGET = float(max(6, min(30, TASK_HORIZON * 2)))
|
| 101 |
|
| 102 |
# Socialinsider 2026 (31M posts)
|
| 103 |
CONTENT_ENERGY_COST = {
|
|
@@ -1189,14 +1184,14 @@ class ViraltestEnvironment(Environment):
|
|
| 1189 |
norm_eng = min(1.0, self._total_engagement / theoretical_max) if theoretical_max > 0 else 0.0
|
| 1190 |
|
| 1191 |
positive_tags = sum(1 for t in self._unique_tags_used if self._tag_performance_avg(t) > 0)
|
| 1192 |
-
tag_discovery = min(1.0, positive_tags /
|
| 1193 |
top_perfs = sorted([self._tag_performance_avg(t) for t in self._unique_tags_used], reverse=True)[:3]
|
| 1194 |
tag_exploitation = (sum(top_perfs) / len(top_perfs)) if top_perfs else 0.0
|
| 1195 |
tag_exploitation = min(1.0, tag_exploitation / 2.0)
|
| 1196 |
tag_score = 0.4 * tag_discovery + 0.6 * tag_exploitation
|
| 1197 |
|
| 1198 |
avg_energy = sum(self._energy_history) / len(self._energy_history) if self._energy_history else 0.0
|
| 1199 |
-
consistency = len(self._days_with_good_posts) /
|
| 1200 |
|
| 1201 |
raw = 0.35 * norm_eng + 0.25 * tag_score + 0.25 * avg_energy + 0.15 * consistency
|
| 1202 |
|
|
@@ -1218,7 +1213,7 @@ class ViraltestEnvironment(Environment):
|
|
| 1218 |
norm_eng = min(1.0, self._total_engagement / theoretical_max) if theoretical_max > 0 else 0.0
|
| 1219 |
|
| 1220 |
positive_tags = sum(1 for t in self._unique_tags_used if self._tag_performance_avg(t) > 0)
|
| 1221 |
-
tag_discovery = min(1.0, positive_tags /
|
| 1222 |
top_perfs = sorted([self._tag_performance_avg(t) for t in self._unique_tags_used], reverse=True)[:3]
|
| 1223 |
tag_exploitation = (sum(top_perfs) / len(top_perfs)) if top_perfs else 0.0
|
| 1224 |
tag_exploitation = min(1.0, tag_exploitation / 2.0)
|
|
|
|
| 1 |
"""
|
| 2 |
Viraltest Environment v2 — Theme #3.1 World-Modeling Simulation.
|
| 3 |
|
| 4 |
+
30-day creator optimization with:
|
| 5 |
- Mosseri-aligned engagement signals (watch_time, sends, saves, likes)
|
| 6 |
- Discoverable tool catalog (partial observability)
|
| 7 |
- Piecewise-linear sleep model (Van Dongen 2003)
|
|
|
|
| 92 |
# Constants (research-backed, Tier 1-3 sources)
|
| 93 |
# ---------------------------------------------------------------------------
|
| 94 |
|
| 95 |
+
TASK_HORIZON = 30 # 30 daily steps (monthly cycle)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 96 |
|
| 97 |
# Socialinsider 2026 (31M posts)
|
| 98 |
CONTENT_ENERGY_COST = {
|
|
|
|
| 1184 |
norm_eng = min(1.0, self._total_engagement / theoretical_max) if theoretical_max > 0 else 0.0
|
| 1185 |
|
| 1186 |
positive_tags = sum(1 for t in self._unique_tags_used if self._tag_performance_avg(t) > 0)
|
| 1187 |
+
tag_discovery = min(1.0, positive_tags / 30.0)
|
| 1188 |
top_perfs = sorted([self._tag_performance_avg(t) for t in self._unique_tags_used], reverse=True)[:3]
|
| 1189 |
tag_exploitation = (sum(top_perfs) / len(top_perfs)) if top_perfs else 0.0
|
| 1190 |
tag_exploitation = min(1.0, tag_exploitation / 2.0)
|
| 1191 |
tag_score = 0.4 * tag_discovery + 0.6 * tag_exploitation
|
| 1192 |
|
| 1193 |
avg_energy = sum(self._energy_history) / len(self._energy_history) if self._energy_history else 0.0
|
| 1194 |
+
consistency = len(self._days_with_good_posts) / 30.0
|
| 1195 |
|
| 1196 |
raw = 0.35 * norm_eng + 0.25 * tag_score + 0.25 * avg_energy + 0.15 * consistency
|
| 1197 |
|
|
|
|
| 1213 |
norm_eng = min(1.0, self._total_engagement / theoretical_max) if theoretical_max > 0 else 0.0
|
| 1214 |
|
| 1215 |
positive_tags = sum(1 for t in self._unique_tags_used if self._tag_performance_avg(t) > 0)
|
| 1216 |
+
tag_discovery = min(1.0, positive_tags / 30.0)
|
| 1217 |
top_perfs = sorted([self._tag_performance_avg(t) for t in self._unique_tags_used], reverse=True)[:3]
|
| 1218 |
tag_exploitation = (sum(top_perfs) / len(top_perfs)) if top_perfs else 0.0
|
| 1219 |
tag_exploitation = min(1.0, tag_exploitation / 2.0)
|
training/run_llm_training.py
CHANGED
|
@@ -146,9 +146,9 @@ def run_episode(task, plan_fn, seed=42):
|
|
| 146 |
|
| 147 |
# ─── Ollama LLM interface ─────────────────────────────────────────────
|
| 148 |
|
| 149 |
-
BASE_SYSTEM_PROMPT = textwrap.dedent(
|
| 150 |
You are an Instagram content strategy agent. Each step is one day.
|
| 151 |
-
You manage a creator account over a
|
| 152 |
|
| 153 |
RESPONSE FORMAT — return ONLY valid JSON, no markdown, no explanation:
|
| 154 |
{
|
|
@@ -319,11 +319,8 @@ def plot_baseline_leaderboard(baseline_results):
|
|
| 319 |
axes[i].text(bar.get_width() + 0.005, bar.get_y() + bar.get_height() / 2,
|
| 320 |
f"{score:.4f}", va="center", fontsize=9)
|
| 321 |
axes[0].set_ylabel("Agent")
|
| 322 |
-
fig.suptitle(
|
| 323 |
-
|
| 324 |
-
fontsize=14,
|
| 325 |
-
fontweight="bold",
|
| 326 |
-
)
|
| 327 |
fig.tight_layout()
|
| 328 |
fig.savefig(PLOTS_DIR / "baseline_leaderboard.png", dpi=150, bbox_inches="tight")
|
| 329 |
plt.close(fig)
|
|
|
|
| 146 |
|
| 147 |
# ─── Ollama LLM interface ─────────────────────────────────────────────
|
| 148 |
|
| 149 |
+
BASE_SYSTEM_PROMPT = textwrap.dedent("""\
|
| 150 |
You are an Instagram content strategy agent. Each step is one day.
|
| 151 |
+
You manage a creator account over a 30-day cycle.
|
| 152 |
|
| 153 |
RESPONSE FORMAT — return ONLY valid JSON, no markdown, no explanation:
|
| 154 |
{
|
|
|
|
| 319 |
axes[i].text(bar.get_width() + 0.005, bar.get_y() + bar.get_height() / 2,
|
| 320 |
f"{score:.4f}", va="center", fontsize=9)
|
| 321 |
axes[0].set_ylabel("Agent")
|
| 322 |
+
fig.suptitle("Viraltest v2 — Heuristic Baseline Leaderboard (30-day episodes)",
|
| 323 |
+
fontsize=14, fontweight="bold")
|
|
|
|
|
|
|
|
|
|
| 324 |
fig.tight_layout()
|
| 325 |
fig.savefig(PLOTS_DIR / "baseline_leaderboard.png", dpi=150, bbox_inches="tight")
|
| 326 |
plt.close(fig)
|
training/run_training_evidence.py
CHANGED
|
@@ -325,11 +325,8 @@ def plot_baseline_leaderboard(baseline_results: Dict):
|
|
| 325 |
f"{score:.4f}", va="center", fontsize=9)
|
| 326 |
|
| 327 |
axes[0].set_ylabel("Agent")
|
| 328 |
-
fig.suptitle(
|
| 329 |
-
|
| 330 |
-
fontsize=14,
|
| 331 |
-
fontweight="bold",
|
| 332 |
-
)
|
| 333 |
fig.tight_layout()
|
| 334 |
path = PLOTS_DIR / "baseline_leaderboard.png"
|
| 335 |
fig.savefig(path, dpi=150, bbox_inches="tight")
|
|
|
|
| 325 |
f"{score:.4f}", va="center", fontsize=9)
|
| 326 |
|
| 327 |
axes[0].set_ylabel("Agent")
|
| 328 |
+
fig.suptitle("Viraltest v2 — Heuristic Baseline Leaderboard (30-day episodes)",
|
| 329 |
+
fontsize=14, fontweight="bold")
|
|
|
|
|
|
|
|
|
|
| 330 |
fig.tight_layout()
|
| 331 |
path = PLOTS_DIR / "baseline_leaderboard.png"
|
| 332 |
fig.savefig(path, dpi=150, bbox_inches="tight")
|
training/train_grpo.ipynb
CHANGED
|
@@ -25,7 +25,35 @@
|
|
| 25 |
},
|
| 26 |
{
|
| 27 |
"cell_type": "code",
|
|
|
|
| 28 |
"metadata": {},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
"source": [
|
| 30 |
"# Cell 1: Install dependencies (quote versions — zsh treats `>` as redirect otherwise)\n",
|
| 31 |
"!pip install -q torch torchvision torchaudio\n",
|
|
@@ -40,7 +68,26 @@
|
|
| 40 |
},
|
| 41 |
{
|
| 42 |
"cell_type": "code",
|
|
|
|
| 43 |
"metadata": {},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
"source": [
|
| 45 |
"# Cell 2: Resolve repo path (Colab: fresh clone. Local: auto-detect project root)\n",
|
| 46 |
"import os\n",
|
|
@@ -122,7 +169,30 @@
|
|
| 122 |
},
|
| 123 |
{
|
| 124 |
"cell_type": "code",
|
|
|
|
| 125 |
"metadata": {},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 126 |
"source": [
|
| 127 |
"# Cell 3: Imports (with runtime validation)\n",
|
| 128 |
"import json, random, time, textwrap, copy, os, sys\n",
|
|
@@ -166,12 +236,15 @@
|
|
| 166 |
"print(f\"GPU: {torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'CPU'}\")\n",
|
| 167 |
"print(f\"Tags: {len(TAG_POOL)}, Topics: {len(ALL_TOPICS)}, Horizon: {TASK_HORIZON} days\")\n",
|
| 168 |
"\n",
|
|
|
|
| 169 |
"# Hard stop if stale repo/code is loaded\n",
|
| 170 |
"assert TASK_HORIZON == 15, (\n",
|
| 171 |
" f\"Expected TASK_HORIZON=15, got {TASK_HORIZON}. \"\n",
|
| 172 |
" \"Restart runtime and run from Cell 1 again (clean clone on main).\"\n",
|
| 173 |
")\n",
|
| 174 |
"\n",
|
|
|
|
|
|
|
| 175 |
"# Same sanity as syntax_only.ipynb (kernel parses modern Python)\n",
|
| 176 |
"import ast\n",
|
| 177 |
"ast.parse(\"def _t(x: int) -> str: return f'{x}'\")\n",
|
|
@@ -191,7 +264,21 @@
|
|
| 191 |
},
|
| 192 |
{
|
| 193 |
"cell_type": "code",
|
|
|
|
| 194 |
"metadata": {},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 195 |
"source": [
|
| 196 |
"# Cell 4: Define heuristic agents + episode runner\n",
|
| 197 |
"_rng = random.Random(42)\n",
|
|
@@ -240,8 +327,7 @@
|
|
| 240 |
" topic=ALL_TOPICS[(day*2+1)%len(ALL_TOPICS)],\n",
|
| 241 |
" tags=[TAG_POOL[(day*6+3+i)%len(TAG_POOL)] for i in range(3)],\n",
|
| 242 |
" intent=INTENTS[(day*2+1)%4]),\n",
|
| 243 |
-
" ]
|
| 244 |
-
" replies=[{\"post_hour\": 12, \"reply_hour\": 13}])\n",
|
| 245 |
"\n",
|
| 246 |
"BASELINE_AGENTS = {\n",
|
| 247 |
" \"always_rest\": plan_always_rest, \"spam\": plan_spam,\n",
|
|
@@ -274,7 +360,51 @@
|
|
| 274 |
},
|
| 275 |
{
|
| 276 |
"cell_type": "code",
|
|
|
|
|
|
|
|
|
|
|
|
|
| 277 |
"metadata": {},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 278 |
"source": [
|
| 279 |
"# Cell 5: Run baselines (safe)\n",
|
| 280 |
"print(\"Running heuristic baselines (5 agents × 3 tasks)...\")\n",
|
|
@@ -315,7 +445,24 @@
|
|
| 315 |
},
|
| 316 |
{
|
| 317 |
"cell_type": "code",
|
|
|
|
|
|
|
|
|
|
|
|
|
| 318 |
"metadata": {},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 319 |
"source": [
|
| 320 |
"# Cell 6: Baseline plots\n",
|
| 321 |
"fig, axes = plt.subplots(1, 3, figsize=(16, 5), sharey=True)\n",
|
|
@@ -348,7 +495,45 @@
|
|
| 348 |
},
|
| 349 |
{
|
| 350 |
"cell_type": "code",
|
|
|
|
|
|
|
|
|
|
|
|
|
| 351 |
"metadata": {},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 352 |
"source": [
|
| 353 |
"# Cell 7: Load model (Qwen2.5-3B bf16 on CUDA + flash-attn-2; fp16/fp32 fallback)\n",
|
| 354 |
"from transformers import AutoTokenizer, AutoModelForCausalLM\n",
|
|
@@ -403,26 +588,42 @@
|
|
| 403 |
"# Cell 8: LLM agent functions\n",
|
| 404 |
"SYSTEM_PROMPT = textwrap.dedent(\"\"\"\\\n",
|
| 405 |
"You are an Instagram content strategy agent. Each step is one day.\n",
|
| 406 |
-
"You manage a creator account over a
|
| 407 |
"\n",
|
| 408 |
"RESPONSE FORMAT — return ONLY valid JSON, no markdown:\n",
|
| 409 |
"{\n",
|
| 410 |
-
" \"tool_calls\": [{\"name\": \"
|
| 411 |
" \"scheduled_actions\": [\n",
|
| 412 |
-
" {\"hour\":
|
| 413 |
-
" \"
|
|
|
|
|
|
|
| 414 |
" ],\n",
|
| 415 |
-
" \"replies\": [{\"post_hour\": 12, \"reply_hour\": 13}],\n",
|
| 416 |
" \"notes\": \"strategy notes\"\n",
|
| 417 |
"}\n",
|
| 418 |
"\n",
|
| 419 |
-
"
|
| 420 |
-
"-
|
| 421 |
-
"-
|
| 422 |
-
"-
|
| 423 |
-
"-
|
| 424 |
-
"-
|
| 425 |
-
"-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 426 |
"\n",
|
| 427 |
"\n",
|
| 428 |
"def format_obs(obs):\n",
|
|
@@ -437,12 +638,14 @@
|
|
| 437 |
" tool_str = \"\"\n",
|
| 438 |
" for tr in getattr(obs, \"tool_results\", []):\n",
|
| 439 |
" if tr.success:\n",
|
| 440 |
-
" tool_str += f\" {tr.name}: {json.dumps(tr.data)
|
|
|
|
|
|
|
| 441 |
" return (f\"Day: {day_name} | days_elapsed={obs.days_elapsed}\\n\"\n",
|
| 442 |
" f\"Energy: {obs.creator_energy:.2f} | Followers: {obs.follower_count}\\n\"\n",
|
| 443 |
" f\"Engagement: {obs.engagement_rate:.3f} | Queue: {obs.content_queue_size}\\n\"\n",
|
| 444 |
" f\"{signals_str}\"\n",
|
| 445 |
-
" f\"Tool results:\\n{tool_str
|
| 446 |
" f\"Plan your actions (JSON only):\")\n",
|
| 447 |
"\n",
|
| 448 |
"\n",
|
|
@@ -495,7 +698,10 @@
|
|
| 495 |
" return ViraltestAction(\n",
|
| 496 |
" tool_calls=tool_calls,\n",
|
| 497 |
" scheduled_actions=scheduled,\n",
|
|
|
|
| 498 |
" replies=data.get(\"replies\", []),\n",
|
|
|
|
|
|
|
| 499 |
" notes=data.get(\"notes\"),\n",
|
| 500 |
" )\n",
|
| 501 |
"\n",
|
|
@@ -511,6 +717,7 @@
|
|
| 511 |
" return torch.device(\"cpu\")\n",
|
| 512 |
"\n",
|
| 513 |
"\n",
|
|
|
|
| 514 |
"def _build_chat(history, prompt):\n",
|
| 515 |
" msgs = [{\"role\": \"system\", \"content\": SYSTEM_PROMPT}]\n",
|
| 516 |
" msgs.extend(history[-14:])\n",
|
|
@@ -600,6 +807,66 @@
|
|
| 600 |
"\n",
|
| 601 |
"def run_llm_episode(mdl, tok, task, seed=42, verbose=False):\n",
|
| 602 |
" return run_llm_episodes_batched(mdl, tok, [(task, seed)], verbose=verbose)[0]\n",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 603 |
"\n",
|
| 604 |
"\n",
|
| 605 |
"print(\"LLM agent functions defined (batched).\")"
|
|
@@ -716,6 +983,7 @@
|
|
| 716 |
" f\"<|im_start|>user\\n{pr['prompt']}<|im_end|>\\n\"\n",
|
| 717 |
" f\"<|im_start|>assistant\\n{pr['response']}<|im_end|>\")\n",
|
| 718 |
" all_pairs.append({\"text\": text, \"reward\": pr[\"return\"]})\n",
|
|
|
|
| 719 |
" kept += 1\n",
|
| 720 |
" print(f\" ep {ep+1}/{EPISODES_PER_ROUND}: {result['task'].split('_')[-1]:>11s} \"\n",
|
| 721 |
" f\"grader={result['grader_score']:.4f} reward={ep_reward:.3f} kept={kept}/{len(result['pairs'])}\")\n",
|
|
@@ -727,6 +995,19 @@
|
|
| 727 |
" print(\" WARNING: 0 well-formed pairs collected; skipping SFT.\")\n",
|
| 728 |
" continue\n",
|
| 729 |
"\n",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 730 |
" threshold = np.percentile([p[\"reward\"] for p in all_pairs], (1 - TOP_K_FRACTION) * 100)\n",
|
| 731 |
" filtered = [p for p in all_pairs if p[\"reward\"] >= threshold] or all_pairs\n",
|
| 732 |
" print(f\" Filtered to {len(filtered)}/{len(all_pairs)} samples (return >= {threshold:.3f})\")\n",
|
|
@@ -736,15 +1017,28 @@
|
|
| 736 |
" # SFT training (real gradient updates)\n",
|
| 737 |
" sft_config = SFTConfig(\n",
|
| 738 |
" output_dir=f\"./checkpoints/round_{round_idx}\",\n",
|
|
|
|
| 739 |
" num_train_epochs=2,\n",
|
| 740 |
" per_device_train_batch_size=4,\n",
|
| 741 |
" gradient_accumulation_steps=2,\n",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 742 |
" learning_rate=2e-5,\n",
|
| 743 |
-
"
|
| 744 |
-
" logging_steps=
|
| 745 |
" save_strategy=\"no\",\n",
|
| 746 |
" max_length=4096,\n",
|
| 747 |
" bf16=True,\n",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 748 |
" report_to=\"none\",\n",
|
| 749 |
" )\n",
|
| 750 |
"\n",
|
|
@@ -987,7 +1281,7 @@
|
|
| 987 |
"name": "python",
|
| 988 |
"nbconvert_exporter": "python",
|
| 989 |
"pygments_lexer": "ipython3",
|
| 990 |
-
"version": "3.
|
| 991 |
}
|
| 992 |
},
|
| 993 |
"nbformat": 4,
|
|
|
|
| 25 |
},
|
| 26 |
{
|
| 27 |
"cell_type": "code",
|
| 28 |
+
<<<<<<< HEAD
|
| 29 |
"metadata": {},
|
| 30 |
+
=======
|
| 31 |
+
"execution_count": 1,
|
| 32 |
+
"metadata": {},
|
| 33 |
+
"outputs": [
|
| 34 |
+
{
|
| 35 |
+
"name": "stdout",
|
| 36 |
+
"output_type": "stream",
|
| 37 |
+
"text": [
|
| 38 |
+
"\n",
|
| 39 |
+
"\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m25.3\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m26.0.1\u001b[0m\n",
|
| 40 |
+
"\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n",
|
| 41 |
+
"\n",
|
| 42 |
+
"\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m25.3\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m26.0.1\u001b[0m\n",
|
| 43 |
+
"\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n",
|
| 44 |
+
"\n",
|
| 45 |
+
"\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m25.3\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m26.0.1\u001b[0m\n",
|
| 46 |
+
"\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n",
|
| 47 |
+
"\n",
|
| 48 |
+
"\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m25.3\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m26.0.1\u001b[0m\n",
|
| 49 |
+
"\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n",
|
| 50 |
+
"\n",
|
| 51 |
+
"\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m25.3\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m26.0.1\u001b[0m\n",
|
| 52 |
+
"\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n"
|
| 53 |
+
]
|
| 54 |
+
}
|
| 55 |
+
],
|
| 56 |
+
>>>>>>> parent of 99717c2 (Set TASK_HORIZON to 15 days and align graders, UI, and training prompts.)
|
| 57 |
"source": [
|
| 58 |
"# Cell 1: Install dependencies (quote versions — zsh treats `>` as redirect otherwise)\n",
|
| 59 |
"!pip install -q torch torchvision torchaudio\n",
|
|
|
|
| 68 |
},
|
| 69 |
{
|
| 70 |
"cell_type": "code",
|
| 71 |
+
<<<<<<< HEAD
|
| 72 |
"metadata": {},
|
| 73 |
+
=======
|
| 74 |
+
"execution_count": 2,
|
| 75 |
+
"metadata": {},
|
| 76 |
+
"outputs": [
|
| 77 |
+
{
|
| 78 |
+
"name": "stdout",
|
| 79 |
+
"output_type": "stream",
|
| 80 |
+
"text": [
|
| 81 |
+
"Mode: local\n",
|
| 82 |
+
"Repo root: /Users/anurag.c/viral-posts-env\n",
|
| 83 |
+
"Working dir: /Users/anurag.c/viral-posts-env\n",
|
| 84 |
+
"Branch: hack1\n",
|
| 85 |
+
"Commit: aedc9c7\n",
|
| 86 |
+
"Plots dir: /Users/anurag.c/viral-posts-env/plots\n"
|
| 87 |
+
]
|
| 88 |
+
}
|
| 89 |
+
],
|
| 90 |
+
>>>>>>> parent of 99717c2 (Set TASK_HORIZON to 15 days and align graders, UI, and training prompts.)
|
| 91 |
"source": [
|
| 92 |
"# Cell 2: Resolve repo path (Colab: fresh clone. Local: auto-detect project root)\n",
|
| 93 |
"import os\n",
|
|
|
|
| 169 |
},
|
| 170 |
{
|
| 171 |
"cell_type": "code",
|
| 172 |
+
<<<<<<< HEAD
|
| 173 |
"metadata": {},
|
| 174 |
+
=======
|
| 175 |
+
"execution_count": 3,
|
| 176 |
+
"metadata": {},
|
| 177 |
+
"outputs": [
|
| 178 |
+
{
|
| 179 |
+
"name": "stdout",
|
| 180 |
+
"output_type": "stream",
|
| 181 |
+
"text": [
|
| 182 |
+
"/Users/anurag.c/viral-posts-env/.venv/lib/python3.14/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
|
| 183 |
+
" from .autonotebook import tqdm as notebook_tqdm\n"
|
| 184 |
+
]
|
| 185 |
+
},
|
| 186 |
+
{
|
| 187 |
+
"name": "stdout",
|
| 188 |
+
"output_type": "stream",
|
| 189 |
+
"text": [
|
| 190 |
+
"GPU: CPU\n",
|
| 191 |
+
"Tags: 114, Topics: 100, Horizon: 30 days\n"
|
| 192 |
+
]
|
| 193 |
+
}
|
| 194 |
+
],
|
| 195 |
+
>>>>>>> parent of 99717c2 (Set TASK_HORIZON to 15 days and align graders, UI, and training prompts.)
|
| 196 |
"source": [
|
| 197 |
"# Cell 3: Imports (with runtime validation)\n",
|
| 198 |
"import json, random, time, textwrap, copy, os, sys\n",
|
|
|
|
| 236 |
"print(f\"GPU: {torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'CPU'}\")\n",
|
| 237 |
"print(f\"Tags: {len(TAG_POOL)}, Topics: {len(ALL_TOPICS)}, Horizon: {TASK_HORIZON} days\")\n",
|
| 238 |
"\n",
|
| 239 |
+
<<<<<<< HEAD
|
| 240 |
"# Hard stop if stale repo/code is loaded\n",
|
| 241 |
"assert TASK_HORIZON == 15, (\n",
|
| 242 |
" f\"Expected TASK_HORIZON=15, got {TASK_HORIZON}. \"\n",
|
| 243 |
" \"Restart runtime and run from Cell 1 again (clean clone on main).\"\n",
|
| 244 |
")\n",
|
| 245 |
"\n",
|
| 246 |
+
=======
|
| 247 |
+
>>>>>>> parent of 99717c2 (Set TASK_HORIZON to 15 days and align graders, UI, and training prompts.)
|
| 248 |
"# Same sanity as syntax_only.ipynb (kernel parses modern Python)\n",
|
| 249 |
"import ast\n",
|
| 250 |
"ast.parse(\"def _t(x: int) -> str: return f'{x}'\")\n",
|
|
|
|
| 264 |
},
|
| 265 |
{
|
| 266 |
"cell_type": "code",
|
| 267 |
+
<<<<<<< HEAD
|
| 268 |
"metadata": {},
|
| 269 |
+
=======
|
| 270 |
+
"execution_count": 4,
|
| 271 |
+
"metadata": {},
|
| 272 |
+
"outputs": [
|
| 273 |
+
{
|
| 274 |
+
"name": "stdout",
|
| 275 |
+
"output_type": "stream",
|
| 276 |
+
"text": [
|
| 277 |
+
"Agents and episode runner defined.\n"
|
| 278 |
+
]
|
| 279 |
+
}
|
| 280 |
+
],
|
| 281 |
+
>>>>>>> parent of 99717c2 (Set TASK_HORIZON to 15 days and align graders, UI, and training prompts.)
|
| 282 |
"source": [
|
| 283 |
"# Cell 4: Define heuristic agents + episode runner\n",
|
| 284 |
"_rng = random.Random(42)\n",
|
|
|
|
| 327 |
" topic=ALL_TOPICS[(day*2+1)%len(ALL_TOPICS)],\n",
|
| 328 |
" tags=[TAG_POOL[(day*6+3+i)%len(TAG_POOL)] for i in range(3)],\n",
|
| 329 |
" intent=INTENTS[(day*2+1)%4]),\n",
|
| 330 |
+
" ])\n",
|
|
|
|
| 331 |
"\n",
|
| 332 |
"BASELINE_AGENTS = {\n",
|
| 333 |
" \"always_rest\": plan_always_rest, \"spam\": plan_spam,\n",
|
|
|
|
| 360 |
},
|
| 361 |
{
|
| 362 |
"cell_type": "code",
|
| 363 |
+
<<<<<<< HEAD
|
| 364 |
+
"metadata": {},
|
| 365 |
+
=======
|
| 366 |
+
"execution_count": 5,
|
| 367 |
"metadata": {},
|
| 368 |
+
"outputs": [
|
| 369 |
+
{
|
| 370 |
+
"name": "stdout",
|
| 371 |
+
"output_type": "stream",
|
| 372 |
+
"text": [
|
| 373 |
+
"Running heuristic baselines (5 agents × 3 tasks)...\n",
|
| 374 |
+
"======================================================================\n",
|
| 375 |
+
" always_rest | monthly_engage | score=0.0000 | energy=1.00\n",
|
| 376 |
+
" always_rest | monthly_strategic | score=0.1750 | energy=1.00\n",
|
| 377 |
+
" always_rest | monthly_competitive | score=0.0350 | energy=1.00\n",
|
| 378 |
+
"\n",
|
| 379 |
+
" spam | monthly_engage | score=0.0042 | energy=0.00\n",
|
| 380 |
+
" spam | monthly_strategic | score=0.0075 | energy=0.00\n",
|
| 381 |
+
" spam | monthly_competitive | score=0.0000 | energy=0.00\n",
|
| 382 |
+
"\n",
|
| 383 |
+
" random | monthly_engage | score=0.5389 | energy=0.92\n",
|
| 384 |
+
" random | monthly_strategic | score=0.6403 | energy=0.92\n",
|
| 385 |
+
" random | monthly_competitive | score=0.6678 | energy=0.92\n",
|
| 386 |
+
"\n",
|
| 387 |
+
" minimal | monthly_engage | score=0.4145 | energy=1.00\n",
|
| 388 |
+
" minimal | monthly_strategic | score=0.7220 | energy=1.00\n",
|
| 389 |
+
" minimal | monthly_competitive | score=0.3850 | energy=1.00\n",
|
| 390 |
+
"\n",
|
| 391 |
+
" smart | monthly_engage | score=0.7883 | energy=1.00\n",
|
| 392 |
+
" smart | monthly_strategic | score=0.8932 | energy=1.00\n",
|
| 393 |
+
" smart | monthly_competitive | score=0.8986 | energy=1.00\n",
|
| 394 |
+
"\n",
|
| 395 |
+
"\n",
|
| 396 |
+
"LEADERBOARD\n",
|
| 397 |
+
"Agent Engage Strategic Competitive Avg\n",
|
| 398 |
+
"------------------------------------------------------------\n",
|
| 399 |
+
"always_rest 0.0000 0.1750 0.0350 0.0700\n",
|
| 400 |
+
"spam 0.0042 0.0075 0.0000 0.0039\n",
|
| 401 |
+
"random 0.5389 0.6403 0.6678 0.6157\n",
|
| 402 |
+
"minimal 0.4145 0.7220 0.3850 0.5072\n",
|
| 403 |
+
"smart 0.7883 0.8932 0.8986 0.8600\n"
|
| 404 |
+
]
|
| 405 |
+
}
|
| 406 |
+
],
|
| 407 |
+
>>>>>>> parent of 99717c2 (Set TASK_HORIZON to 15 days and align graders, UI, and training prompts.)
|
| 408 |
"source": [
|
| 409 |
"# Cell 5: Run baselines (safe)\n",
|
| 410 |
"print(\"Running heuristic baselines (5 agents × 3 tasks)...\")\n",
|
|
|
|
| 445 |
},
|
| 446 |
{
|
| 447 |
"cell_type": "code",
|
| 448 |
+
<<<<<<< HEAD
|
| 449 |
+
"metadata": {},
|
| 450 |
+
=======
|
| 451 |
+
"execution_count": 6,
|
| 452 |
"metadata": {},
|
| 453 |
+
"outputs": [
|
| 454 |
+
{
|
| 455 |
+
"data": {
|
| 456 |
+
"image/png": "iVBORw0KGgoAAAANSUhEUgAABjIAAAHvCAYAAAD+XUa3AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAef9JREFUeJzt3QWYXNX5OP4TSAga3AnBXRKKa5Aiwd0JDsWtuBcrRYsUSvECwa0tULQ4wQnuBQrBITgE5v+85/u/85vd7G52l0327uzn8zw3mZ25M3NlZs699z3ve3pUKpVKAgAAAAAAKKFxOnsBAAAAAAAAmiOQAQAAAAAAlJZABgAAAAAAUFoCGQAAAAAAQGkJZAAAAAAAAKUlkAEAAAAAAJSWQAYAAAAAAFBaAhkAAAAAAEBpCWQAAAAAAAClJZABAHQZ2267berRo0eeBg4cOFbe87777qu+Z0xvv/32WHlfaItZZpml+hk9+uijx+jGu+SSSxp8J/j1v1+12zO2L13797sz2qqxTdsIAIxtAhkAwFiz+uqrVy/uTD755OmHH35ocr5KpZJmn3326rwDBgwo5V4q04WcsX0h9LXXXkunn356Wm+99dJ8882XpphiijTeeOOl6aefPq299trplltuSV3hon9zFxnj/mKemL+7KEuQovF3q5jGHXfcNOmkk6aFF1447bHHHunVV1/ttGXsThrvD8EWAADGtp5j/R0BgG4reqnecccd+fYXX3yR/vGPf6QNN9xwlPkeeuih9OabbzZ4Xthss83SAgsskG/37dt3rC03ozr11FPT+eefP8r9w4cPz/s1pt122y2dc845Nt9YcNhhh6Uvv/wy31566aXH6Hsttthi6U9/+lPqDL/88ksaMWJEeu655/J08cUX54vssUxdWe327OrrAgAAY4JABgAw1kTv/ckmmywHMcJll13WZCAj7i/06tUrbbnlltWMjpjaKi589unT51ctO02bddZZ8z6ZYYYZ0osvvpiuueaa9PPPP+fHzj333LT++uunVVZZxeYbQ7766qs0ySSTpJ122mmsbeP5558/T2PTpptumhZddNE0cuTINHTo0HTjjTfm+7/99tt0/PHHp5tuuil1ZQcccEBnLwIdoF7amnpZDwCgvigtBQCMNeOPP37Oqijcdttt6dNPP20wT5Sbuvbaa6t/r7XWWmmqqaZqc435m2++OfdMn3jiidPMM8+c5/nss8/SgQcemFZeeeVcLiguAEc5pGmnnTb99re/TZdffnkua9Ua8T4rrrjiKBf1i2UoskgKzz77bNp+++1zyawJJpggL1eUzDrhhBPSN998M8rr//e//0277LJLmnPOOfP8se1mnHHGtMwyy6T99tsvvfTSSw1KINXabrvtWl0W6cILL6zOO9FEE42yLBF0ivcu5rniiivy/ZEZc+utt6Y33ngjBywOP/zwdOWVV6YLLrigwfNjH9ej+JyeffbZafnll29QVmvjjTdOjzzyyCjzx7gVze2TKElW+/mNDIPmnhffl9133z3NNNNMucxS7L/RjZERZb4i2BSf8wgMxgXK+BxGYPHEE0/MWQ7FMsRnp1btchWvO7ryUxFsuOiii9Kqq66a3zO2zdRTT52WXHLJdMwxx7Rre8fyx8X+gw8+ON1www3VzKzw8ssvN5j3mWeeydlASyyxRP7OFN+ffv365YDIgw8+2OQyn3HGGWmppZbKwdaePXumKaecMgdsttlmmzRkyJBRnvPhhx+mQw89NPXv3z//lsR7zDHHHHn/vPPOO21av+bKNjXe1vG5i8DNXHPNlXr37p0/B7FdmivTF9/RddddN382Yz9ESb+VVlopf49b+1v3a7R1G7Vn34X4Xuy666758xbPiaDX1VdfPdrli89+/O7HZ3WaaaapflbXXHPN9K9//Wu0JbZef/31dMopp6R5550374/4rDTlo48+SjvuuGOabrrp8vosssgiTX6mwnfffZfL9sVvfeyvoo0aNGhQDhQ39dk94ogj8uPxvY7Pb3zP4/O73HLLpbPOOiv99NNPo/3Nid+SWK7YfvG79mu3LQBAh6sAAIxFjz76aFw9q05nn312g8evvfbaBo/ffPPN1ccGDx5cvX+FFVZo8Lza5yy33HIN/p500knzPMOGDWtwf1PTdttt1+B177333gaPv/XWW6O8X1NTLGvh3HPPrfTs2bPZeeebb77KBx98UJ3/ww8/rEw99dQtvv5f/vKXPG9sh5bm69evX4v7Y8SIEZUJJ5ywOv+VV17Z4PELL7ywwXb89ttvW3y9r776qsH777HHHpWyiW3S3OeoULtdG2/Djz76qNK/f/9mt/k444xTOeOMMxo856ijjmr29eIzVfv8+Mw19bypppqqMs888zSY9/TTTx9lneI5hYsvvni0n9XvvvtulGVoaipet/Fr1vr0008riy22WLOvUXwXR6fx9y7eM4wcObLyyCOPVPr06dPsPjzrrLNaXI8ePXpUX6+p35ampiWWWKLB/A8//HDeHy2t5/3339/se7T0+1W7bI239bLLLtvk+2299dYNXu/nn3/O97W0ThtvvHHenr9mf7SkPduoPfvu888/H+V7UUxrrrlmk7/fIX7LVllllRbfb7/99mtxOzRua9Zdd91R9nX8vs8yyyxNvv6pp57a4PWjHZh//vlbXKYNN9yw8tNPPzX7m9vUFOtZu68bf98br8fCCy/8q7YtAMCYoLQUADBWRU/b6L1aZBREGanondtUWanoIRu9TNvqgQceyFkckf0RvVJfeOGFfP8444yT33vxxRfPPWOj5+r333+fnn766dxzOa4nRs396H0a84yupn1kI5x33nnV+6LncfSgDUWP8YcffjgPShw9f0P0So/e5VES6NJLL02ffPJJLskUPXn//e9/53muv/769PHHH+fb8XrRSz7W4/3338+9z2P9Cr/73e9y1srvf//7UcrwhBgYuSXRS3qjjTaqbvfIqth8882rj8ffhdie0SO3JY17x49uO3a2d999N/eobur+5my99da553ix/bbYYovcMz7Gdrn99tvzvt53333zPohe1R0lPisxRamueN34jEQv6Zb85S9/aTD2QnxWogd3rN9jjz1W/R5GVkl8pp944okGva1rx25ozdgbsW0ef/zx6t/xfYvvcPRWj+9ZvGd7xHegcbZI8Z2u/eyHeK/4nkUWQHxvIvspxg+5++6787LF93z//ffP35P4PH/99dfp73//e/X5Ue4ueqbHcyIz6j//+c8oZXcimyX2RSiyBeK1rrvuuvx7E8+N13nttddG+x1si8hIiHJt8803X86qiJ71IW6fdNJJucRbOPnkk3OmQYge97EsMUD6W2+9le+PHvqR+RbbKH63Olp7t1Fb912IbLDa350VVlghT/F9/Oc//9nsMsZ39K677sq3I+shft8iA27YsGF528R7nXbaaek3v/lN/o43JX6LI2tn7bXXzvNHllRj8fse6xfvF/sispWK8oqRYbTOOuvkLJUQZRSL9irEb3Ps6zvvvLOa6RXtQ2TyHXnkkfnveM3ZZpstb7fIYok2I/ZvbJNYj/i+x3rG8zbZZJNm1yP2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ElcXXXRRk71N42BywIABafzxx099+/ZNhxxySHr55Zerr99U2m+kCceyxPzjjTdeLtuxyiqr5ItEANAZom0q7L///mnHHXdMK620UlpzzTXTgQcemDMx/vnPf1Z7SdZmY4Tadq9oW2vb23//+985gyKCIz179kwXXHBBnicyKlZeeeV8MWLiiSfO7eIMM8yQ1l9//QZtdHEsUGRjhGOOOabJsSp+/vnndP755+fjg2hj4zX79euXdtppp9wzs6kLSAcccEB+3ziuWGyxxXJpj+bqb49ujIybb745X3yKklzx3lNNNVXOZqlddgCo7UxQBDFClJa68MILc1sYbfHgwYPTkCFD0vPPP58mnHDCPE+cm0Z7tOKKK+Zz3Th3jXYnzmfvvvvuUTZubTsd58m/+93v0tRTT50mmWSStPbaa+dMy3jNWJbIbujdu3ead95587LUaurcfIsttsjnzbFsyy+/fHrooYdGef/Wts1FG1tkY4QoSd24PW6qjY7/G59/x/FK4/EwmhojI87Pi/tOPPHEUY4TYjsVjxdZmeGll17Kx0xxfBPXBPr06ZPb/HhdhXSgRpSWAuiqLr744ogKVKeW3HvvvdX5+vTpU5lmmmkaPDemqaaaqjJixIjqc4YNG5bnbTxfv379KlNMMUX173jtwqabbjrK/LXT3nvv3WC5Lr300ibnW2SRRZpdt3POOacyzjjjNPsehxxySIdtYwBorc0226zaFs0999yVIUOGVIYPH97kvCussEKL7WXRtkabW9w355xzNpjn9NNPz/NMO+20zb5Ojx49Ktdff/0oxwJNTbFM4dtvv62suOKKzc432WSTVR577LHquvz888+VVVZZpcn37t+/f/XvwYMHN3kMU7xv+OWXXyrbbrtts++97rrr+kACMIpod4u2YqWVVhrtFho5cmRlvfXWa7FdPP744xs8p/axueaaa5T5Z5111squu+7a5Gs9/PDD1depbY+jTZ1hhhlGmX+88car3HfffdXntKVtbnydoPFUtMdHHXXUKPfF/y09N1678XFMcd+dd95ZvW+BBRZosO2uuuqq6mPLLbdc9f4bb7yxMv744zf7fltuuWU+NgAqFRkZQF2p7SFSTLWDiBZGjBiRMyyuvPLKXCuzKD/1ySef5PsKe++9d543TD/99LkX5HXXXZef+9lnnzW5DOuss04677zzcmbEvffem3uyRE+Y6EkZzj777DR8+PB8++uvv0577bVX9blLL710HoD0L3/5S3rjjTeafP0ozbHnnnvmQdwiXfiwww7LPVSjZ0r0SgnR++Oee+75FVsSANouMi8Kr7zyStpss81yz86ZZpop91KMtrHoWXjWWWela6+9dpQSkcUUmYqNvfbaa7lH5T/+8Y90zTXX5EFLi0E4o42ObI/o5XnHHXekE044IT8W7xclrkK8Zrz2GmusUX3NeL3iPWOZih6a0YYXvTDjWCHa2l133bU6SHmsTwxkHqKn6V133ZVvx7HH73//+/Svf/0r964sBhVvrcgyKXp2ho022igfe8S2O/zww3PPVwBoXGox2t3CqquuOtoNdM455+RzzxCZGMcee2y17SrEuWZttmWtjz/+OJ/nRhtYlHmMrIg4F95jjz3ya8X5beHPf/5zk68TbWqcj0e7fvXVV+fxJsKPP/6Ydt555+pxQ1va5kGDBuV2vXZw70MPPbTa3sd6NScea1yyOo5XiufGazcnskOLsTQi8yWyVgq11xl22GGH6jaMKhHff/99/jvW5fbbb0+XX355zjQJsX1jXYHGXXwBupjR9bSo7a3ZuBfm0KFDq69T22tkv/32y/d9/PHHDea/4YYbqvM///zzTfYaDZ988knloIMOqiy44IKViSaaKPfGbLxMt9xyS573uuuua9DjpLbX6tlnn93gOYX999+/el/0/nzggQeq0/bbb199LHrFAsDYtvvuuzfZ9tVmFBQ9C996660m27patRkZG2ywQZPzvPDCC5Vtttkm9wTt3bt3k+9bm3FZ29syemPWimWbeuqpq4+fdtppDdra6aefvvrY7bffnp+z1lprVe9bZ511GrzeoosuOkpvz5YyMmrnX3/99du1DwDoXt57770Gbd4FF1ww2ucMGDCgOv+ee+7Z4LHatmi33Xar3l/7Hueee271/kGDBlXvX3zxxav3X3vttQ0qDhQan5vH+XXhiSeeaPDYU0891a62ubmsiVpNZWQ0ta5xvNJYc699zDHHVO8/8MAD832ffvpppVevXvm+qPjwzTff5PvPOuusBhkctet02GGHVR9bcsklR7s/oTvoKZoD1Ptg31FnsrGoTRm1qwtRi7NQZFoUg5UWokZlYf7558/jX0Svj1oxmGnMV9sbpimff/55tWdpYfbZZ0/TTjtt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UFoCGQAAAAAAQGkJZAAAAAAAAKUlkAEAAAAAAJSWQAYAAAAAAFBaAhkAAAAAAEBpCWQAAAAAAAClJZABAAAAAACUlkAGAAAAAABQWgIZAAAAAABAaQlkAAAAAAAApSWQAQB0ip9++intscceafLJJ09TTDFF2nPPPdPIkSObnHfiiSduME055ZQNHv/f//6X1ltvvXz/VFNNlTbZZJP08ccft/rxeO++ffumPn36pBlnnDHts88+6ccffxyDaw8A9d12N257Bw8e3ODxN954I62xxhr5taLtPfnkkxs8vtFGG6Xpp58+t82zzjprOu6446qPvfrqq2n99ddP0003XZpsssnSMssskx566KExtNYA0D3b7k022SR98sknrW67X3zxxbTyyivnx6ON3nnnndO3337bYJ6//e1vae65504TTTRRmmWWWdLNN9/c6nURyOgiBg4cmC+qAEC9iAsSDz74YD7YeeGFF9IDDzyQTjjhhCbn/frrrxtMceBTa/fdd8////e//01vvfVW+v7779Nee+3V6sd322239PLLL6cRI0akZ599Nk+ND8oAoLtrS9vduO394Ycfqo/9/PPPaZ111kmLLLJI+uijj9I999yTzj777HTllVdW5znqqKPS22+/ndvm//znP/mxv//97/mxL774Il9IGTZsWPr000/TtttumwYNGtTgYgsAkH5V2x3nzQceeGCr2+4tttgin6t/+OGHuY2O8+o//OEP1cf/+te/plNPPTUNGTIkn9c/9thjacEFF2z1bhLIKDm9QQGoVxdddFE6/PDDc2/LmA477LB04YUXjvZ5Q4cOzUGHWm+++WbuLRLZGpNMMknadNNN84FTax+fd955c4+QUKlU0jjjjJNee+21Dl1fAOhObXfjtneDDTaoPvbKK6/kKYIVvXr1yhc9dthhh3yBoxAXNnr37p1v9+jRo0HbvPjii+denlNPPXUad9xx00477ZT/f+6558b4NgCA7tJ2b7rppjkAEqINHl3bHc/faqut0njjjZfb6Ah8FOfdEQg58sgj05lnnpkGDBiQ2/Zpp502zTbbbK1eF4GM0bjuuuvyAdQEE0yQ02pWWWWV9M033+QeH5FqExGs2OiRznrsscfm1Jzf//73OVVnpplmShdffHGD1zvooIPSXHPNlSaccMK8o4444oic4lM4+uijU//+/XOaTaTPjj/++Pm9ogdK7OjYyTFFzxQA6Ko+//zz9N577+U2rxC333nnnfTll1+2+Nw46Prtb3/b4L799tsvXXvttfm50UvzqquuSmuvvXarHw8nnXRSPmCbZpppcs+RSLkFANrXdjdue+PcuvDLL79UOw/U3tc4EBEZk3HuPPPMM+eem3Fu3JS4SPLVV1+l+eabz+4CgA5qu+O8efXVV291233AAQekyy67LH333Xdp+PDh6cYbb6yed0cQJDI1nnrqqVxSKq6bR0eEyLxsLYGMFnzwwQdp8803T9tvv3166aWX0n333Zd7kRQ7LFJo3n///XT//fen0047LUek1lprrVwHLFJjdt1117TLLrvkD0wholmXXHJJjmZFYOKCCy5Ip59+eoP3ff3119P111+fbrjhhvTMM8/k+ZZaaqm8c2OZYoo63gDQVcXFiBAdAQrF7bgQ0ZzoTBBpqNtss02D+6M2dqS3FnU/44DtkEMOafXj4eCDD87LFW10tOFR0xMAaF/b3bjtjQsihejFGRcxomdmlJyKUhfRY7TxxYxzzz03v+/jjz+e2/54rcbidTfbbLN06KGHarsBoAPb7jhvjuBGmHPOOUfbdkfZxyhjFde/I/sjrl/HdfXw2Wef5f/vuuuu9MQTT+Rr3lG+at99902tJZDRgggYRIZFBC9iR0VmRvQIid6aIXbon//853wQFjsl/o8BTOIAKnZuXCCJVJrYgYVI5Vl66aXz60VEKiJV11xzzSjlpCJ6FWk2Cy20UJp00knz60RPlLioElOkzTYlPkjxAaqdAKBsira0thdIcTsOepoTvUOiPVxttdUa9AKJDI046CrG0Ijbq666aqsebyzKTC288MLN9vrsaNpuAOqt7W6q7V1iiSWqj0dJihjc8+mnn86DhW655ZZpu+22y1UQGouSUosuumh+jzh/rhXvH8cEyy67bK5uMLZouwHoDm33Msssk9Zff/1Wtd0R9IhKRtERP66PR+AiyjdHqanaZYnr5TGQeExx+9Zbb231+ghktCAuYsRI6xHA2HjjjXP2ROyUwvzzz58PqgpRYqp2gJIINsTOjEhW4eqrr84fgghGxA6MwEak89Tq169friPWHieeeGIOfBSTzA0Ayih6eEQqafTCKMTtaLei/WpOlF4cPHhw6tmzZ/W+OECKwchi8O4IcsQUZaEiOzIG/Rzd402Jso9ja4wMbTcA9dZ2N9X2RrWCEINzF+fT//73v3NbHK8TwYEVVlih2fdv3DYXQYx4nfPOOy+XYB5btN0AdIe2e88998zZE4WW2u433ngjl5SK50eH/HjvaPv/+c9/5scjASCGUPg1BDJaEIGIO++8M91222251uZZZ52VN3qkvRSRqFpx4NTUfUUNsUceeSRHqwYNGpT+8Y9/5AhWDLDSeEDvYrDR9ohIVhzQFdO7777b7tcCgDEpem8cf/zxuXZmTDHu1I477tjs/FFT8+GHH84DitWKnhxzzDFHOuecc9L333+fp7gdB2xFT4+WHo+eJjGmVZSmiPKRUWf7uOOOa5D1MSZpuwGot7a7qbY3OgaGoudm1NSOkpFxPhxllYvBSENcSIlyy9FGx/l0tP9RDaFom6PyQNTsjvEno5PD2AxiBG03AN2h7T7nnHNy9kWhpbZ7nnnmyZ32oyxkVDiK0lXR9kfFoRDjT0d2xh//+MecKBDn33F73XXXbfW6CGSMRhwQRQbFMccckwMPEVGKgUraIw6+ItsigheRGhvlp+IArTXifWN099Hp3bt36tOnT4MJAMroiCOOyGNARSmnmKK9jfKMIcaoiKnxIN/LLbdcbj8bixTXGDQsDrKiFufQoUPTLbfc0qrHo62/8sor0+yzz57Ta+NAas0110xnnHFGGhu03QDUY9vduO198sknG7xWlFiOQbyjx+Ypp5ySbrrpplxauRDtcHQ6iFreUco5eoXGeFYhzskfffTRHOyIc964cBLTFVdcMVa2g7YbgO7Qdg8dOjQP+N2atjva4SgTFfNHUCSGVYhgxaWXXtqgbZ9hhhnSrLPOmpMF4jp5jDvdWj0qtUON00CUnLj77rtzDe1pppkm/x2Ro9hJUSIqdkbcLgwcODCP/F574SN22j777JOnuGCy4YYbpssvvzwttthiObUmAiQRoCgGPou6nvGatSk/Yeedd873xQcmPhgxPkdtWavmRE+VSBVa7Yo1U68JG2aLAMDYcut67esEMLr2LbIP6y1or+0GoB7bb203AIx5t9bxubeMjBbEzrn//vtzKahIWY1UmVNPPTWPwN4e66yzTh6JfY899sgBj8jQiKhYa8SgZlHqKkpcxfgZjcfVAAAAAACAeiQjo87p1QlAGdRzr5COpu0GoCxkZLSOthuAsri1js+9ZWQAAAAAAAClJZABAAAAAACUlkAGAAAAAABQWgIZAAAAAABAaQlkAAAAAAAApSWQAQAAAAAAlJZABgAAAAAAUFoCGQAAAAAAQGkJZAAAAAAAAKUlkAEAAAAAAJSWQAYAAAAAAFBaAhkAAAAAAEBpCWQAAAAAAAClJZABAAAAAACUlkAGAAAAAABQWgIZAAAAAABAaQlkAAAAAAAApSWQAQAAAAAAlJZABgAAAAAAUFoCGQAAAAAAQGkJZAAAAAAAAKUlkAEAAAAAAJSWQAYAAAAAAFBaPTt7ARg7rlnrytSnTx+bGwC6CG03AHQt2m4AGHNkZAAAAAAAAKUlkAEAAAAAAJSWQAYAAAAAAFBaAhkAAAAAAEBpCWQAAAAAAAClJZABAAAAAACUlkAGAAAAAABQWgIZAAAAAABAaQlkAAAAAAAApSWQAQAAAAAAlJZABgAAAAAAUFoCGQAAAAAAQGkJZAAAAAAAAKUlkAEAAAAAAJRWz85eAMaOta/5NvWc0O6GMe3uLSa0kYEOoe0G+HUclzG2abupF34/gTKSkQEAAAAAAJSWQAYAAAAAAFBaAhkAAAAAAEBpCWQAAAAAAAClJZABAAAAAACUlkAGAAAAAABQWgIZAAAAAABAaQlkAAAAAAAApSWQAQAAAAAAlJZABgAAAAAAUFoCGQAAAAAAQGkJZAAAAAAAAKUlkAEAAAAAAJSWQAYAAAAAAFBaAhkAAAAAAEBpCWQAAAAAAAClJZABAAAAAACUlkAGAAAAAABQWgIZAAAAAABAaQlkAAAAAAAApSWQAQAAAAAAlJZABgAAAAAAUFoCGQAAAAAAQGkJZDRy3333pR49eqQvvvii1Rtx2223Teutt15H75tOex+gY/30009pjz32SJNPPnmaYoop0p577plGjhzZ4nO+++67NMccc6TJJpuswf1HHHFEWnDBBVPPnj3TPvvs0+zzn3/++TTeeOON8psRv28TTjhhmnjiifO08MIL/8q1AwCov2Oy4lipmHr16pUWWmih/NgPP/yQdtpppzTrrLOmSSaZJM0zzzzpoosuqj73o48+SltuuWWaaaaZUp8+fdKAAQPSLbfc0uD133///TRo0KA00UQTpZlnnjldcMEFY3jtAcbO72c81rdv3/z7N+OMM+bz1h9//LH6+IsvvphWXnnl/FrTTTdd2nnnndO3335bfXzgwIGpd+/eDX6D4zezMGLEiLTFFlvk15922mnTH/7wB7sWugmBjEaWXnrp9MEHH6RJJ5201RvxzDPPTJdccklH7xugThx33HHpwQcfzAdsL7zwQnrggQfSCSec0OJzjjzyyNSvX79R7o/gxsknn5zWWWedZp/7yy+/5JPrZZZZpsnHH3744fT111/n6dlnn23HGgEA1PcxWXGsVEzzzjtv2myzzfJjcfFu+umnT3fddVe+oBbngvvvv3/697//XX1uBC8effTR3EHu2GOPTZtvvnl+30L8HRfwIuhx7bXXpt///vfpP//5z1jaEgBj7vdzt912Sy+//HL+fYzzzZjiHLYQQYi55547ffjhh2nYsGH58cbBiD/+8Y8NfoNnmGGGBoGSzz77LL3zzjt5OSIQfNlll9ml0A0IZDQSPZjjgDJ6LbdWBD0a95oGKEQPvcMPPzyf8MZ02GGHpQsvvLDZDfTkk0+m22+/PR100EGjPDZ48OC0xhpr5N4nzfnzn/+cT7ZXWGEFOwEAoJ3HZIWhQ4fmi3eRIR8iiyKCE7PPPns+b1xyySXTiiuumC/yhdlmmy0dcMABOSNjnHHGSWuvvXa+aBeBjfDGG2/keU888cT8WksssUTO4KjN6gDoqr+fcS4av22hUqnk38HXXnut+vibb76Zttpqq3z9beqpp86d9CKg0RqRuTFkyJAcWInrcHPNNVcObLTmtxzo+uo+kBEpafGjFqlskbYWaWcRrf3mm2/Sdtttl1OBo4fzbbfd1mRpqehdEz+Od9xxR/4xjpS21VdfPWdtNFfyqa3vGX7++ee0ww475PTkCSaYIB/oRqYH0LV9/vnn6b333kv9+/ev3he3o/fIl19+Ocr80cMvsinOOeecfGDXVv/973/zb8ef/vSnZueJMgZxwBjpvMUJNQBAPWvrMVmtuEAWHUlqewTX+v7773Owoyg91VhkXbz00kvVx5977rl8ITDOE2uXJe4HqIffz5NOOilfP5tmmmlyxkVcIytEoDcyKKKc8vDhw9ONN96YA761IlARJawiu6022+KVV17JZaoaL4vfT+ge6j6QES699NI01VRT5YPL+PH83e9+lzbeeONcRuqpp55Kq666atp6660b1OSrFfefcsop6fLLL0/3339//rGOH96OfM8oBRM9diKtOHr7RFmZQw89NF1zzTVtWteo1xrpe7UT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AAAAAEpLIAMAAAAAACgtgQwAAAAAAKC0BDIAAAAAAIDSEsgAAAAAAABKSyADAAAAAAAoLYEMAAAAAACgtHp29gIwdvz9739PE0wwgc0NjDXbbbedrQ2/grYb6Cq0+fB/tN1APdLOUxYyMgAAAAAAgNISyAAAAAAAAEpLIAMAAAAAACgtgQwAAAAAAKC0BDIAAAAAAIDSEsgAAAAAAABKSyADAAAAAAAoLYEMAAAAAACgtAQyAAAAAACA0hLIAAAAAAAA6ieQsdJKK6UvvvhilPtHjBiRHwMAAAAAAOi0QMZ9992Xfvzxx1Hu//7779MDDzzQUcsFAAAAAACQerZ2Gzz33HPV2y+++GIaPnx49e+ff/453X777WnGGWe0SQEAAAAAgLEfyOjfv3/q0aNHnpoqITXBBBOks846q+OWDAAAAAAA6PZaHch46623UqVSSbPNNlsaOnRomnrqqauPjTfeeGmaaaZJ4447brffoAAAAAAAQCcEMvr165f//+WXXzrw7QEAAAAAADogkFHrtddeS/fee2/66KOPRglsHHnkke15SQAAAAAAgF8fyLjgggvS7373uzTVVFOl6aabLo+ZUYjbAhkAAAAAAECnBTKOO+64dPzxx6eDDjqowxYCAAAAAACgKeOkNvr888/Txhtv3NanAQAAAAAAjPlARgQx/v3vf7f9nQAAAAAAAMZ0aak55pgjHXHEEenRRx9NCy64YOrVq1eDx/faa6+2viQAAAAAAEDHBDL++te/poknnjj95z//yVOtGOxbIAMAAAAAAOi00lJvvfVWs9Obb77ZYQvWlW277bZpvfXW6+zFACiVn376Ke2xxx5p8sknT1NMMUXac88908iRI5v9HR1vvPFy4LyYHnnkkerj8dy+ffumPn36pBlnnDHts88+6ccff6w+/uKLL6aVV145v9d0002Xdt555/Ttt99WH3/yySfTsssum58/22yzpcsuu2wMrz0AdB9tafPDLbfckvr3758mmmiiNMMMM6TzzjtvlHk+/PDD/FoxX633338/DRo0KD935plnThdccEH1sR9++CENHDgwTTPNNLnNn2eeeXLHPACgPO383/72tzT33HPnx2eZZZZ088035/sfeOCBBtcEYhpnnHEadKJ/8MEH05JLLpkmnXTSfG3gkEMOSb/88ovdW6faHMgoxAWjV155pcUPKgAUjjvuuHyQEUGGF154IR+UnHDCCc1uoN122y19/fXX1WmppZZq8NjLL7+cRowYkZ599tk8nXzyydXHt9hii3wgFBc9hg0blh//wx/+kB/74osv8gWPrbbaKn3++efpqquuygdesWwAwNht82+//fbcrp9xxhm5XY/5I/jQWFwwGTBgwCj3b7755rnTwkcffZSuvfba9Pvf/75aOaBnz57prLPOysGOeO0bbrghl0mO5QEAOr+djw4Gp556ahoyZEg+73/sscfyUAZhueWWa3BN4I033kjjjjtu2myzzfLjP//8c1p33XXz9Nlnn6WHHnoov05tpwa6eSAjerTusMMOacIJJ0zzzz9/euedd/L9cRHopJNOSl1Fbc9dAMa8iy66KB1++OFp+umnz9Nhhx2WLrzwwna91rzzzpt7a4RKpZJ7Zbz22mvVxyNDMAIVkdUx9dRTp3XWWScHNMLDDz+cevfunXbdddd8ELTEEkukDTbYIPcCAQDGbpsfgYUjjzwyX9SIdjl6d0bmRK3omRkXKLbeeusG98cFjbiQcuKJJ+bjgmjTt9xyy/z+IV4vLoZEQKMohRzT66+/bjcDQCe38xGIiMfOPPPM3Fkh2uhpp502V01oyqWXXprmnHPOtPTSS+e/v/zyy3x8MHjw4Pzakc2xyiqrVM/9qT9tDmREik70bL3vvvvS+OOPX70/PihXX311Kqv4wkQvnig/MtVUU6XVVlstnXbaafnANg56o0RJ0fu3cMkll6TJJpss3XHHHfmiWaQwrb766umDDz6ozhNfuv322y/PN+WUU6YDDzwwX1SrFSnNkfYUKc2xzaKcyeOPP159PLZlfFnjfeKLO8EEE6SVVlop9yq67bbb8ntHKnT0MK4tjQLQVUTmw3vvvdegHETcjmB4HHw0Jco9RZpqBM2jh0bj9NAInsfvcvy2RrsUAfXCAQcckJ//3XffpeHDh6cbb7wxrb322vmxeJ3Gv9Nx33PPPdfBaw0A3U9b2vxvvvkml3v83//+l+aaa66cWbHxxhs3ON+K58T5VlPlpqLtjgsocdGj9r0at+lrrbVWPg+bb7758rzrr79+B681AHQPHdnOR6WfqKLw1FNP5SDETDPNlHbaaaecudFcACU61xfiesH222+fgyhR7io6ONx1111pzTXXHGPrTxcLZNx0003p7LPPzhfj4+J7IS40xQemzCJyF71zI9UoDoSjB++f//znnNYUj91zzz05EFErAgennHJKuvzyy9P999+fv5hxgawQF9ci4BFfpugNFJHAuGBWK17z+uuvz+8RX8455pgjB1Ji3lpHH3103rbRW/jdd99Nm2yySU69uvLKK9M///nP9O9//zunRrckgibxha+dADpbESSOoG+huP3VV1+NMn8Ef+Og5uOPP84HJdFDI6ZaBx98cH7dSGeN7Io4KCqsscYa+Td5kkkmyRc4IlgdBzghSlTFAVX83sbBTrQJ8bvt95LOou0GumubHxdDonNBnGPeeeedOVMisiYjq7L2XCrGzooemE29V+37FO/V+H3+8Y9/5LY/OpBtuOGGueMY/BrabqC76sh2vrguGsGHJ554Ij3zzDN5DOZ99913lPeN8lVReWGbbbZpcH9cO43yVNG2x/XW6LwQndCpT20OZMRFpej92lgcGNYGNsooDn6jhnrUTY8psjNWXHHFHPWLDIio8XbNNdc0eE5c5Iqgx6KLLpoWWWSRnNVx9913Vx+PQENkqURZksiciHljgJna7fKXv/wl/elPf8oX1qIXUNRqiy9Y47SreP9lllkmZ2VEhDFqu8Zz4++oC7fRRhule++9t8V1jLTqeP9iiot3AJ0tMidCbQ+N4nYEGxqL39soCRXpoTFwVwQtmsv6i9/ehRdeOF/kKA6WIkswenJEMDoOjiLzrjhYiuy5W2+9NQeJI/gRr73ddtvl+6EzaLuB7trmF/NGB4Z+/frlv4855ph8zhPnUXHRIjocHHTQQc2+V+Pen/F3U8cWcUyxwgor5J6fcW4Gv4a2G+iuOrKdLx6P66pRPSemuB3n643FNdQoGR3XCQrR+THGxzj99NPT999/n8fEeumll/I5PvWpzYGMuKAf2QGFIngRtcVrB2Ito9/85jcN/o6I38orr5xHtY8vW9Rc/fTTTxuUb4qxQGafffbq39GzN0o+FV/USIeKWqyFqL8a26gQWSoRDIkARaFXr15p8cUXz1+uWgsttFD1dqQ8x3vX1oWL+4r3bk584WO5iikyOwA6W9TBjDTR6GFRiNsRbK0N/jYnMuhaEr+zxRgZ8bsbJaXiYCmy8OK9d9lllwZtV/wmR/Zb/ObHRZIoPxUXN6AzaLuB7trmRw/OmWeeucnXiR6c0YEsel/OMMMM+eJGlJF8/vnn8+04D4vzp7hoUXuOFO9VDBI6umMGaC9tN9BddWQ7H53Ma4ctaE5UT7j22mvTjjvu2OD+GAsjliU6fsf12LhmG+Nl1J77080DGTEK/aGHHpp+97vfpZEjR+ZSH6uuumq6+OKL0/HHH5/KrBgYNrz99ts53SgOfqPsU9RsO+ecc0YZCDyCDrUicNO4tnpHqX2veJ+m3rtxjfjGIkUrxtOonQDKILIeop2IoEFM0Z40PhApRHZcHKzE722kmMZ4GFEKokhljTbniy++yI/HwUtktEXJvhADh0XPjnPPPTe3U5HeGplwkd1WePrpp3NJgAh4xGNRaiKy9KAzaLuB7tzm77zzzrl8btTPjnb52GOPzZ3Noi2PsTFeffXVfIEkpngsLnrE7agSEB3OonNCnJ9GZ7ShQ4emK664olo/O+aLUhbxunFMEBc24vHimAHaS9sNdGcd1c5HtZqonPDHP/4xV1aIc/y4HVkWta666qpcQSGuPzfusB4dGqJ0VVwvjSpCMTRA7bk/3TyQEWNjxAFhHAhGT5cYtyEOIh955JFRMh7KLAIX8SGPMS6ibEkMOhMf/raISGNE+x577LHqfbFd4rULcXBdjMtR2wsoBvuOMlMA3cURRxyRM/eiFFRMxYWHEGNcxFSI8Sui50Zky2255ZZpt912S/vvv381qBtloeL3NR6Pg5wYzCtK/YU4IIpU1DjYiR6bUT4wDohinKJCjI8UWW6Rlho9O2KMpOjtCQCM3TY/yj/EBY0oExm9OSMgERchQnTKip6WxRS9QKOzV9yOUlEh2vu4OBJtenR6iFLCRZZlnJvF+0abHxdA4vZpp52WtthiC7sZADq5nQ9xHh/n4rPOOmvurBAlqKKtblxWKoInjSs1xHOGDBmSgyNxjLDAAgvka9RRaor61KMyptILSmbgwIGpf//+1Qtdzz77bPXvtddeOwcaIj00DoIjChjpTzGId/TQjQtghYjyrb/++tWsjIgUxsFyfKmiF3B82eJLFGNuxLwhXiMulMU8cWEu5r/lllty+ZP4okVP4Biro3jf0NR7x2Dg8Zq16VujEz2aI+AS2SYGtQPGpjjQgDGlaN+ijGK9ZR9qu4GuRptPa2i7Abom7Xz3NqJE594927PwTYkespFeGdkHXUFEAiPoEIGICGAsv/zyecCubbbZpk2vEz2Eoz5r1GCLyOD222+fAx21g95ESZTI/ogxOKLESYyhcccdd+QgBgAAAAAA0IEZGXGxvhjguymR5rvtttumo446arSDszLm6dUJdBa9NuguvUI6mrYb6Gq0+bSGthuga9LOd28junJGRpQ8Ouyww3KwYvHFF8/3xaBqUXv88MMPzwOrnHLKKTk7o6iPBgAAAAAAMFYCGRGwiAGyN9lkk+p9McZEDPx9/vnnp7vvvjuPAxGj1wtkAAAAAAAAv0abaz89/PDDacCAAaPcH/c98sgj+fayyy6b3nnnnV+1YAAAAAAAAG0OZPTt2zddeOGFo9wf98Vj4dNPPzWQNQAAAAAAMPZLS8X4FxtvvHG67bbb0mKLLZbve+KJJ9JLL72Urr/++vz3448/njbddNNfv3QAAAAAAEC31uZAxjrrrJNeeeWVdN5556VXX30137fGGmukm266KX399df579/97ncdv6QAAAAAAEC30+ZARphlllnSSSedlG+PGDEiXXXVVTkDIzIzfv75545eRgAAAAAAoJtq8xgZhfvvvz8NHjw4zTDDDOnUU09NK664Ynr00Uc7dukAAAAAAIBurU0ZGcOHD0+XXHJJHtg7MjE22WST9MMPP+SyUvPNN9+YW0oAAAAAAKBbanVGxtprr53mnnvu9Nxzz6Uzzjgjvf/+++mss84as0sHAAAAAAB0a63OyLjtttvSXnvtlQfynnPOOcfsUgEAAAAAALQlI+PBBx9MX331VfrNb36TllhiiXT22WenTz75xEYEAAAAAAA6P5Cx5JJLpgsuuCB98MEHaZdddklDhgzJA33/8ssv6c4778xBDgAAAAAAgE4JZBQmmmiitP322+cMjWHDhqX9998/nXTSSWmaaaZJ66yzTocuHAAAAAAA0L21OZBRKwb/Pvnkk9N7772Xrrrqqo5bKgAAAAAAgF8byCiMO+64ab311ku33HKLjQoAAAAAAJQrkAEAAAAAADAmCGQAAAAAAAClJZABAAAAAACUlkAGAAAAAABQWgIZAAAAAABAaQlkAAAAAAAApSWQAQAAAAAAlFbPzl4Axo6tttoq9enTx+YGgC5C2w0AXYu2GwDGHBkZAAAAAABAaQlkAAAAAAAApSWQAQAAAAAAlJZABgAAAAAAUFoCGQAAAAAAQGkJZAAAAAAAAKUlkAEAAAAAAJSWQAYAAAAAAFBaAhkAAAAAAEBpCWQAAAAAAAClJZABAAAAAACUlkAGAAAAAABQWgIZAAAAAABAaQlkAAAAAAAApSWQ0V1cNGlnLwEA0Na2+/wethkAAADdnkAGAAAAAABQWgIZAAAAAABAaQlkAAAAAAAApSWQAQAAAAAAlJZABgAAAAAAUFoCGQAAAAAAQGkJZAAAAAAAAKUlkAEAAAAAAJSWQAYAAAAAAFBaAhkAAAAAAEBpCWQAAAAAAAClJZABAAAAAACUlkAGAAAAAABQWgIZAAAAAABAaQlkAAAAAAAApSWQAQAAAAAAlJZABgAAAAAAUFoCGQAAAAAAQGkJZAAAAAAAAKUlkAEAAAAAAJSWQAYAAAAAAFBaAhkAAAAAAEBpCWQAAAAAAAClJZDRzf30009pjz32SJNPPnmaYoop0p577plGjhzZrnlb+1rfffddmmOOOdJkk01Wve+jjz5KW265ZZpppplSnz590oABA9Itt9wyhtYaALq2sdl+TzzxxA2mXr16pYUWWqj6+LbbbpvGG2+8BvM88sgjY3gLAEC5jc22uqPO1QGgzAQyurnjjjsuPfjgg+nFF19ML7zwQnrggQfSCSec0K55W/taRx55ZOrXr1+D+77++uscvHj00UfTF198kY499ti0+eab59cCADqv/Y42unaad95502abbdbgPXbbbbcG8yy11FJ2GQDd2thsqzvqXB0ASq1CXfvyyy8rsZu/PL3pXT3TTDNVrr322urf11xzTWXmmWdu17ytea0nnniissACC1TuuOOOyqSTTtrisg8YMKBy4YUXtmItAei27duXX1bquu0+rxztd+Gxxx6rjDvuuJX//e9/1fsGDx5c2Xvvvdu4lgB0N92i7a5Zt7HZVndkWw8AZW2/ZWS0wXXXXZcWXHDBNMEEE6Qpp5wyrbLKKumbb77JJRXWW2+9dMwxx6Spp546l0badddd048//lh97u23356WXXbZXE4pnrvWWmulN954o/r422+/nXr06JGuueaatNxyy+X3WGyxxdKrr76aHn/88bTooovmUg1rrLFG+vjjjzskiPX555+n9957L/Xv3796X9x+55130pdfftmmeVvzWpG6utNOO6Vzzjknl6BoSZSaeumllxqUrgAAxn77XevCCy/MxyIzzDBDg/svu+yyXKpi/vnnT6eeemr65Zdf7CoAuq2x2VZ3dFsPAGUlkNFKH3zwQS51tP322+cL7Pfdd1/aYIMNoptkfvzuu++u3n/VVVelG264IQc2ChHw2G+//dITTzyR5x1nnHHS+uuvP8qJ/lFHHZUOP/zw9NRTT6WePXumLbbYIh144IHpzDPPzOmfr7/+ei7N1JwffvghjRgxosHUnCj9EGrHqihuf/XVV22atzWv9ac//SmXj1p++eVb2NIpB4CiZMUmm2ySAzgAUM/a0nZ3RvtdeywzZMiQtOOOOza4f6+99kqvvPJK7mgRgY44ZokJALpr2z022+qObOsBoMwEMtoQyIiMgghezDLLLDkzI+pBR5ZEiAyDiy66KPdEXHPNNfMYD3/+85+rgYoNN9wwPzcGuY7eDzHvsGHDRhkD4oADDkirrbZarj+99957pyeffDIdccQRaZlllslBgB122CHde++9zS7niSeemCaddNLq1Ldv32bnLZa9thdGcXuSSSZp07yjezwCMOedd14OZowuiLHRRhulCSecMF1wwQUtzgsA9aAtbffYbr9rXXvttbl9juOcWossskjOSB133HHTkksumQ4++OB09dVXt2kbAEA9td1js63uyLYeAMpMIKOVFl544bTyyivnAMbGG2+cL7JHimbt43FyX4hBLqPnw7vvvpv/fu2113JGx2yzzZZLT0UwJEQ6Z63aUkrTTjtt/j/es/a+KLvUnEMOOSQflBRT8f5NmXzyydNMM82Unnnmmep9cTsOwuJgrC3zju7xGFjsww8/THPNNVeaaqqp0rrrrpt7rcTtxx57rBrEiG0b/19//fWjLT8FAPWgLW332G6/a/3tb39LgwcPzhmjLYmsUwDozm332GyrO7KtB4Ayc6bZStHL8M4770y33XZbmm+++dJZZ52V5p577vTWW2+16vlrr712+uyzz3IAJC7c1168r9WrV6/q7Rgzo6n7Wqo73bt37xwoqZ1ast1226Xjjz8+DR8+PE8nnHDCKCUjWjtvS49HmajIyogDppjiYkj0/ojbkWny008/5XmibMVNN92U1wMAuoO2tt1js/0uROmohx9+OGeGNhbje0XnhCi3GSU0TzrppJyJCgDdue0em211R7T1AFB2LXepo4EIIkSJp5hinIp+/fqlG2+8MT/27LPPpu+++y4P0h0effTRnMIZvRw+/fTTfAEgghgxkHeIDIUyiLJVsXxRyipstdVW6dBDD823Y8DyECWhRjfv6B6PbJXajJUoQRHbM3qGhP/85z/p5ptvTuOPP37O0ijE82vfAwAYe+13Ica+iGOYOeecc5TNf/bZZ6edd945l+CcccYZc+nN/fff324CoFsbm211R7T1AFB2PSrFaNW0KDIoYpDuVVddNU0zzTT572j8I3sg6kBHKaTIuoiBut9+++08KHj0eojamZFBEc9ZY4018mDeUU4q6kc//vjjORCy3nrr5efMOuus6emnn85jaIQYOHzFFVfMJayKwbguueSStM8++6QvvviiVXssekhGuuiXp6fUZx+7GoD6UG3fvvyyVRkMXUmDtjv6R+yi/Qag6+sWbXcdrhsA3duIErVxMjJaKXbU/fffn84444y8AyMb49RTT83BiQhkxPgZ0Utx+eWXTz/88EMeD+Poo4+u1ooeMmRI2muvvdICCyyQS1LFQOADBw4ck/sWAAAAAAC6PBkZHWDbbbfNGRKRnVE2MjIAqEdl6hXS0WRkAFCPukXbXYfrBkD3NqJEbZzBvgEAAAAAgNISyAAAAAAAAErLGBkdIAbgBgAAAAAAOp6MDAAAAAAAoLQEMgAAAAAAgNISyAAAAAAAAEpLIAMAAAAAACgtgQwAAAAAAKC0BDIAAAAAAIDSEsgAAAAAAABKSyADAAAAAAAoLYEMAAAAAACgtAQyAAAAAACA0hLIAAAAAAAASksgAwAAAAAAKC2BDAAAAAAAoLQEMgAAAAAAgNISyAAAAAAAAEpLIAMAAAAAACgtgQwAAAAAAKC0BDIAAAAAAIDSEsgAAAAAAABKSyADAAAAAAAorZ6dvQCMJdt/aVMDQFdru/v06eylAAAAgE4nIwMAAAAAACgtgQwAAAAAAKC0BDIAAAAAAIDSEsgAAAAAAABKSyADAAAAAAAoLYEMAAAAAACgtAQyAAAAAACA0hLIAAAAAAAASksgAwAAAAAAKC2BDAAAAAAAoLQEMgAAAAAAgNISyAAAAAAAAEpLIAMAAAAAACitnp29AAAAjOqDVVZMX/cc16b5FWZ4eKjtB0CXaLu1WQDQMhkZAAAAAABAaQlkAAAAAAAApSWQAQAAAAAAlJZABgAAAAAAUFoCGQAAAAAAQGkJZAAAAAAAAKUlkAEAAAAAAJSWQAYAAAAAAFBaAhkAAAAAAEBpCWQAAAAAAAClJZABAAAAAACUlkAGAAAAAABQWgIZAAAAAABAaQlkAAAAAAAApSWQAQAAAAAAlJZABgAAAAAAUFoCGQAAAAAAQGkJZAAAAAAAAKUlkAEAAAAAAJSWQAYAAAAAAFBaAhkAAAAAAEBpCWQAAAAAAAClJZABAAAAAACUlkAGAAAAAABQWqUNZLz99tupR48e6ZlnnunsRak7P/30U9pjjz3S5JNPnqaYYoq05557ppEjR7Zr3jH9OABAR2nLccfZZ5+dFl100dS7d++03nrrNXjsnXfeSRNPPHGDqWfPnmmdddapzjNw4MD83Np53n///erjI0aMSFtssUXq06dPmnbaadMf/vAHOxqAdrdbo5s3/u7bt29ud2accca0zz77pB9//FG7BUCXUdpABg3FyXAcaHSE4447Lj344IPpxRdfTC+88EJ64IEH0gknnNCuecf04wAAHaUtxx0zzDBDOvzww9NOO+00ymMzzzxz+vrrr6vTZ599liabbLK02WabNZjvj3/8Y4P54jVrLyjF8yIoEstxwQUXpMsuu8zOBqBd7dbo5t1tt93Syy+/nAPpzz77bJ5OPvlk7RYAXYZAxlhQ28uhDC666KJ8Yj799NPn6bDDDksXXnhhu+Yd048DAHSUthx3bLDBBjkTY6qpphrt6950003pl19+yc9pjW+//TYNGTIkX3SKAMhcc82VAxuOgQBob7s1unnnnXfeNNFEE+XblUoljTPOOOm1117TbgHQZXRqIOP2229Pyy67bD6Bm3LKKdNaa62V3njjjSbnjdT+U045pfp3nFj26tUr924L7733Xi5F9frrr+e/L7/88vycSSaZJE033XQ5df+jjz6qNtpzzDFHg9cLUcaqeI2Y5+ijj8497qIsQPSg22uvvVq1XrPMMksuD7DNNtvktM2dd9453x+9I5Zbbrk0wQQT5JTOeL1vvvmm+rxzzz03zTnnnGn88cfPJQY22mijfP+2226b/vOf/6QzzzwzL19MUXqrPT7//PO8rfr371+9L25Hb8Avv/yyTfOO6ccBADrKmDzuiAtFW265ZT6GqxWBiijvMWDAgAbZFq+88kru6NJ4WZ577rlftRwA1I+OPHcvnHTSSbnU4TTTTJMzMiKIXku7BUCZdWogIy7i77fffumJJ55Id999d+4RsP766+cebY2tsMIK6b777su3I8gQaZIRAIngQIgL/VHnMQIURX3ICCZE4xy95OLCfwQEQgQCtt9++3TxxRc3eI/4e/nll8+vcf3116fTTz89nX/++bmXQrzGggsu2Op1iyDJwgsvnJ5++ul0xBFH5ADN6quvnjbccMN8knr11VfnZY8aliG2QQQ2jj322HxyG0GeWJYQAYyllloqlzb44IMP8hSBkKb88MMPOVW0dqpVBH5i2xWK21999VWb5h3TjwNAdzC6tpuOMaaOO/773/+mu+66K+24444N7j/xxBPz8d+HH36YLxzFxaIbb7yxuizRKzbG1ahdFsc/AF3D2Gi7O/LcvXDwwQfneaP81K677po7fRa0WwCUXacGMuKifqTgR+AgegtEKuSwYcNyo9rUGBFx4f/nn3/OgYDxxhsv93wrghvxfwQ7ChGoWGONNdJss82WllxyyfTnP/853XbbbdUGPoIaETAYOnRoNfBx5ZVX5ueF6LkQjfoqq6ySszIWX3zxJmskN2ellVZK+++/f5p99tnzFAcFsbwxzkVkXSy99NJ5maJ33vfff5/fL05oIyulX79+uedekQEy6aST5vWdcMIJ8zLFNO644zb5vvE+MX8xNQ54RO+LUNsro7gd2SttmXdMPw4A3cHo2m46xpg67oiOMHHcFh1YakUnlNifkUG82mqrpV122SV3ZCmWJcpL1Q7CGsvi+AegaxgbbXdHnrs3FmWmot0qOnsG7RYAZdepgYzIdNh8881zsCFKMEVJphAX9RuLkkzRkyAyHCL7IoIWEdwoAhlxX/xdePLJJ9Paa6+dgxDRcBdBjuK1o1TUmmuumYMn4dZbb829KjbeeOP8d/z/3Xff5WWLAEb0oKs92RydKGtVKzJDLrnkknyAUUxxUhvZJ2+99Vb67W9/mwMY8X5bb711uuKKK/IJblsdcsgh+YClmN59990Gj08++eRppplmymW0CnE7DrziAKwt847pxwGgOxhd203HGBPHHXEcF4GMxtkYTYnM48Lcc8+dAxxxfFi7LG3J/gWgvtvujjx3b0p05mxpjAztFgBl06mBjAg0fPbZZ+mCCy5Ijz32WJ6aGxw70iKjx0AELoqgRZReisDGq6++mhvgIlgRJasiSBDBkQgIPP7449VU/trXjpPOGGgxAhZxErrpppvmrIcQDX5kbMS4FTGmxW677ZbfLxr71igG0SpEJkj0xIuDiWKKk9dY7sjYiGDLU089la666qo8MNeR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3HJp8sknz9Mqq6wy2v1a9nW64YYb0qKLLpomm2yyNNFEE6X+/funyy+/PNXDd6owZMiQ/Blcb731Uldep0suuSSvR+0Uz+vq++mLL75Iu+++e5p++ulT796901xzzVW637+2rNPAgQNH2U8xrbnmmqkr76f4DZ977rnTBBNMkPr27Zv23Xff9P3336d6U49td1dQj21xV1CP7WpXUI/tZFeg3atf2u5yb3Ptduds91ra7bG3zbXZHUOb3QVV6NKGDBlSGW+88SoXXXRR5YUXXqjstNNOlckmm6zy4YcfNjn/Qw89VBl33HErJ598cuXFF1+sHH744ZVevXpVhg0bVumq6zR06NDKAQccULnqqqsq0003XeX000+vlE1b12mLLbaonHPOOZWnn3668tJLL1W23XbbyqSTTlp57733Kl11ne69997KDTfckD93r7/+euWMM87In8Xbb7+9UiZtXa/CW2+9VZlxxhkryy23XGXdddetdOV1uvjiiyt9+vSpfPDBB9Vp+PDhla68Tj/88ENl0UUXrQwaNKjy4IMP5v113333VZ555plKV12nTz/9tME+ev755/N3KvZfV12nK664otK7d+/8f+yjO+64ozL99NNX9t1330o9qce2uyuox7a4K6jHdrUrqMd2sivQ7tUvbXf5t7l2u3O2e0G7Pfa2uTa7Y2izuyaBjC5u8cUXr+y+++7Vv3/++efKDDPMUDnxxBObnH+TTTaprLnmmg3uW2KJJSq77LJLpauuU61+/fqVMpDxa9YpjBw5sjLJJJNULr300kq9rFMYMGBAviBXJu1Zr9g/Sy+9dOVvf/tbZfDgwaW74NLWdYoL4XGxrszauk5/+ctfKrPNNlvlxx9/rJTVr/1OxW9f/E58/fXXla66TjHvSiut1OC+/fbbr7LMMstU6kk9tt1dQT22xV1BPbarXUE9tpNdgXavfmm7y7/NG9Nuj73trt3+dbTZnUOb3TUpLdWF/fjjj+nJJ5/MpQ4K44wzTv77kUceafI5cX/t/GG11VZrdv6usE5l1xHr9O2336affvopTTHFFKke1imCqHfffXd65ZVX0vLLL5/Kor3rdeyxx6Zpppkm7bDDDqls2rtOX3/9derXr18u7bPuuuvmEm5deZ1uueWWtNRSS+WSGdNOO21aYIEF0gknnJB+/vnnVC+/ExdeeGHabLPNcum2rrpOSy+9dH5OkUr95ptv5rImgwYNSvWiHtvurqAe2+KuoB7b1a6gHtvJrkC7V7+03V1jmzem3R5721273X7a7M6hze66enb2AtB+n3zyST65iJONWvH3yy+/3ORzhg8f3uT8cX9XXaey64h1Ouigg9IMM8wwyoWsrrZOX375ZZpxxhnTDz/8kMYdd9x07rnnpt/+9repLNqzXg8++GC+gPzMM8+kMmrPOsX4BBdddFFaaKGF8j475ZRT8gXmCGbMNNNMqSuuU1wQv+eee9KWW26ZL4y//vrrabfddssXJY866qjU1X8n4sL/888/nz+LZdGeddpiiy3y85Zddtkc8Bw5cmTadddd06GHHprqRT223V1BPbbFXUE9tqtdQT22k12Bdq9+abu7xjZvTLs9dra7dvvX0WZ3Dm121yUjA0rupJNOyoNm3XjjjaUccLktJplkknxh4vHHH0/HH3982m+//dJ9992Xuqqvvvoqbb311nlguammmirVi+iRuc022+QB2VdYYYU8UPvUU0+dzj///NRV/fLLL7l371//+tf0m9/8Jm266abpsMMOS+edd16qB3HRLwaAXnzxxVNXFr8H0QM4gpxPPfVU/uz985//TH/4wx86e9Ho5uqpLS6zem1Xu4J6byfLSrsHY4Z2e+zQbncObXbn0GaXg4yMLixO8KJX+4cfftjg/vh7uumma/I5cX9b5u8K61R2v2adoid8HITddddduXd8V1+nSEudY4458u24SP7SSy+lE088MQ0cODB1xfV644030ttvv53WXnvtBgcVoWfPnrl01uyzz566+neqV69eacCAAbl3Zhm0Z52mn376vB7xvMK8886be7RHWul4442Xuup++uabb/IF1kjpLpP2rNMRRxyRL2LuuOOO+e8IzsT67bzzzvmCWvyGdHX12HZ3BfXYFncF9diudgX12E52Bdq9+qXt7hrbvKDdHnvbXbv962mzO4c2u+vq+lcEurE4oYgeUzHWQO3JXvwdPaqbEvfXzh/uvPPOZufvCutUdu1dp5NPPjn3Qr799tvToosumsqko/ZTPCfKTHXV9ZpnnnnSsGHDcpZJMa2zzjppxRVXzLdjfIl62FeRXhzrGRc5yqA967TMMsvkQExxQSy8+uqreZ3KcHHm1+yna6+9Nn+Pttpqq1Qm7VmnqGXcOFhRXFSLUlP1oB7b7q6gHtvirqAe29WuoB7bya5Au1e/tN1dY5sH7fbY3e7a7V9Pm905tNldWGePNs6vM2TIkErv3r0rl1xySeXFF1+s7LzzzpXJJpusMnz48Pz41ltvXTn44IOr8z/00EOVnj17Vk455ZTKSy+9VDnqqKMqvXr1qgwbNqzLrtMPP/xQefrpp/M0/fTTVw444IB8+7XXXqt01XU66aSTKuONN17luuuuq3zwwQfV6auvvqp01XU64YQTKv/+978rb7zxRp4/PoPxWbzgggsqZdLW9Wps8ODBlXXXXbfSldfpmGOOqdxxxx15Xz355JOVzTbbrDL++ONXXnjhhUpXXad33nmnMskkk1T22GOPyiuvvFL5xz/+UZlmmmkqxx13XKWrf/aWXXbZyqabblopo7auU7RJsZ+uuuqqyptvvpl/M2afffbKJptsUqkn9dh2dwX12BZ3BfXYrnYF9dhOdgXavfql7S7/Ntdud852b0y7Pea3uTa7Y2izuyaBjDpw1llnVWaeeeZ8sr344otXHn300epjK6ywQm5Ial1zzTWVueaaK88///zzV/75z39WuvI6vfXWW9FNd5Qp5uuq69SvX78m1ykuXnXVdTrssMMqc8wxR74gPvnkk1eWWmqp3HDUw3eqKxy4tWWd9tlnn+q80047bWXQoEGVp556qtLV99PDDz9cWWKJJfJB4myzzVY5/vjjKyNHjqx05XV6+eWX829DXPAvq7as008//VQ5+uijc/Aifiv69u1b2W233Sqff/55pd7UY9vdFdRjW9wV1GO72hXUYzvZFWj36pe2u9zbXLvdOdu9Me322Nnm2uyOoc3uenrEP52dFQIAAAAAANAUY2QAAAAAAAClJZABAAAAAACUlkAGAAAAAABQWgIZAAAAAABAaQlkAAAAAAAApSWQAQAAAAAAlJZABgAAAAAAUFoCGQAAAAAAQGkJZAAAAAAAAKUlkAEAAAAAAJSWQAYAAAAAAFBaAhkAAAAAAEAqq/8P64QIdBSqlmgAAAAASUVORK5CYII=",
|
| 457 |
+
"text/plain": [
|
| 458 |
+
"<Figure size 1600x500 with 3 Axes>"
|
| 459 |
+
]
|
| 460 |
+
},
|
| 461 |
+
"metadata": {},
|
| 462 |
+
"output_type": "display_data"
|
| 463 |
+
}
|
| 464 |
+
],
|
| 465 |
+
>>>>>>> parent of 99717c2 (Set TASK_HORIZON to 15 days and align graders, UI, and training prompts.)
|
| 466 |
"source": [
|
| 467 |
"# Cell 6: Baseline plots\n",
|
| 468 |
"fig, axes = plt.subplots(1, 3, figsize=(16, 5), sharey=True)\n",
|
|
|
|
| 495 |
},
|
| 496 |
{
|
| 497 |
"cell_type": "code",
|
| 498 |
+
<<<<<<< HEAD
|
| 499 |
+
"metadata": {},
|
| 500 |
+
=======
|
| 501 |
+
"execution_count": 7,
|
| 502 |
"metadata": {},
|
| 503 |
+
"outputs": [
|
| 504 |
+
{
|
| 505 |
+
"name": "stdout",
|
| 506 |
+
"output_type": "stream",
|
| 507 |
+
"text": [
|
| 508 |
+
"Loading Qwen/Qwen2.5-1.5B-Instruct without 4-bit (bitsandbytes/CUDA unavailable).\n",
|
| 509 |
+
" On Colab: run `pip install -U bitsandbytes>=0.46.1` and use a GPU runtime.\n",
|
| 510 |
+
" On Mac: use fp16 on MPS or fp32 on CPU.\n"
|
| 511 |
+
]
|
| 512 |
+
},
|
| 513 |
+
{
|
| 514 |
+
"ename": "KeyboardInterrupt",
|
| 515 |
+
"evalue": "",
|
| 516 |
+
"output_type": "error",
|
| 517 |
+
"traceback": [
|
| 518 |
+
"\u001b[31m---------------------------------------------------------------------------\u001b[39m",
|
| 519 |
+
"\u001b[31mKeyboardInterrupt\u001b[39m Traceback (most recent call last)",
|
| 520 |
+
"\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[7]\u001b[39m\u001b[32m, line 44\u001b[39m\n\u001b[32m 40\u001b[39m \u001b[33m\" On Colab: run `pip install -U bitsandbytes>=0.46.1` and use a GPU runtime.\\n\"\u001b[39m\n\u001b[32m 41\u001b[39m \u001b[33m\" On Mac: use fp16 on MPS or fp32 on CPU.\"\u001b[39m\n\u001b[32m 42\u001b[39m )\n\u001b[32m 43\u001b[39m dtype = torch.float16 \u001b[38;5;28;01mif\u001b[39;00m (torch.cuda.is_available() \u001b[38;5;28;01mor\u001b[39;00m getattr(torch.backends, \u001b[33m\"mps\"\u001b[39m, \u001b[38;5;28;01mNone\u001b[39;00m) \u001b[38;5;28;01mand\u001b[39;00m torch.backends.mps.is_available()) \u001b[38;5;28;01melse\u001b[39;00m torch.float32\n\u001b[32m---> \u001b[39m\u001b[32m44\u001b[39m model = AutoModelForCausalLM.from_pretrained(\n\u001b[32m 45\u001b[39m MODEL_NAME,\n\u001b[32m 46\u001b[39m trust_remote_code=\u001b[38;5;28;01mTrue\u001b[39;00m,\n\u001b[32m 47\u001b[39m dtype=dtype,\n",
|
| 521 |
+
"\u001b[36mFile \u001b[39m\u001b[32m~/viral-posts-env/.venv/lib/python3.14/site-packages/transformers/models/auto/auto_factory.py:394\u001b[39m, in \u001b[36m_BaseAutoModelClass.from_pretrained\u001b[39m\u001b[34m(cls, pretrained_model_name_or_path, *model_args, **kwargs)\u001b[39m\n\u001b[32m 392\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mhasattr\u001b[39m(parent_config, \u001b[33m\"\u001b[39m\u001b[33mquantization_config\u001b[39m\u001b[33m\"\u001b[39m):\n\u001b[32m 393\u001b[39m config.quantization_config = parent_config.quantization_config\n\u001b[32m--> \u001b[39m\u001b[32m394\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[30;43mmodel_class\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43mfrom_pretrained\u001b[39;49m\u001b[30;43m(\u001b[39;49m\n\u001b[32m 395\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mpretrained_model_name_or_path\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43m*\u001b[39;49m\u001b[30;43mmodel_args\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43mconfig\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mconfig\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43m*\u001b[39;49m\u001b[30;43m*\u001b[39;49m\u001b[30;43mhub_kwargs\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43m*\u001b[39;49m\u001b[30;43m*\u001b[39;49m\u001b[30;43mkwargs\u001b[39;49m\n\u001b[32m 396\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 397\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[32m 398\u001b[39m \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mUnrecognized configuration class \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mconfig.\u001b[34m__class__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m for this kind of AutoModel: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mcls\u001b[39m.\u001b[34m__name__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[33m\"\u001b[39m\n\u001b[32m 399\u001b[39m \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mModel type should be one of \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[33m'\u001b[39m\u001b[33m, \u001b[39m\u001b[33m'\u001b[39m.join(c.\u001b[34m__name__\u001b[39m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mfor\u001b[39;00m\u001b[38;5;250m \u001b[39mc\u001b[38;5;250m \u001b[39m\u001b[38;5;129;01min\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28mcls\u001b[39m._model_mapping)\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m.\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 400\u001b[39m )\n",
|
| 522 |
+
"\u001b[36mFile \u001b[39m\u001b[32m~/viral-posts-env/.venv/lib/python3.14/site-packages/transformers/modeling_utils.py:4118\u001b[39m, in \u001b[36mPreTrainedModel.from_pretrained\u001b[39m\u001b[34m(cls, pretrained_model_name_or_path, config, cache_dir, ignore_mismatched_sizes, force_download, local_files_only, token, revision, use_safetensors, weights_only, fusion_config, disable_mmap, *model_args, **kwargs)\u001b[39m\n\u001b[32m 4113\u001b[39m logger.warning_once(\n\u001b[32m 4114\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mA kernel_config was provided but use_kernels is False; setting use_kernels=True automatically. To suppress this warning, explicitly set use_kernels to True.\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 4115\u001b[39m )\n\u001b[32m 4116\u001b[39m use_kernels = \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[32m-> \u001b[39m\u001b[32m4118\u001b[39m checkpoint_files, sharded_metadata = \u001b[30;43m_get_resolved_checkpoint_files\u001b[39;49m\u001b[30;43m(\u001b[39;49m\n\u001b[32m 4119\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mpretrained_model_name_or_path\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mpretrained_model_name_or_path\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 4120\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mvariant\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mvariant\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 4121\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mgguf_file\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mgguf_file\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 4122\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43muse_safetensors\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43muse_safetensors\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 4123\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mdownload_kwargs\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mdownload_kwargs_with_commit\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 4124\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43muser_agent\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43muser_agent\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 4125\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mis_remote_code\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mcls\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43mis_remote_code\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43m)\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 4126\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mtransformers_explicit_filename\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mgetattr\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43mconfig\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43m\"\u001b[39;49m\u001b[30;43mtransformers_weights\u001b[39;49m\u001b[30;43m\"\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43;01mNone\u001b[39;49;00m\u001b[30;43m)\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 4127\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mtqdm_class\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mtqdm_class\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 4128\u001b[39m \u001b[30;43m\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 4130\u001b[39m is_quantized = hf_quantizer \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[32m 4132\u001b[39m \u001b[38;5;66;03m# Find the correct dtype based on current state\u001b[39;00m\n",
|
| 523 |
+
"\u001b[36mFile \u001b[39m\u001b[32m~/viral-posts-env/.venv/lib/python3.14/site-packages/transformers/modeling_utils.py:660\u001b[39m, in \u001b[36m_get_resolved_checkpoint_files\u001b[39m\u001b[34m(pretrained_model_name_or_path, variant, gguf_file, use_safetensors, user_agent, is_remote_code, transformers_explicit_filename, download_kwargs, tqdm_class)\u001b[39m\n\u001b[32m 648\u001b[39m can_auto_convert = (\n\u001b[32m 649\u001b[39m \u001b[38;5;129;01mnot\u001b[39;00m is_offline_mode() \u001b[38;5;66;03m# for obvious reasons\u001b[39;00m\n\u001b[32m 650\u001b[39m \u001b[38;5;66;03m# If we are in a CI environment or in a pytest run, we prevent the conversion\u001b[39;00m\n\u001b[32m (...)\u001b[39m\u001b[32m 653\u001b[39m \u001b[38;5;129;01mand\u001b[39;00m subfolder == \u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m \u001b[38;5;66;03m# converter bot does not work on subfolders\u001b[39;00m\n\u001b[32m 654\u001b[39m )\n\u001b[32m 656\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m 657\u001b[39m \u001b[38;5;66;03m# Load from URL or cache if already cached\u001b[39;00m\n\u001b[32m 658\u001b[39m \u001b[38;5;66;03m# Since we set _raise_exceptions_for_missing_entries=False, we don't get an exception but a None\u001b[39;00m\n\u001b[32m 659\u001b[39m \u001b[38;5;66;03m# result when internet is up, the repo and revision exist, but the file does not.\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m660\u001b[39m resolved_archive_file = \u001b[30;43mcached_file\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43mpretrained_model_name_or_path\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43mfilename\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43m*\u001b[39;49m\u001b[30;43m*\u001b[39;49m\u001b[30;43mcached_file_kwargs\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 662\u001b[39m \u001b[38;5;66;03m# Try safetensors files first if not already found\u001b[39;00m\n\u001b[32m 663\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m resolved_archive_file \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m filename == _add_variant(SAFE_WEIGHTS_NAME, variant):\n\u001b[32m 664\u001b[39m \u001b[38;5;66;03m# Maybe the checkpoint is sharded, we try to grab the index name in this case.\u001b[39;00m\n",
|
| 524 |
+
"\u001b[36mFile \u001b[39m\u001b[32m~/viral-posts-env/.venv/lib/python3.14/site-packages/transformers/utils/hub.py:278\u001b[39m, in \u001b[36mcached_file\u001b[39m\u001b[34m(path_or_repo_id, filename, **kwargs)\u001b[39m\n\u001b[32m 223\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34mcached_file\u001b[39m(\n\u001b[32m 224\u001b[39m path_or_repo_id: \u001b[38;5;28mstr\u001b[39m | os.PathLike,\n\u001b[32m 225\u001b[39m filename: \u001b[38;5;28mstr\u001b[39m,\n\u001b[32m 226\u001b[39m **kwargs,\n\u001b[32m 227\u001b[39m ) -> \u001b[38;5;28mstr\u001b[39m | \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m 228\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m\"\"\"\u001b[39;00m\n\u001b[32m 229\u001b[39m \u001b[33;03m Tries to locate a file in a local folder and repo, downloads and cache it if necessary.\u001b[39;00m\n\u001b[32m 230\u001b[39m \n\u001b[32m (...)\u001b[39m\u001b[32m 276\u001b[39m \u001b[33;03m ```\u001b[39;00m\n\u001b[32m 277\u001b[39m \u001b[33;03m \"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m278\u001b[39m file = \u001b[30;43mcached_files\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43mpath_or_repo_id\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mpath_or_repo_id\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43mfilenames\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43m[\u001b[39;49m\u001b[30;43mfilename\u001b[39;49m\u001b[30;43m]\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43m*\u001b[39;49m\u001b[30;43m*\u001b[39;49m\u001b[30;43mkwargs\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 279\u001b[39m file = file[\u001b[32m0\u001b[39m] \u001b[38;5;28;01mif\u001b[39;00m file \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;28;01melse\u001b[39;00m file\n\u001b[32m 280\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m file\n",
|
| 525 |
+
"\u001b[36mFile \u001b[39m\u001b[32m~/viral-posts-env/.venv/lib/python3.14/site-packages/transformers/utils/hub.py:422\u001b[39m, in \u001b[36mcached_files\u001b[39m\u001b[34m(path_or_repo_id, filenames, cache_dir, force_download, proxies, token, revision, local_files_only, subfolder, repo_type, user_agent, _raise_exceptions_for_gated_repo, _raise_exceptions_for_missing_entries, _raise_exceptions_for_connection_errors, _commit_hash, tqdm_class, **deprecated_kwargs)\u001b[39m\n\u001b[32m 419\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m 420\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(full_filenames) == \u001b[32m1\u001b[39m:\n\u001b[32m 421\u001b[39m \u001b[38;5;66;03m# This is slightly better for only 1 file\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m422\u001b[39m \u001b[30;43mhf_hub_download\u001b[39;49m\u001b[30;43m(\u001b[39;49m\n\u001b[32m 423\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mpath_or_repo_id\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 424\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mfilenames\u001b[39;49m\u001b[30;43m[\u001b[39;49m\u001b[30;43m0\u001b[39;49m\u001b[30;43m]\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 425\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43msubfolder\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43;01mNone\u001b[39;49;00m\u001b[30;43m \u001b[39;49m\u001b[30;43;01mif\u001b[39;49;00m\u001b[30;43m \u001b[39;49m\u001b[30;43mlen\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43msubfolder\u001b[39;49m\u001b[30;43m)\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43m==\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43m0\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43;01melse\u001b[39;49;00m\u001b[30;43m \u001b[39;49m\u001b[30;43msubfolder\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 426\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mrepo_type\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mrepo_type\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 427\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mrevision\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mrevision\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 428\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mcache_dir\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mcache_dir\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 429\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43muser_agent\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43muser_agent\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 430\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mforce_download\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mforce_download\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 431\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mproxies\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mproxies\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 432\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mtoken\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mtoken\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 433\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mlocal_files_only\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mlocal_files_only\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 434\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mtqdm_class\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mtqdm_class\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 435\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 436\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 437\u001b[39m snapshot_download(\n\u001b[32m 438\u001b[39m path_or_repo_id,\n\u001b[32m 439\u001b[39m allow_patterns=full_filenames,\n\u001b[32m (...)\u001b[39m\u001b[32m 448\u001b[39m tqdm_class=tqdm_class,\n\u001b[32m 449\u001b[39m )\n",
|
| 526 |
+
"\u001b[36mFile \u001b[39m\u001b[32m~/viral-posts-env/.venv/lib/python3.14/site-packages/huggingface_hub/utils/_validators.py:88\u001b[39m, in \u001b[36mvalidate_hf_hub_args.<locals>._inner_fn\u001b[39m\u001b[34m(*args, **kwargs)\u001b[39m\n\u001b[32m 84\u001b[39m validate_repo_id(arg_value)\n\u001b[32m 86\u001b[39m kwargs = smoothly_deprecate_legacy_arguments(fn_name=fn.\u001b[34m__name__\u001b[39m, kwargs=kwargs)\n\u001b[32m---> \u001b[39m\u001b[32m88\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[30;43mfn\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43m*\u001b[39;49m\u001b[30;43margs\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43m*\u001b[39;49m\u001b[30;43m*\u001b[39;49m\u001b[30;43mkwargs\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n",
|
| 527 |
+
"\u001b[36mFile \u001b[39m\u001b[32m~/viral-posts-env/.venv/lib/python3.14/site-packages/huggingface_hub/file_download.py:995\u001b[39m, in \u001b[36mhf_hub_download\u001b[39m\u001b[34m(repo_id, filename, subfolder, repo_type, revision, library_name, library_version, cache_dir, local_dir, user_agent, force_download, etag_timeout, token, local_files_only, headers, endpoint, tqdm_class, dry_run)\u001b[39m\n\u001b[32m 974\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m _hf_hub_download_to_local_dir(\n\u001b[32m 975\u001b[39m \u001b[38;5;66;03m# Destination\u001b[39;00m\n\u001b[32m 976\u001b[39m local_dir=local_dir,\n\u001b[32m (...)\u001b[39m\u001b[32m 992\u001b[39m dry_run=dry_run,\n\u001b[32m 993\u001b[39m )\n\u001b[32m 994\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m--> \u001b[39m\u001b[32m995\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[30;43m_hf_hub_download_to_cache_dir\u001b[39;49m\u001b[30;43m(\u001b[39;49m\n\u001b[32m 996\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43;03m# Destination\u001b[39;49;00m\n\u001b[32m 997\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mcache_dir\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mcache_dir\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 998\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43;03m# File info\u001b[39;49;00m\n\u001b[32m 999\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mrepo_id\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mrepo_id\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 1000\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mfilename\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mfilename\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 1001\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mrepo_type\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mrepo_type\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 1002\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mrevision\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mrevision\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 1003\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43;03m# HTTP info\u001b[39;49;00m\n\u001b[32m 1004\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mendpoint\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mendpoint\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 1005\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43metag_timeout\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43metag_timeout\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 1006\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mheaders\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mhf_headers\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 1007\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mtoken\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mtoken\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 1008\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43;03m# Additional options\u001b[39;49;00m\n\u001b[32m 1009\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mlocal_files_only\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mlocal_files_only\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 1010\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mforce_download\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mforce_download\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 1011\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mtqdm_class\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mtqdm_class\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 1012\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mdry_run\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mdry_run\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 1013\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43m)\u001b[39;49m\n",
|
| 528 |
+
"\u001b[36mFile \u001b[39m\u001b[32m~/viral-posts-env/.venv/lib/python3.14/site-packages/huggingface_hub/file_download.py:1213\u001b[39m, in \u001b[36m_hf_hub_download_to_cache_dir\u001b[39m\u001b[34m(cache_dir, repo_id, filename, repo_type, revision, endpoint, etag_timeout, headers, token, local_files_only, force_download, tqdm_class, dry_run)\u001b[39m\n\u001b[32m 1209\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m pointer_path\n\u001b[32m 1211\u001b[39m \u001b[38;5;66;03m# Local file doesn't exist or etag isn't a match => retrieve file from remote (or cache)\u001b[39;00m\n\u001b[32m-> \u001b[39m\u001b[32m1213\u001b[39m \u001b[30;43m\u001b[39;49m\u001b[30;43;01mwith\u001b[39;49;00m\u001b[30;43m \u001b[39;49m\u001b[30;43mWeakFileLock\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43mlock_path\u001b[39;49m\u001b[30;43m)\u001b[39;49m\u001b[30;43m:\u001b[39;49m\n\u001b[32m 1214\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43m_download_to_tmp_and_move\u001b[39;49m\u001b[30;43m(\u001b[39;49m\n\u001b[32m 1215\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mincomplete_path\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mPath\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43mblob_path\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43m+\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43m\"\u001b[39;49m\u001b[30;43m.incomplete\u001b[39;49m\u001b[30;43m\"\u001b[39;49m\u001b[30;43m)\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 1216\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mdestination_path\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mPath\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43mblob_path\u001b[39;49m\u001b[30;43m)\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m (...)\u001b[39m\u001b[32m 1224\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mtqdm_class\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mtqdm_class\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 1225\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 1226\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43;01mif\u001b[39;49;00m\u001b[30;43m \u001b[39;49m\u001b[30;43;01mnot\u001b[39;49;00m\u001b[30;43m \u001b[39;49m\u001b[30;43mos\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43mpath\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43mexists\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43mpointer_path\u001b[39;49m\u001b[30;43m)\u001b[39;49m\u001b[30;43m:\u001b[39;49m\n",
|
| 529 |
+
"\u001b[36mFile \u001b[39m\u001b[32m/opt/homebrew/Cellar/python@3.14/3.14.2_1/Frameworks/Python.framework/Versions/3.14/lib/python3.14/contextlib.py:141\u001b[39m, in \u001b[36m_GeneratorContextManager.__enter__\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 139\u001b[39m \u001b[38;5;28;01mdel\u001b[39;00m \u001b[38;5;28mself\u001b[39m.args, \u001b[38;5;28mself\u001b[39m.kwds, \u001b[38;5;28mself\u001b[39m.func\n\u001b[32m 140\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m--> \u001b[39m\u001b[32m141\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[30;43mnext\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43mself\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43mgen\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 142\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mStopIteration\u001b[39;00m:\n\u001b[32m 143\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mRuntimeError\u001b[39;00m(\u001b[33m\"\u001b[39m\u001b[33mgenerator didn\u001b[39m\u001b[33m'\u001b[39m\u001b[33mt yield\u001b[39m\u001b[33m\"\u001b[39m) \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m\n",
|
| 530 |
+
"\u001b[36mFile \u001b[39m\u001b[32m~/viral-posts-env/.venv/lib/python3.14/site-packages/huggingface_hub/utils/_fixes.py:99\u001b[39m, in \u001b[36mWeakFileLock\u001b[39m\u001b[34m(lock_file, timeout)\u001b[39m\n\u001b[32m 96\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m Timeout(\u001b[38;5;28mstr\u001b[39m(lock_file))\n\u001b[32m 98\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m---> \u001b[39m\u001b[32m99\u001b[39m \u001b[30;43mlock\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43macquire\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43mtimeout\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mmin\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43mlog_interval\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43mtimeout\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43m-\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43melapsed_time\u001b[39;49m\u001b[30;43m)\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43;01mif\u001b[39;49;00m\u001b[30;43m \u001b[39;49m\u001b[30;43mtimeout\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43;01melse\u001b[39;49;00m\u001b[30;43m \u001b[39;49m\u001b[30;43mlog_interval\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 100\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m Timeout:\n\u001b[32m 101\u001b[39m logger.info(\n\u001b[32m 102\u001b[39m \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mStill waiting to acquire lock on \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mlock_file\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m (elapsed: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtime.time()\u001b[38;5;250m \u001b[39m-\u001b[38;5;250m \u001b[39mstart_time\u001b[38;5;132;01m:\u001b[39;00m\u001b[33m.1f\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m seconds)\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 103\u001b[39m )\n",
|
| 531 |
+
"\u001b[36mFile \u001b[39m\u001b[32m~/viral-posts-env/.venv/lib/python3.14/site-packages/filelock/_api.py:513\u001b[39m, in \u001b[36mBaseFileLock.acquire\u001b[39m\u001b[34m(self, timeout, poll_interval, poll_intervall, blocking, cancel_check)\u001b[39m\n\u001b[32m 511\u001b[39m msg = \u001b[33m\"\u001b[39m\u001b[33mLock \u001b[39m\u001b[38;5;132;01m%s\u001b[39;00m\u001b[33m not acquired on \u001b[39m\u001b[38;5;132;01m%s\u001b[39;00m\u001b[33m, waiting \u001b[39m\u001b[38;5;132;01m%s\u001b[39;00m\u001b[33m seconds ...\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 512\u001b[39m _LOGGER.debug(msg, lock_id, lock_filename, poll_interval)\n\u001b[32m--> \u001b[39m\u001b[32m513\u001b[39m \u001b[30;43mtime\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43msleep\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43mpoll_interval\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 514\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m:\n\u001b[32m 515\u001b[39m \u001b[38;5;28mself\u001b[39m._context.lock_counter = \u001b[38;5;28mmax\u001b[39m(\u001b[32m0\u001b[39m, \u001b[38;5;28mself\u001b[39m._context.lock_counter - \u001b[32m1\u001b[39m)\n",
|
| 532 |
+
"\u001b[31mKeyboardInterrupt\u001b[39m: "
|
| 533 |
+
]
|
| 534 |
+
}
|
| 535 |
+
],
|
| 536 |
+
>>>>>>> parent of 99717c2 (Set TASK_HORIZON to 15 days and align graders, UI, and training prompts.)
|
| 537 |
"source": [
|
| 538 |
"# Cell 7: Load model (Qwen2.5-3B bf16 on CUDA + flash-attn-2; fp16/fp32 fallback)\n",
|
| 539 |
"from transformers import AutoTokenizer, AutoModelForCausalLM\n",
|
|
|
|
| 588 |
"# Cell 8: LLM agent functions\n",
|
| 589 |
"SYSTEM_PROMPT = textwrap.dedent(\"\"\"\\\n",
|
| 590 |
"You are an Instagram content strategy agent. Each step is one day.\n",
|
| 591 |
+
"You manage a creator account over a 30-day cycle.\n",
|
| 592 |
"\n",
|
| 593 |
"RESPONSE FORMAT — return ONLY valid JSON, no markdown:\n",
|
| 594 |
"{\n",
|
| 595 |
+
" \"tool_calls\": [{\"name\": \"<tool>\", \"arguments\": {...}}],\n",
|
| 596 |
" \"scheduled_actions\": [\n",
|
| 597 |
+
" {\"hour\": 0-23, \"action_type\": \"post|create_content\",\n",
|
| 598 |
+
" \"content_type\": \"reel|story|carousel|text_post\",\n",
|
| 599 |
+
" \"topic\": \"<string>\", \"tags\": [\"...\"],\n",
|
| 600 |
+
" \"intent\": \"send_bait|save_bait|watch_bait|like_bait\"}\n",
|
| 601 |
" ],\n",
|
|
|
|
| 602 |
" \"notes\": \"strategy notes\"\n",
|
| 603 |
"}\n",
|
| 604 |
"\n",
|
| 605 |
+
"TOOLS (cost in API budget, total=100):\n",
|
| 606 |
+
"- query_trends(niche) cost=1 trending topics+tags for niche\n",
|
| 607 |
+
"- query_audience(segment_id) cost=2 segment topic affinities + active hours\n",
|
| 608 |
+
"- query_competitor(competitor_id, window_days) cost=2 competitor recent posts\n",
|
| 609 |
+
"- query_tag_history(tag) cost=1 your past signals (watch/sends/saves/likes) for a tag\n",
|
| 610 |
+
"- predict_engagement(scheduled_actions) cost=3 simulate a plan WITHOUT committing\n",
|
| 611 |
+
"- draft_review(scheduled_actions) cost=3 AI review of a draft plan\n",
|
| 612 |
+
"- query_creator_pool() cost=1 list collab partners with audience overlap\n",
|
| 613 |
+
"- propose_collab(partner_id, content_type, hour) cost=5 co-author the post at that hour (max 2/month)\n",
|
| 614 |
+
"\n",
|
| 615 |
+
"ACTION SCHEMA:\n",
|
| 616 |
+
"- hour: 0..23 (unlisted hours = rest)\n",
|
| 617 |
+
"- action_type: post (publish) | create_content (build queue, no publish)\n",
|
| 618 |
+
"- content_type: reel | story | carousel | text_post\n",
|
| 619 |
+
"- intent: which Mosseri signal the post optimises for\n",
|
| 620 |
+
" send_bait -> DM shares (strongest discovery signal)\n",
|
| 621 |
+
" save_bait -> bookmarks (content quality)\n",
|
| 622 |
+
" watch_bait -> reels watch time\n",
|
| 623 |
+
" like_bait -> likes from existing followers\n",
|
| 624 |
+
"- tags: up to 5 hashtags\n",
|
| 625 |
+
"- topic: free-form string\n",
|
| 626 |
+
"- empty scheduled_actions = full day rest\"\"\")\n",
|
| 627 |
"\n",
|
| 628 |
"\n",
|
| 629 |
"def format_obs(obs):\n",
|
|
|
|
| 638 |
" tool_str = \"\"\n",
|
| 639 |
" for tr in getattr(obs, \"tool_results\", []):\n",
|
| 640 |
" if tr.success:\n",
|
| 641 |
+
" tool_str += f\" {tr.name}: {json.dumps(tr.data)}\\n\"\n",
|
| 642 |
+
" if not tool_str:\n",
|
| 643 |
+
" tool_str = \" (none)\\n\"\n",
|
| 644 |
" return (f\"Day: {day_name} | days_elapsed={obs.days_elapsed}\\n\"\n",
|
| 645 |
" f\"Energy: {obs.creator_energy:.2f} | Followers: {obs.follower_count}\\n\"\n",
|
| 646 |
" f\"Engagement: {obs.engagement_rate:.3f} | Queue: {obs.content_queue_size}\\n\"\n",
|
| 647 |
" f\"{signals_str}\"\n",
|
| 648 |
+
" f\"Tool results:\\n{tool_str}\"\n",
|
| 649 |
" f\"Plan your actions (JSON only):\")\n",
|
| 650 |
"\n",
|
| 651 |
"\n",
|
|
|
|
| 698 |
" return ViraltestAction(\n",
|
| 699 |
" tool_calls=tool_calls,\n",
|
| 700 |
" scheduled_actions=scheduled,\n",
|
| 701 |
+
<<<<<<< HEAD
|
| 702 |
" replies=data.get(\"replies\", []),\n",
|
| 703 |
+
=======
|
| 704 |
+
>>>>>>> parent of 99717c2 (Set TASK_HORIZON to 15 days and align graders, UI, and training prompts.)
|
| 705 |
" notes=data.get(\"notes\"),\n",
|
| 706 |
" )\n",
|
| 707 |
"\n",
|
|
|
|
| 717 |
" return torch.device(\"cpu\")\n",
|
| 718 |
"\n",
|
| 719 |
"\n",
|
| 720 |
+
<<<<<<< HEAD
|
| 721 |
"def _build_chat(history, prompt):\n",
|
| 722 |
" msgs = [{\"role\": \"system\", \"content\": SYSTEM_PROMPT}]\n",
|
| 723 |
" msgs.extend(history[-14:])\n",
|
|
|
|
| 807 |
"\n",
|
| 808 |
"def run_llm_episode(mdl, tok, task, seed=42, verbose=False):\n",
|
| 809 |
" return run_llm_episodes_batched(mdl, tok, [(task, seed)], verbose=verbose)[0]\n",
|
| 810 |
+
=======
|
| 811 |
+
"def generate_action(mdl, tok, obs, history, temperature=0.7, debug=True):\n",
|
| 812 |
+
" prompt = format_obs(obs)\n",
|
| 813 |
+
" messages = [{\"role\": \"system\", \"content\": SYSTEM_PROMPT}]\n",
|
| 814 |
+
" messages.extend(history[-14:])\n",
|
| 815 |
+
" messages.append({\"role\": \"user\", \"content\": prompt})\n",
|
| 816 |
+
" text_input = tok.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)\n",
|
| 817 |
+
" inputs = tok(text_input, return_tensors=\"pt\").to(_infer_model_device(mdl))\n",
|
| 818 |
+
" with torch.no_grad():\n",
|
| 819 |
+
" out = mdl.generate(**inputs, max_new_tokens=512, temperature=temperature,\n",
|
| 820 |
+
" do_sample=True, top_p=0.9, pad_token_id=tok.eos_token_id)\n",
|
| 821 |
+
" resp = tok.decode(out[0][inputs[\"input_ids\"].shape[1]:], skip_special_tokens=True)\n",
|
| 822 |
+
" if debug:\n",
|
| 823 |
+
" print(\"=\" * 60)\n",
|
| 824 |
+
" print(f\"[LLM PROMPT] tokens={inputs['input_ids'].shape[1]}\")\n",
|
| 825 |
+
" print(prompt)\n",
|
| 826 |
+
" print(\"-\" * 60)\n",
|
| 827 |
+
" print(f\"[LLM RESPONSE] tokens={out.shape[1] - inputs['input_ids'].shape[1]}\")\n",
|
| 828 |
+
" print(resp)\n",
|
| 829 |
+
" print(\"=\" * 60)\n",
|
| 830 |
+
" return resp, parse_model_output(resp)\n",
|
| 831 |
+
"\n",
|
| 832 |
+
"\n",
|
| 833 |
+
"def run_llm_episode(mdl, tok, task, seed=42, verbose=False, debug_llm=True):\n",
|
| 834 |
+
" env = ViraltestEnvironment()\n",
|
| 835 |
+
" obs = env.reset(task=task, seed=seed)\n",
|
| 836 |
+
" rewards, energies = [], [obs.creator_energy]\n",
|
| 837 |
+
" history, pairs = [], []\n",
|
| 838 |
+
" for day in range(1, TASK_HORIZON + 1):\n",
|
| 839 |
+
" if obs.done: break\n",
|
| 840 |
+
" if debug_llm:\n",
|
| 841 |
+
" print(f\"\\n>>> Day {day} | task={task} | energy={obs.creator_energy:.2f}\")\n",
|
| 842 |
+
" resp, action = generate_action(mdl, tok, obs, history, debug=debug_llm)\n",
|
| 843 |
+
" prompt = format_obs(obs)\n",
|
| 844 |
+
" pairs.append({\"prompt\": prompt, \"response\": resp})\n",
|
| 845 |
+
" obs = env.step(action)\n",
|
| 846 |
+
" r = obs.reward or 0.0\n",
|
| 847 |
+
" rewards.append(r)\n",
|
| 848 |
+
" energies.append(obs.creator_energy)\n",
|
| 849 |
+
" history.extend([{\"role\": \"user\", \"content\": prompt},\n",
|
| 850 |
+
" {\"role\": \"assistant\", \"content\": resp}])\n",
|
| 851 |
+
" if verbose:\n",
|
| 852 |
+
" n_p = len([s for s in action.scheduled_actions if s.action_type==\"post\"])\n",
|
| 853 |
+
" print(f\" Day {day:2d}: r={r:.4f} e={obs.creator_energy:.2f} posts={n_p} tools={len(action.tool_calls)}\")\n",
|
| 854 |
+
" if obs.done: break\n",
|
| 855 |
+
" gs = (obs.metadata or {}).get(\"grader_score\", 0.0)\n",
|
| 856 |
+
" # Per-step credit assignment: G_t = r_t + gamma * G_{t+1}, terminal = grader_score * w\n",
|
| 857 |
+
" GAMMA, TERMINAL_W = 0.95, 5.0\n",
|
| 858 |
+
" G, returns = gs * TERMINAL_W, [0.0] * len(rewards)\n",
|
| 859 |
+
" for t in reversed(range(len(rewards))):\n",
|
| 860 |
+
" G = rewards[t] + GAMMA * G\n",
|
| 861 |
+
" returns[t] = G\n",
|
| 862 |
+
" for i, pr in enumerate(pairs):\n",
|
| 863 |
+
" pr[\"return\"] = returns[i] if i < len(returns) else 0.0\n",
|
| 864 |
+
" return {\"task\": task, \"grader_score\": gs, \"total_reward\": sum(rewards),\n",
|
| 865 |
+
" \"final_energy\": obs.creator_energy, \"rewards\": rewards,\n",
|
| 866 |
+
" \"returns\": returns, \"energies\": energies, \"pairs\": pairs,\n",
|
| 867 |
+
" \"follower_delta\": obs.follower_count - 10000,\n",
|
| 868 |
+
" \"burned_out\": obs.creator_energy <= 0}\n",
|
| 869 |
+
>>>>>>> parent of 99717c2 (Set TASK_HORIZON to 15 days and align graders, UI, and training prompts.)
|
| 870 |
"\n",
|
| 871 |
"\n",
|
| 872 |
"print(\"LLM agent functions defined (batched).\")"
|
|
|
|
| 983 |
" f\"<|im_start|>user\\n{pr['prompt']}<|im_end|>\\n\"\n",
|
| 984 |
" f\"<|im_start|>assistant\\n{pr['response']}<|im_end|>\")\n",
|
| 985 |
" all_pairs.append({\"text\": text, \"reward\": pr[\"return\"]})\n",
|
| 986 |
+
<<<<<<< HEAD
|
| 987 |
" kept += 1\n",
|
| 988 |
" print(f\" ep {ep+1}/{EPISODES_PER_ROUND}: {result['task'].split('_')[-1]:>11s} \"\n",
|
| 989 |
" f\"grader={result['grader_score']:.4f} reward={ep_reward:.3f} kept={kept}/{len(result['pairs'])}\")\n",
|
|
|
|
| 995 |
" print(\" WARNING: 0 well-formed pairs collected; skipping SFT.\")\n",
|
| 996 |
" continue\n",
|
| 997 |
"\n",
|
| 998 |
+
=======
|
| 999 |
+
"\n",
|
| 1000 |
+
" rets = result[\"returns\"]\n",
|
| 1001 |
+
" print(f\" ep {ep+1}/{EPISODES_PER_ROUND}: {task.split('_')[-1]:>11s} \"\n",
|
| 1002 |
+
" f\"grader={result['grader_score']:.4f} reward={ep_reward:.3f} \"\n",
|
| 1003 |
+
" f\"return[min={min(rets):.2f} max={max(rets):.2f} mean={np.mean(rets):.2f}]\")\n",
|
| 1004 |
+
"\n",
|
| 1005 |
+
" avg_r = np.mean(episode_rewards)\n",
|
| 1006 |
+
" avg_g = np.mean(episode_graders)\n",
|
| 1007 |
+
" print(f\" Avg reward={avg_r:.3f} Avg grader={avg_g:.4f}\")\n",
|
| 1008 |
+
"\n",
|
| 1009 |
+
" # Filter to top-K by per-pair return (per-step credit assignment)\n",
|
| 1010 |
+
>>>>>>> parent of 99717c2 (Set TASK_HORIZON to 15 days and align graders, UI, and training prompts.)
|
| 1011 |
" threshold = np.percentile([p[\"reward\"] for p in all_pairs], (1 - TOP_K_FRACTION) * 100)\n",
|
| 1012 |
" filtered = [p for p in all_pairs if p[\"reward\"] >= threshold] or all_pairs\n",
|
| 1013 |
" print(f\" Filtered to {len(filtered)}/{len(all_pairs)} samples (return >= {threshold:.3f})\")\n",
|
|
|
|
| 1017 |
" # SFT training (real gradient updates)\n",
|
| 1018 |
" sft_config = SFTConfig(\n",
|
| 1019 |
" output_dir=f\"./checkpoints/round_{round_idx}\",\n",
|
| 1020 |
+
<<<<<<< HEAD
|
| 1021 |
" num_train_epochs=2,\n",
|
| 1022 |
" per_device_train_batch_size=4,\n",
|
| 1023 |
" gradient_accumulation_steps=2,\n",
|
| 1024 |
+
=======
|
| 1025 |
+
" max_steps=7,\n",
|
| 1026 |
+
" per_device_train_batch_size=32,\n",
|
| 1027 |
+
" gradient_accumulation_steps=1,\n",
|
| 1028 |
+
>>>>>>> parent of 99717c2 (Set TASK_HORIZON to 15 days and align graders, UI, and training prompts.)
|
| 1029 |
" learning_rate=2e-5,\n",
|
| 1030 |
+
" warmup_ratio=0.1,\n",
|
| 1031 |
+
" logging_steps=1,\n",
|
| 1032 |
" save_strategy=\"no\",\n",
|
| 1033 |
" max_length=4096,\n",
|
| 1034 |
" bf16=True,\n",
|
| 1035 |
+
<<<<<<< HEAD
|
| 1036 |
+
=======
|
| 1037 |
+
" gradient_checkpointing=False,\n",
|
| 1038 |
+
" dataloader_num_workers=4,\n",
|
| 1039 |
+
" dataloader_pin_memory=True,\n",
|
| 1040 |
+
" optim=\"adamw_torch_fused\",\n",
|
| 1041 |
+
>>>>>>> parent of 99717c2 (Set TASK_HORIZON to 15 days and align graders, UI, and training prompts.)
|
| 1042 |
" report_to=\"none\",\n",
|
| 1043 |
" )\n",
|
| 1044 |
"\n",
|
|
|
|
| 1281 |
"name": "python",
|
| 1282 |
"nbconvert_exporter": "python",
|
| 1283 |
"pygments_lexer": "ipython3",
|
| 1284 |
+
"version": "3.13.1"
|
| 1285 |
}
|
| 1286 |
},
|
| 1287 |
"nbformat": 4,
|
training/train_grpo_smoke.ipynb
CHANGED
|
@@ -1,4 +1,17 @@
|
|
| 1 |
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
"cells": [
|
| 3 |
{
|
| 4 |
"cell_type": "markdown",
|
|
@@ -13,8 +26,8 @@
|
|
| 13 |
},
|
| 14 |
{
|
| 15 |
"cell_type": "code",
|
| 16 |
-
"execution_count": null,
|
| 17 |
"metadata": {},
|
|
|
|
| 18 |
"outputs": [],
|
| 19 |
"source": [
|
| 20 |
"# Cell 1: Minimal deps (quoted versions for zsh / shell safety)\n",
|
|
@@ -24,8 +37,8 @@
|
|
| 24 |
},
|
| 25 |
{
|
| 26 |
"cell_type": "code",
|
| 27 |
-
"execution_count": null,
|
| 28 |
"metadata": {},
|
|
|
|
| 29 |
"outputs": [],
|
| 30 |
"source": [
|
| 31 |
"# Cell 2: Repo path (same logic as main notebook)\n",
|
|
@@ -78,8 +91,8 @@
|
|
| 78 |
},
|
| 79 |
{
|
| 80 |
"cell_type": "code",
|
| 81 |
-
"execution_count": null,
|
| 82 |
"metadata": {},
|
|
|
|
| 83 |
"outputs": [],
|
| 84 |
"source": [
|
| 85 |
"# Cell 3: Core imports + TASK_HORIZON check\n",
|
|
@@ -107,15 +120,15 @@
|
|
| 107 |
" TOPIC_CATEGORIES,\n",
|
| 108 |
")\n",
|
| 109 |
"\n",
|
| 110 |
-
"assert TASK_HORIZON ==
|
| 111 |
"print(\"OK: TASK_HORIZON =\", TASK_HORIZON)\n",
|
| 112 |
"print(\"OK: tags =\", len(TAG_POOL), \"niches =\", len(TOPIC_CATEGORIES))"
|
| 113 |
]
|
| 114 |
},
|
| 115 |
{
|
| 116 |
"cell_type": "code",
|
| 117 |
-
"execution_count": null,
|
| 118 |
"metadata": {},
|
|
|
|
| 119 |
"outputs": [],
|
| 120 |
"source": [
|
| 121 |
"# Cell 4: One minimal episode (syntax + env wiring)\n",
|
|
@@ -160,13 +173,13 @@
|
|
| 160 |
"r = run_episode(\"monthly_engage\", plan_minimal, seed=42)\n",
|
| 161 |
"print(\"Episode result:\", r)\n",
|
| 162 |
"assert r[\"steps\"] == TASK_HORIZON, f\"Expected {TASK_HORIZON} steps, got {r['steps']}\"\n",
|
| 163 |
-
"print(\"OK: full episode completed\")"
|
| 164 |
]
|
| 165 |
},
|
| 166 |
{
|
| 167 |
"cell_type": "code",
|
| 168 |
-
"execution_count": null,
|
| 169 |
"metadata": {},
|
|
|
|
| 170 |
"outputs": [],
|
| 171 |
"source": [
|
| 172 |
"# Cell 5: Optional ML stack (no model download)\n",
|
|
@@ -193,18 +206,5 @@
|
|
| 193 |
"If all cells pass, open `train_grpo.ipynb` and run the full pipeline."
|
| 194 |
]
|
| 195 |
}
|
| 196 |
-
]
|
| 197 |
-
"metadata": {
|
| 198 |
-
"kernelspec": {
|
| 199 |
-
"display_name": ".venv",
|
| 200 |
-
"language": "python",
|
| 201 |
-
"name": "python3"
|
| 202 |
-
},
|
| 203 |
-
"language_info": {
|
| 204 |
-
"name": "python",
|
| 205 |
-
"version": "3.14.2"
|
| 206 |
-
}
|
| 207 |
-
},
|
| 208 |
-
"nbformat": 4,
|
| 209 |
-
"nbformat_minor": 4
|
| 210 |
}
|
|
|
|
| 1 |
{
|
| 2 |
+
"nbformat": 4,
|
| 3 |
+
"nbformat_minor": 4,
|
| 4 |
+
"metadata": {
|
| 5 |
+
"kernelspec": {
|
| 6 |
+
"display_name": "Python 3",
|
| 7 |
+
"language": "python",
|
| 8 |
+
"name": "python3"
|
| 9 |
+
},
|
| 10 |
+
"language_info": {
|
| 11 |
+
"name": "python",
|
| 12 |
+
"version": "3.10.0"
|
| 13 |
+
}
|
| 14 |
+
},
|
| 15 |
"cells": [
|
| 16 |
{
|
| 17 |
"cell_type": "markdown",
|
|
|
|
| 26 |
},
|
| 27 |
{
|
| 28 |
"cell_type": "code",
|
|
|
|
| 29 |
"metadata": {},
|
| 30 |
+
"execution_count": null,
|
| 31 |
"outputs": [],
|
| 32 |
"source": [
|
| 33 |
"# Cell 1: Minimal deps (quoted versions for zsh / shell safety)\n",
|
|
|
|
| 37 |
},
|
| 38 |
{
|
| 39 |
"cell_type": "code",
|
|
|
|
| 40 |
"metadata": {},
|
| 41 |
+
"execution_count": null,
|
| 42 |
"outputs": [],
|
| 43 |
"source": [
|
| 44 |
"# Cell 2: Repo path (same logic as main notebook)\n",
|
|
|
|
| 91 |
},
|
| 92 |
{
|
| 93 |
"cell_type": "code",
|
|
|
|
| 94 |
"metadata": {},
|
| 95 |
+
"execution_count": null,
|
| 96 |
"outputs": [],
|
| 97 |
"source": [
|
| 98 |
"# Cell 3: Core imports + TASK_HORIZON check\n",
|
|
|
|
| 120 |
" TOPIC_CATEGORIES,\n",
|
| 121 |
")\n",
|
| 122 |
"\n",
|
| 123 |
+
"assert TASK_HORIZON == 30, f\"Expected TASK_HORIZON=30, got {TASK_HORIZON}\"\n",
|
| 124 |
"print(\"OK: TASK_HORIZON =\", TASK_HORIZON)\n",
|
| 125 |
"print(\"OK: tags =\", len(TAG_POOL), \"niches =\", len(TOPIC_CATEGORIES))"
|
| 126 |
]
|
| 127 |
},
|
| 128 |
{
|
| 129 |
"cell_type": "code",
|
|
|
|
| 130 |
"metadata": {},
|
| 131 |
+
"execution_count": null,
|
| 132 |
"outputs": [],
|
| 133 |
"source": [
|
| 134 |
"# Cell 4: One minimal episode (syntax + env wiring)\n",
|
|
|
|
| 173 |
"r = run_episode(\"monthly_engage\", plan_minimal, seed=42)\n",
|
| 174 |
"print(\"Episode result:\", r)\n",
|
| 175 |
"assert r[\"steps\"] == TASK_HORIZON, f\"Expected {TASK_HORIZON} steps, got {r['steps']}\"\n",
|
| 176 |
+
"print(\"OK: full monthly episode completed\")"
|
| 177 |
]
|
| 178 |
},
|
| 179 |
{
|
| 180 |
"cell_type": "code",
|
|
|
|
| 181 |
"metadata": {},
|
| 182 |
+
"execution_count": null,
|
| 183 |
"outputs": [],
|
| 184 |
"source": [
|
| 185 |
"# Cell 5: Optional ML stack (no model download)\n",
|
|
|
|
| 206 |
"If all cells pass, open `train_grpo.ipynb` and run the full pipeline."
|
| 207 |
]
|
| 208 |
}
|
| 209 |
+
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 210 |
}
|