RoadSafety-OpenEnv / server /environment.py
Anoopsingh53's picture
Upload environment.py
f96fa35 verified
Raw
History Blame Contribute Delete
5.54 kB
import random
import uuid
import os
import pandas as pd
from typing import Dict, Any
from openenv.core.env_server import Environment
from models import RiderSafetyAction, RiderSafetyObservation, RiderSafetyState
DATASET_PATH = os.path.join(os.path.dirname(__file__), "..", "road_accident_imu_dataset_8000.csv")
class RiderSafetyEnv(Environment):
def __init__(self):
self._state = RiderSafetyState()
self._step_count = 0
self._sequence = []
# Load dataset once
if os.path.exists(DATASET_PATH):
self.df = pd.read_csv(DATASET_PATH)
self.crash_indices = self.df[self.df['Crash_Label'] == 1].index.tolist()
self.normal_indices = self.df[self.df['Crash_Label'] == 0].index.tolist()
else:
self.df = None
def reset(self, seed=None, episode_id=None, task=None, **kwargs) -> RiderSafetyObservation:
self._step_count = 0
self._state = RiderSafetyState()
self._state.episode_id = episode_id or str(uuid.uuid4())
# Determine task difficulty from kwargs or default
task_name = kwargs.get("task", task or "medium").lower()
self._state.task_name = task_name
self._state.target_goal = f"Successfully complete {task_name} task"
# We simulate 3 to 5 step sequences.
self._state.max_turns = random.randint(3, 5)
if self.df is None:
self._sequence = [{"Speed_kmh": 40, "Acc_X": 0, "Acc_Y": 0, "Crash_Label": 0, "Motion_Intensity": 9.8}] * self._state.max_turns
else:
# Pick scenario based on task difficulty
if task_name == "easy":
# Easy: Very obvious crash or purely normal driving.
is_crash = random.choice([True, False])
elif task_name == "medium":
# Medium: High variance normal driving and borderline crashes.
# Biasing towards more crashes
is_crash = random.random() < 0.6
else:
# Hard: Tricky edge cases (e.g. high intensity but no crash, or low intensity crash)
is_crash = random.random() < 0.7
if is_crash and self.crash_indices:
start_idx = max(0, random.choice(self.crash_indices) - self._state.max_turns + 2) # ensure crash is inside sequence
else:
start_idx = random.choice(self.normal_indices)
start_idx = min(start_idx, max(0, len(self.df) - self._state.max_turns))
end_idx = start_idx + self._state.max_turns
self._sequence = self.df.iloc[start_idx:end_idx].to_dict('records')
self._state.crash_occurred = any(row.get('Crash_Label', 0) == 1 for row in self._sequence)
first_obs = self._sequence[0]
return self._create_observation(first_obs, 0.01, False)
def step(self, action: RiderSafetyAction) -> RiderSafetyObservation:
self._step_count += 1
if action.decision == "DISPATCH_SOS":
self._state.sos_dispatched = True
done = self._step_count >= self._state.max_turns
# Default reward should NOT be 0.0 for the validator
reward = 0.01
if done:
reward = self._grade_task()
# Get current data row, simulate transcript based on crash label
obs_idx = min(self._step_count, len(self._sequence)-1)
obs_data = self._sequence[obs_idx]
return self._create_observation(obs_data, reward, done)
def _grade_task(self) -> float:
# Grading logic maps directly to openenv grader requirements (0.0 to 1.0)
is_true_positive = self._state.crash_occurred and self._state.sos_dispatched
is_true_negative = not self._state.crash_occurred and not self._state.sos_dispatched
is_false_alarm = not self._state.crash_occurred and self._state.sos_dispatched
score = 0.0
if self._state.task_name == "easy":
if is_true_positive or is_true_negative: score = 1.0
else: score = 0.0
elif self._state.task_name == "medium":
if is_true_positive or is_true_negative: score = 1.0
elif is_false_alarm: score = 0.2
else: score = 0.0
else: # Hard Task
if is_true_positive or is_true_negative: score = 1.0
else: score = 0.0
# Meta Hackathon Validator requires scores strictly in (0, 1)
# 0.99 for success and 0.01 for failure.
return max(0.01, min(0.99, score))
def _create_observation(self, row: Dict[str, Any], reward: float, done: bool) -> RiderSafetyObservation:
# Generate contextual transcript
transcript = "Normal background noise"
if row.get('Crash_Label', 0) == 1:
transcript = "Loud bang! Tires screeching! Screaming!"
elif row.get('Motion_Intensity', 0.0) > 10.0:
transcript = "Heavy wind, screeching tires"
sensor_summary = f"Speed: {row.get('Speed_kmh', 0):.1f}kmph, "\
f"Motion Intensity: {row.get('Motion_Intensity', 0):.2f}, "\
f"Acc(X/Y/Z): {row.get('Acc_X',0):.2f}/{row.get('Acc_Y',0):.2f}/{row.get('Acc_Z',0):.2f}"
return RiderSafetyObservation(
done=done,
reward=reward,
sensor_summary=sensor_summary,
audio_transcript=transcript
)
@property
def state(self) -> RiderSafetyState:
return self._state