gagan-devv commited on
Commit
e8ac5f7
·
1 Parent(s): 51f7f90

deleted app.py from root directory

Browse files

Signed-off-by: Gagan Ahlawat <gagan.devvv@gmail.com>

Files changed (1) hide show
  1. app.py +0 -498
app.py DELETED
@@ -1,498 +0,0 @@
1
- """
2
- Interactive Gradio UI for Cloud Resource Allocation RL Environment.
3
-
4
- This module provides a web-based interface for manually interacting with the
5
- cloud resource allocation environment. Users can observe system metrics and
6
- take actions to learn about system dynamics before training an RL agent.
7
- """
8
-
9
- from fastapi import FastAPI
10
- from fastapi.responses import JSONResponse
11
- import gradio as gr
12
- import numpy as np
13
- import matplotlib.pyplot as plt
14
- from env.environment import CloudResourceEnv
15
- from env.grader import EpisodeGrader
16
-
17
-
18
- # Initialize environment and grader
19
- env = CloudResourceEnv()
20
- grader = EpisodeGrader()
21
-
22
- # Global state for UI
23
- current_state = None
24
- episode_active = False
25
- cpu_history = []
26
- resource_history = []
27
- step_history = []
28
-
29
-
30
- def create_cpu_plot():
31
- """Create CPU utilization plot over time."""
32
- if not cpu_history:
33
- # Return empty plot if no data
34
- fig, ax = plt.subplots(figsize=(8, 4))
35
- ax.set_xlabel('Step')
36
- ax.set_ylabel('CPU Utilization (%)')
37
- ax.set_title('CPU Utilization Over Time')
38
- ax.grid(True, alpha=0.3)
39
- ax.set_ylim(0, 100)
40
- return fig
41
-
42
- fig, ax = plt.subplots(figsize=(8, 4))
43
- ax.plot(step_history, cpu_history, marker='o', linewidth=2, markersize=4, color='#2E86AB')
44
- ax.axhline(y=70, color='orange', linestyle='--', alpha=0.7, label='Target Max (70%)')
45
- ax.axhline(y=40, color='green', linestyle='--', alpha=0.7, label='Target Min (40%)')
46
- ax.axhline(y=95, color='red', linestyle='--', alpha=0.7, label='Critical (95%)')
47
- ax.set_xlabel('Step')
48
- ax.set_ylabel('CPU Utilization (%)')
49
- ax.set_title('CPU Utilization Over Time')
50
- ax.legend(loc='upper right')
51
- ax.grid(True, alpha=0.3)
52
- ax.set_ylim(0, 100)
53
- plt.tight_layout()
54
- return fig
55
-
56
-
57
- def create_resource_plot():
58
- """Create resource allocation plot over time."""
59
- if not resource_history:
60
- # Return empty plot if no data
61
- fig, ax = plt.subplots(figsize=(8, 4))
62
- ax.set_xlabel('Step')
63
- ax.set_ylabel('Allocated Resources')
64
- ax.set_title('Resource Allocation Over Time')
65
- ax.grid(True, alpha=0.3)
66
- return fig
67
-
68
- fig, ax = plt.subplots(figsize=(8, 4))
69
- ax.plot(step_history, resource_history, marker='s', linewidth=2, markersize=4, color='#A23B72')
70
- ax.set_xlabel('Step')
71
- ax.set_ylabel('Allocated Resources')
72
- ax.set_title('Resource Allocation Over Time')
73
- ax.grid(True, alpha=0.3)
74
- plt.tight_layout()
75
- return fig
76
-
77
-
78
- def reset_environment() -> tuple:
79
- """
80
- Reset the environment to start a new episode.
81
-
82
- Returns:
83
- Tuple of display values for all UI components
84
- """
85
- global current_state, episode_active, cpu_history, resource_history, step_history
86
-
87
- # Reset environment
88
- current_state = env.reset()
89
- episode_active = True
90
-
91
- # Clear history
92
- cpu_history = []
93
- resource_history = []
94
- step_history = []
95
-
96
- # Extract state components
97
- cpu_util = current_state[0]
98
- memory_util = current_state[1]
99
- request_rate = int(current_state[2])
100
- allocated_resources = int(current_state[3])
101
-
102
- # Initialize history with first state
103
- cpu_history.append(cpu_util)
104
- resource_history.append(allocated_resources)
105
- step_history.append(0)
106
-
107
- # Calculate initial latency
108
- latency = request_rate / max(allocated_resources, 1)
109
-
110
- # Determine system status
111
- status = get_system_status(cpu_util, memory_util)
112
-
113
- return (
114
- f"{cpu_util:.2f}%",
115
- f"{memory_util:.2f}%",
116
- str(request_rate),
117
- str(allocated_resources),
118
- f"{latency:.2f} ms", # latency display
119
- "0.00", # cumulative reward
120
- "0", # step count
121
- status,
122
- "", # episode completion message
123
- gr.update(interactive=True), # increase button
124
- gr.update(interactive=True), # decrease button
125
- gr.update(interactive=True), # maintain button
126
- create_cpu_plot(), # CPU plot
127
- create_resource_plot() # Resource plot
128
- )
129
-
130
-
131
- def get_system_status(cpu_util: float, memory_util: float) -> str:
132
- """
133
- Determine system status based on utilization metrics.
134
-
135
- Args:
136
- cpu_util: CPU utilization percentage
137
- memory_util: Memory utilization percentage
138
-
139
- Returns:
140
- Status string indicating system health
141
- """
142
- if cpu_util > 95.0 or memory_util > 95.0:
143
- return "🔴 UNSTABLE - Critical utilization!"
144
- elif cpu_util > 70.0 or memory_util > 70.0:
145
- return "🟡 WARNING - High utilization"
146
- elif cpu_util < 35.0 and memory_util < 35.0:
147
- return "🟢 OVER-PROVISIONED - Excess resources"
148
- else:
149
- return "🟢 NORMAL - Optimal operation"
150
-
151
-
152
- def execute_action(action: int) -> tuple:
153
- """
154
- Execute an action in the environment and update display.
155
-
156
- Args:
157
- action: Action to execute (0: decrease, 1: maintain, 2: increase)
158
-
159
- Returns:
160
- Tuple of display values for all UI components
161
- """
162
- global current_state, episode_active, cpu_history, resource_history, step_history
163
-
164
- if not episode_active:
165
- return get_inactive_episode_display()
166
-
167
- try:
168
- # Execute step
169
- observation, reward, done, info = env.step(action)
170
- current_state = observation
171
-
172
- # Extract state components
173
- cpu_util = observation[0]
174
- memory_util = observation[1]
175
- request_rate = int(observation[2])
176
- allocated_resources = int(observation[3])
177
-
178
- # Update history
179
- cpu_history.append(cpu_util)
180
- resource_history.append(allocated_resources)
181
- step_history.append(info['step'])
182
-
183
- # Get cumulative reward and step count
184
- cumulative_reward = info['cumulative_reward']
185
- step_count = info['step']
186
- latency = info['latency']
187
-
188
- # Determine system status
189
- status = get_system_status(cpu_util, memory_util)
190
-
191
- # Check if episode terminated
192
- if done:
193
- episode_active = False
194
- completion_msg = handle_episode_completion()
195
-
196
- return (
197
- f"{cpu_util:.2f}%",
198
- f"{memory_util:.2f}%",
199
- str(request_rate),
200
- str(allocated_resources),
201
- f"{latency:.2f} ms", # latency display
202
- f"{cumulative_reward:.2f}",
203
- str(step_count),
204
- status,
205
- completion_msg,
206
- gr.update(interactive=False), # disable increase button
207
- gr.update(interactive=False), # disable decrease button
208
- gr.update(interactive=False), # disable maintain button
209
- create_cpu_plot(), # CPU plot
210
- create_resource_plot() # Resource plot
211
- )
212
- else:
213
- return (
214
- f"{cpu_util:.2f}%",
215
- f"{memory_util:.2f}%",
216
- str(request_rate),
217
- str(allocated_resources),
218
- f"{latency:.2f} ms", # latency display
219
- f"{cumulative_reward:.2f}",
220
- str(step_count),
221
- status,
222
- "", # no completion message yet
223
- gr.update(interactive=True),
224
- gr.update(interactive=True),
225
- gr.update(interactive=True),
226
- create_cpu_plot(), # CPU plot
227
- create_resource_plot() # Resource plot
228
- )
229
-
230
- except Exception as e:
231
- # Handle errors gracefully
232
- return get_error_display(str(e))
233
-
234
-
235
- def handle_episode_completion() -> str:
236
- """
237
- Handle episode completion and generate grading report.
238
-
239
- Returns:
240
- Formatted completion message with grading results
241
- """
242
- # Grade the episode
243
- grading_result = grader.grade_episode(
244
- env.episode_states,
245
- env.episode_actions,
246
- env.episode_rewards
247
- )
248
-
249
- # Format completion message
250
- status_emoji = "✅" if grading_result['passed'] else "❌"
251
-
252
- message = f"""
253
- 🏁 **Episode Complete!**
254
-
255
- {status_emoji} **Status**: {'PASSED' if grading_result['passed'] else 'FAILED'}
256
-
257
- **Performance Metrics:**
258
- - Final Score: {grading_result['final_score']:.3f}
259
- - Average Reward: {grading_result['avg_reward']:.3f}
260
- - Stability Score: {grading_result['stability_score']:.3f}
261
- - Efficiency Score: {grading_result['efficiency_score']:.3f}
262
-
263
- **System Metrics:**
264
- - Average CPU: {grading_result['avg_cpu']:.2f}%
265
- - Average Memory: {grading_result['avg_memory']:.2f}%
266
- - Average Latency: {grading_result['avg_latency']:.2f} ms
267
-
268
- **Episode Stats:**
269
- - Total Steps: {len(env.episode_rewards)}
270
- - Cumulative Reward: {env.cumulative_reward:.2f}
271
-
272
- Click **Reset** to start a new episode!
273
- """
274
-
275
- return message
276
-
277
-
278
- def get_inactive_episode_display() -> tuple:
279
- """
280
- Get display values when no episode is active.
281
-
282
- Returns:
283
- Tuple of display values indicating inactive state
284
- """
285
- return (
286
- "N/A",
287
- "N/A",
288
- "N/A",
289
- "N/A",
290
- "N/A", # latency
291
- "0.00",
292
- "0",
293
- "⚪ No active episode",
294
- "Click Reset to start a new episode",
295
- gr.update(interactive=False),
296
- gr.update(interactive=False),
297
- gr.update(interactive=False),
298
- create_cpu_plot(),
299
- create_resource_plot()
300
- )
301
-
302
-
303
- def get_error_display(error_msg: str) -> tuple:
304
- """
305
- Get display values when an error occurs.
306
-
307
- Args:
308
- error_msg: Error message to display
309
-
310
- Returns:
311
- Tuple of display values with error information
312
- """
313
- return (
314
- "ERROR",
315
- "ERROR",
316
- "ERROR",
317
- "ERROR",
318
- "ERROR", # latency
319
- "0.00",
320
- "0",
321
- "🔴 ERROR",
322
- f"⚠️ Error: {error_msg}\n\nClick Reset to recover.",
323
- gr.update(interactive=False),
324
- gr.update(interactive=False),
325
- gr.update(interactive=False),
326
- create_cpu_plot(),
327
- create_resource_plot()
328
- )
329
-
330
-
331
- # Action handler functions
332
- def handle_increase() -> tuple:
333
- """Handle increase action button click."""
334
- return execute_action(CloudResourceEnv.ACTION_INCREASE)
335
-
336
-
337
- def handle_decrease() -> tuple:
338
- """Handle decrease action button click."""
339
- return execute_action(CloudResourceEnv.ACTION_DECREASE)
340
-
341
-
342
- def handle_maintain() -> tuple:
343
- """Handle maintain action button click."""
344
- return execute_action(CloudResourceEnv.ACTION_MAINTAIN)
345
-
346
-
347
- def handle_run_multiple_steps(num_steps: int, action_choice: str) -> tuple:
348
- """
349
- Execute multiple steps with the same action.
350
-
351
- Args:
352
- num_steps: Number of steps to execute
353
- action_choice: Action to repeat ("Increase", "Decrease", or "Maintain")
354
-
355
- Returns:
356
- Tuple of display values for all UI components
357
- """
358
- global episode_active
359
-
360
- if not episode_active:
361
- return get_inactive_episode_display()
362
-
363
- # Map action choice to action integer
364
- action_map = {
365
- "Increase": CloudResourceEnv.ACTION_INCREASE,
366
- "Decrease": CloudResourceEnv.ACTION_DECREASE,
367
- "Maintain": CloudResourceEnv.ACTION_MAINTAIN
368
- }
369
-
370
- action = action_map.get(action_choice, CloudResourceEnv.ACTION_MAINTAIN)
371
-
372
- # Execute multiple steps
373
- for _ in range(int(num_steps)):
374
- if not episode_active:
375
- break
376
- result = execute_action(action)
377
-
378
- return result
379
-
380
-
381
- # Create Gradio interface
382
- with gr.Blocks(title="Cloud Resource Allocation RL") as demo:
383
- gr.Markdown("""
384
- # 🌐 Cloud Resource Allocation RL Environment
385
-
386
- Manually control cloud resource allocation and observe system dynamics.
387
- Learn how actions affect CPU, memory, and system stability before training an RL agent.
388
-
389
- **Actions:**
390
- - **Increase**: Add 1 server instance
391
- - **Decrease**: Remove 1 server instance (minimum 1)
392
- - **Maintain**: Keep current allocation
393
- """)
394
-
395
- with gr.Row():
396
- with gr.Column(scale=1):
397
- gr.Markdown("### 📊 System Metrics")
398
- cpu_display = gr.Textbox(label="CPU Utilization", value="N/A", interactive=False)
399
- memory_display = gr.Textbox(label="Memory Utilization", value="N/A", interactive=False)
400
- request_display = gr.Textbox(label="Request Rate", value="N/A", interactive=False)
401
- resource_display = gr.Textbox(label="Allocated Resources", value="N/A", interactive=False)
402
- latency_display = gr.Textbox(label="Latency", value="N/A", interactive=False)
403
-
404
- with gr.Column(scale=1):
405
- gr.Markdown("### 📈 Episode Progress")
406
- reward_display = gr.Textbox(label="Cumulative Reward", value="0.00", interactive=False)
407
- step_display = gr.Textbox(label="Step Count", value="0", interactive=False)
408
- status_display = gr.Textbox(label="System Status", value="⚪ No active episode", interactive=False)
409
-
410
- # Visualization section
411
- gr.Markdown("### 📉 Real-Time Metrics")
412
- with gr.Row():
413
- cpu_plot = gr.Plot(label="CPU Utilization Over Time")
414
- resource_plot = gr.Plot(label="Resource Allocation Over Time")
415
-
416
- gr.Markdown("### 🎮 Actions")
417
- with gr.Row():
418
- increase_btn = gr.Button("⬆️ Increase Resources", variant="primary", interactive=False)
419
- maintain_btn = gr.Button("➡️ Maintain Resources", variant="secondary", interactive=False)
420
- decrease_btn = gr.Button("⬇️ Decrease Resources", variant="stop", interactive=False)
421
-
422
- # Multi-step execution
423
- gr.Markdown("### ⚡ Run Multiple Steps")
424
- with gr.Row():
425
- num_steps_input = gr.Slider(minimum=1, maximum=20, value=5, step=1, label="Number of Steps")
426
- action_dropdown = gr.Dropdown(
427
- choices=["Increase", "Maintain", "Decrease"],
428
- value="Maintain",
429
- label="Action to Repeat"
430
- )
431
- run_multi_btn = gr.Button("▶️ Run Multiple Steps", variant="secondary")
432
-
433
- gr.Markdown("### 🔄 Episode Control")
434
- reset_btn = gr.Button("🔄 Reset Environment", variant="primary")
435
-
436
- completion_display = gr.Markdown("")
437
-
438
- # Wire up event handlers
439
- outputs = [
440
- cpu_display,
441
- memory_display,
442
- request_display,
443
- resource_display,
444
- latency_display,
445
- reward_display,
446
- step_display,
447
- status_display,
448
- completion_display,
449
- increase_btn,
450
- decrease_btn,
451
- maintain_btn,
452
- cpu_plot,
453
- resource_plot
454
- ]
455
-
456
- reset_btn.click(fn=reset_environment, outputs=outputs)
457
- increase_btn.click(fn=handle_increase, outputs=outputs)
458
- decrease_btn.click(fn=handle_decrease, outputs=outputs)
459
- maintain_btn.click(fn=handle_maintain, outputs=outputs)
460
- run_multi_btn.click(
461
- fn=handle_run_multiple_steps,
462
- inputs=[num_steps_input, action_dropdown],
463
- outputs=outputs
464
- )
465
-
466
- gr.Markdown("""
467
- ---
468
- ### 💡 Tips
469
- - **Optimal Range**: Keep CPU and memory between 40-70% for best rewards
470
- - **Over-Provisioning**: Too many resources waste money (negative rewards)
471
- - **Under-Provisioning**: Too few resources risk system instability (negative rewards)
472
- - **Stochastic Dynamics**: Request rate fluctuates randomly each step
473
- - **Multi-Step Mode**: Use "Run Multiple Steps" to quickly test action sequences
474
- """)
475
-
476
-
477
- if __name__ == "__main__":
478
- # Create FastAPI app
479
- app = FastAPI()
480
-
481
- @app.post("/reset")
482
- async def reset_endpoint():
483
- """Reset endpoint for validator compliance."""
484
- return {"status": "ok"}
485
-
486
- # Mount Gradio interface at root path
487
- app = gr.mount_gradio_app(app, demo, path="/")
488
-
489
- # Run with uvicorn
490
- import uvicorn
491
- import logging
492
-
493
- # Suppress uvicorn access logs to keep stdout clean for inference
494
- # Only errors will be logged to stderr
495
- uvicorn_access_logger = logging.getLogger("uvicorn.access")
496
- uvicorn_access_logger.disabled = True
497
-
498
- uvicorn.run(app, host="0.0.0.0", port=7860, log_level="error")