astroocra commited on
Commit
fcedd47
·
1 Parent(s): 0e0bc53

server/app.py

Browse files
Files changed (1) hide show
  1. server/app.py +186 -4
server/app.py CHANGED
@@ -11,7 +11,11 @@ except Exception as exc:
11
  ) from exc
12
 
13
  from server.env import EcoLLMInferenceRoutingEnvironment
 
14
  from server.models import RLAction, RLObservation
 
 
 
15
 
16
  # ✅ CRITICAL: Use create_app() - this creates the /reset, /step, /state endpoints
17
  app = create_app(
@@ -22,8 +26,10 @@ app = create_app(
22
  max_concurrent_envs=4,
23
  )
24
 
 
25
  @app.get("/")
26
  <<<<<<< HEAD
 
27
  def root():
28
  return {"status": "ok", "service": "eco_llm_inference_routing"}
29
 
@@ -41,10 +47,26 @@ async def root():
41
  # OPTIONAL: Gradio UI (does NOT interfere with API)
42
  # ══════════════════════════════════════════════════════════════════════════════
43
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  try:
45
  import gradio as gr
46
  from gradio.routes import mount_gradio_app
47
 
 
48
  def reset_demo(task_id: str, state: dict)
49
  })
50
 
@@ -52,6 +74,137 @@ try:
52
  # 🌱 Eco-LLM Inference Routing Environment
53
  **Carbon-aware LLM query routing** — balance accuracy, energy, latency & carbon footprint.
54
  """)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
  with gr.Row():
57
  task_selector = gr.Dropdown(
@@ -59,11 +212,14 @@ try:
59
  value="task_1",
60
  label="Task",
61
  )
62
- reset_btn = gr.Button("🔄 Reset Episode", variant="primary")
63
 
 
64
  obs_box = gr.Textbox(label="Environment State", lines=8, interactive=False)
 
 
 
65
 
66
- gr.Markdown("### Take an Action")
67
  with gr.Row():
68
  strategy_dd = gr.Dropdown(
69
  choices=["NONE", "USE_CACHE", "DO_CASCADE", "EARLY_EXIT", "WAIT", "CALL_KB"],
@@ -75,6 +231,7 @@ try:
75
  value="SMALL",
76
  label="Model",
77
  )
 
78
  exit_cb = gr.Checkbox(label="exit_flag", value=False)
79
 
80
  step -> tuple:
@@ -203,32 +360,49 @@ try:
203
  ### Reward Formula
204
  `reward = score − (carbon_intensity × energy_cost) − (0.1 × latency) + bonuses`
205
  """)
 
 
 
 
 
 
 
206
 
207
  reset_btn.click(
208
  reset_demo,
209
  inputs=[task_selector],
 
210
  outputs=[obs_box, reward_breakdown, total_reward_num, demo_state],
 
 
 
211
  )
212
  step_btn.click(
213
  step_demo,
214
  inputs=[strategy_dd, model_dd, exit_cb, demo_state],
215
- outputs=[obs_box, reward_breakdown, total_reward_num, demo_state],
216
  )
217
 
218
  app = mount_gradio_app(app, demo, path="/ui")
 
219
 
220
  except ImportError:
221
  print("⚠️ Gradio not installed - API only mode")
 
 
 
222
  pass
223
 
224
 
225
  def main(host: str = "0.0.0.0", port: int = 7860) -> None:
226
  """Run the server."""
227
  import uvicorn
228
- uvicorn.run(app, host=host, port=port)
 
229
 
230
 
231
  if __name__ == "__main__":
 
232
  import
233
  value="task_1",
234
  label="Task"
@@ -267,3 +441,11 @@ if __name__ == "__main__":
267
 
268
  # Mount Gradio at /ui (
269
 
 
 
 
 
 
 
 
 
 
11
  ) from exc
12
 
13
  from server.env import EcoLLMInferenceRoutingEnvironment
14
+ <<<<<<< HEAD
15
  from server.models import RLAction, RLObservation
16
+ =======
17
+ from server.models import ModelChoice, RLAction, RLObservation, Strategy
18
+ >>>>>>> cb2c156 (Fix OpenEnv app startup and serializable Gradio state)
19
 
20
  # ✅ CRITICAL: Use create_app() - this creates the /reset, /step, /state endpoints
21
  app = create_app(
 
26
  max_concurrent_envs=4,
27
  )
28
 
29
+
30
  @app.get("/")
31
  <<<<<<< HEAD
32
+ <<<<<<< HEAD
33
  def root():
34
  return {"status": "ok", "service": "eco_llm_inference_routing"}
35
 
 
47
  # OPTIONAL: Gradio UI (does NOT interfere with API)
48
  # ══════════════════════════════════════════════════════════════════════════════
49
 
50
+ =======
51
+ def root() -> dict[str, str]:
52
+ return {
53
+ "status": "ok",
54
+ "service": "eco_llm_inference_routing",
55
+ "ui": "/ui",
56
+ }
57
+
58
+
59
+ @app.get("/health")
60
+ def health() -> dict[str, str]:
61
+ return {"status": "healthy"}
62
+
63
+
64
+ >>>>>>> cb2c156 (Fix OpenEnv app startup and serializable Gradio state)
65
  try:
66
  import gradio as gr
67
  from gradio.routes import mount_gradio_app
68
 
69
+ <<<<<<< HEAD
70
  def reset_demo(task_id: str, state: dict)
71
  })
72
 
 
74
  # 🌱 Eco-LLM Inference Routing Environment
75
  **Carbon-aware LLM query routing** — balance accuracy, energy, latency & carbon footprint.
76
  """)
77
+ =======
78
+ def _serialize_env_state(env: EcoLLMInferenceRoutingEnvironment) -> dict[str, object]:
79
+ state = env.state
80
+ return {
81
+ "task_id": state.task_id,
82
+ "step_count": state.step_count,
83
+ "step_index": state.step_index,
84
+ "query_index": state.query_index,
85
+ "total_energy": float(state.total_energy),
86
+ "total_latency": float(state.total_latency),
87
+ "cache_contents": list(state.cache_contents),
88
+ "carbon_history_index": state.carbon_history_index,
89
+ }
90
+
91
+ def _restore_env_state(
92
+ env: EcoLLMInferenceRoutingEnvironment,
93
+ serialized_state: dict[str, object],
94
+ ) -> None:
95
+ env._state.task_id = str(serialized_state["task_id"])
96
+ env._state.step_count = int(serialized_state["step_count"])
97
+ env._state.step_index = int(serialized_state["step_index"])
98
+ env._state.query_index = int(serialized_state["query_index"])
99
+ env._state.total_energy = float(serialized_state["total_energy"])
100
+ env._state.total_latency = float(serialized_state["total_latency"])
101
+ env._state.cache_contents = list(serialized_state["cache_contents"])
102
+ env._state.carbon_history_index = int(serialized_state["carbon_history_index"])
103
+
104
+ def reset_demo(task_id: str) -> tuple[str, str, float, dict[str, object]]:
105
+ demo_env = EcoLLMInferenceRoutingEnvironment()
106
+ obs = demo_env.reset(task_id=task_id)
107
+ updated_state = {
108
+ "task_id": task_id,
109
+ "env_state": _serialize_env_state(demo_env),
110
+ "history": [],
111
+ "total_reward": 0.0,
112
+ "episode_active": True,
113
+ }
114
+ log = (
115
+ f"Reset task: {task_id}\n"
116
+ f"Difficulty: {demo_env.current_task.difficulty}\n"
117
+ f"Query: {obs.query}\n"
118
+ f"Carbon intensity: {obs.carbon_intensity:.2f}\n"
119
+ f"Cache: {obs.cache_contents or 'empty'}\n"
120
+ f"KB available: {obs.kb_available}"
121
+ )
122
+ return log, "", 0.0, updated_state
123
+
124
+ def step_demo(
125
+ strategy: str,
126
+ model: str,
127
+ exit_flag: bool,
128
+ state: dict[str, object],
129
+ ) -> tuple[str, str, float, dict[str, object]]:
130
+ if not state.get("episode_active") or not state.get("env_state"):
131
+ return "Click Reset first.", "", 0.0, state
132
+
133
+ demo_env = EcoLLMInferenceRoutingEnvironment()
134
+ demo_env.reset(task_id=str(state["task_id"]))
135
+ _restore_env_state(demo_env, dict(state["env_state"]))
136
+
137
+ obs = demo_env._build_observation(
138
+ reward=demo_env._empty_reward(["restored"]),
139
+ done=demo_env._episode_complete,
140
+ )
141
+ if obs.done:
142
+ return (
143
+ "Episode complete. Click Reset to start again.",
144
+ "",
145
+ round(float(state.get("total_reward", 0.0)), 3),
146
+ state,
147
+ )
148
+
149
+ action = RLAction(
150
+ strategy=Strategy(strategy),
151
+ model_choice=ModelChoice(model),
152
+ exit_flag=exit_flag,
153
+ )
154
+ new_obs = demo_env.step(action)
155
+ reward = new_obs.reward_details
156
+ total_reward = float(state.get("total_reward", 0.0)) + reward.total_reward
157
+
158
+ history = list(state.get("history", []))
159
+ history.append(
160
+ f"Step {len(history) + 1}: {strategy}+{model} reward={reward.total_reward:+.3f}"
161
+ )
162
+
163
+ log = "\n".join(history) + "\n\n"
164
+ if new_obs.done:
165
+ log += "Episode complete."
166
+ else:
167
+ log += (
168
+ f"Query: {new_obs.query}\n"
169
+ f"Carbon intensity: {new_obs.carbon_intensity:.2f}\n"
170
+ f"Cache: {new_obs.cache_contents or 'empty'}\n"
171
+ f"KB available: {new_obs.kb_available}"
172
+ )
173
+
174
+ breakdown = (
175
+ f"score={reward.score:.1f} "
176
+ f"energy={reward.energy_cost:.2f} "
177
+ f"carbon={reward.carbon_penalty:.3f} "
178
+ f"latency={reward.latency_penalty:.3f} "
179
+ f"bonuses={reward.bonuses:.2f} "
180
+ f"total={reward.total_reward:+.3f}"
181
+ )
182
+ updated_state = {
183
+ "task_id": str(state["task_id"]),
184
+ "env_state": _serialize_env_state(demo_env),
185
+ "history": history,
186
+ "total_reward": round(total_reward, 3),
187
+ "episode_active": not new_obs.done,
188
+ }
189
+ return log, breakdown, round(total_reward, 3), updated_state
190
+
191
+ with gr.Blocks(title="Eco-LLM Routing Demo") as demo:
192
+ demo_state = gr.State(
193
+ {
194
+ "task_id": "task_1",
195
+ "env_state": None,
196
+ "history": [],
197
+ "total_reward": 0.0,
198
+ "episode_active": False,
199
+ }
200
+ )
201
+ gr.Markdown(
202
+ """
203
+ # Eco-LLM Inference Routing
204
+ API-first OpenEnv app with an optional local demo.
205
+ """
206
+ )
207
+ >>>>>>> cb2c156 (Fix OpenEnv app startup and serializable Gradio state)
208
 
209
  with gr.Row():
210
  task_selector = gr.Dropdown(
 
212
  value="task_1",
213
  label="Task",
214
  )
215
+ reset_btn = gr.Button("Reset", variant="primary")
216
 
217
+ <<<<<<< HEAD
218
  obs_box = gr.Textbox(label="Environment State", lines=8, interactive=False)
219
+ =======
220
+ obs_box = gr.Textbox(label="State", lines=8, interactive=False)
221
+ >>>>>>> cb2c156 (Fix OpenEnv app startup and serializable Gradio state)
222
 
 
223
  with gr.Row():
224
  strategy_dd = gr.Dropdown(
225
  choices=["NONE", "USE_CACHE", "DO_CASCADE", "EARLY_EXIT", "WAIT", "CALL_KB"],
 
231
  value="SMALL",
232
  label="Model",
233
  )
234
+ <<<<<<< HEAD
235
  exit_cb = gr.Checkbox(label="exit_flag", value=False)
236
 
237
  step -> tuple:
 
360
  ### Reward Formula
361
  `reward = score − (carbon_intensity × energy_cost) − (0.1 × latency) + bonuses`
362
  """)
363
+ =======
364
+ exit_cb = gr.Checkbox(label="Exit flag", value=False)
365
+
366
+ step_btn = gr.Button("Step")
367
+ reward_box = gr.Textbox(label="Reward", interactive=False)
368
+ total_num = gr.Number(label="Total reward", interactive=False)
369
+ >>>>>>> cb2c156 (Fix OpenEnv app startup and serializable Gradio state)
370
 
371
  reset_btn.click(
372
  reset_demo,
373
  inputs=[task_selector],
374
+ <<<<<<< HEAD
375
  outputs=[obs_box, reward_breakdown, total_reward_num, demo_state],
376
+ =======
377
+ outputs=[obs_box, reward_box, total_num, demo_state],
378
+ >>>>>>> cb2c156 (Fix OpenEnv app startup and serializable Gradio state)
379
  )
380
  step_btn.click(
381
  step_demo,
382
  inputs=[strategy_dd, model_dd, exit_cb, demo_state],
383
+ outputs=[obs_box, reward_box, total_num, demo_state],
384
  )
385
 
386
  app = mount_gradio_app(app, demo, path="/ui")
387
+ <<<<<<< HEAD
388
 
389
  except ImportError:
390
  print("⚠️ Gradio not installed - API only mode")
391
+ =======
392
+ except ImportError: # pragma: no cover
393
+ >>>>>>> cb2c156 (Fix OpenEnv app startup and serializable Gradio state)
394
  pass
395
 
396
 
397
  def main(host: str = "0.0.0.0", port: int = 7860) -> None:
398
  """Run the server."""
399
  import uvicorn
400
+
401
+ uvicorn.run(app, host=host, port=port, log_level="info")
402
 
403
 
404
  if __name__ == "__main__":
405
+ <<<<<<< HEAD
406
  import
407
  value="task_1",
408
  label="Task"
 
441
 
442
  # Mount Gradio at /ui (
443
 
444
+ =======
445
+ import argparse
446
+
447
+ parser = argparse.ArgumentParser()
448
+ parser.add_argument("--port", type=int, default=7860)
449
+ args = parser.parse_args()
450
+ main(port=args.port)
451
+ >>>>>>> cb2c156 (Fix OpenEnv app startup and serializable Gradio state)