Spaces:
Sleeping
Sleeping
Upload folder using huggingface_hub
Browse files- inference.py +20 -42
- models.py +9 -7
- server/app.py +0 -1
- server/environment.py +27 -37
inference.py
CHANGED
|
@@ -1,55 +1,33 @@
|
|
| 1 |
import os
|
| 2 |
-
import sys
|
| 3 |
from openai import OpenAI
|
| 4 |
from client import SupportEnvClient, SupportAction
|
| 5 |
|
| 6 |
-
# Hackathon defined variables
|
| 7 |
API_BASE_URL = os.getenv("API_BASE_URL", "https://router.huggingface.co/v1")
|
| 8 |
MODEL_NAME = os.getenv("MODEL_NAME", "Qwen/Qwen2.5-72B-Instruct")
|
| 9 |
-
API_KEY = os.getenv("HF_TOKEN") or os.getenv("
|
| 10 |
-
|
| 11 |
|
| 12 |
client = OpenAI(base_url=API_BASE_URL, api_key=API_KEY)
|
| 13 |
|
| 14 |
def run_task(task_name: str):
|
| 15 |
-
|
| 16 |
-
|
|
|
|
| 17 |
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
)
|
| 33 |
-
action_str = completion.choices[0].message.content.strip().replace('.', '')
|
| 34 |
-
except Exception as e:
|
| 35 |
-
action_str = "Tech" # Fallback
|
| 36 |
-
|
| 37 |
-
result = env.step(SupportAction(department=action_str))
|
| 38 |
-
reward_val = float(result.reward or 0.0)
|
| 39 |
-
rewards.append(reward_val)
|
| 40 |
-
|
| 41 |
-
print(f"[STEP] step={step} action={action_str} reward={reward_val:.2f} done={str(result.done).lower()} error=null", flush=True)
|
| 42 |
-
step += 1
|
| 43 |
-
if step > 10: break # Safety break
|
| 44 |
-
|
| 45 |
-
score = sum(rewards)
|
| 46 |
-
success = "true" if score >= 0.99 else "false"
|
| 47 |
-
rewards_str = ",".join([f"{r:.2f}" for r in rewards])
|
| 48 |
-
|
| 49 |
-
print(f"[END] success={success} steps={step-1} score={score:.2f} rewards={rewards_str}", flush=True)
|
| 50 |
-
finally:
|
| 51 |
-
env.close()
|
| 52 |
|
| 53 |
if __name__ == "__main__":
|
| 54 |
-
for task in ["easy", "medium", "hard"]:
|
| 55 |
-
run_task(task)
|
|
|
|
| 1 |
import os
|
|
|
|
| 2 |
from openai import OpenAI
|
| 3 |
from client import SupportEnvClient, SupportAction
|
| 4 |
|
|
|
|
| 5 |
API_BASE_URL = os.getenv("API_BASE_URL", "https://router.huggingface.co/v1")
|
| 6 |
MODEL_NAME = os.getenv("MODEL_NAME", "Qwen/Qwen2.5-72B-Instruct")
|
| 7 |
+
API_KEY = os.getenv("HF_TOKEN") or os.getenv("OPENAI_API_KEY")
|
| 8 |
+
ENV_URL = os.getenv("ENV_URL", "https://swapnilpatil28-support-env.hf.space")
|
| 9 |
|
| 10 |
client = OpenAI(base_url=API_BASE_URL, api_key=API_KEY)
|
| 11 |
|
| 12 |
def run_task(task_name: str):
|
| 13 |
+
env = SupportEnvClient(base_url=ENV_URL).sync()
|
| 14 |
+
obs = env.reset(task_name=task_name)
|
| 15 |
+
print(f"[START] task={task_name} env=support_env model={MODEL_NAME}", flush=True)
|
| 16 |
|
| 17 |
+
step, rewards = 1, []
|
| 18 |
+
while not obs.done:
|
| 19 |
+
prompt = f"Ticket: {obs.observation.content}. Details: {obs.observation.search_result or 'None'}. Output one word: Billing, Tech, or Sales."
|
| 20 |
+
completion = client.chat.completions.create(model=MODEL_NAME, messages=[{"role": "user", "content": prompt}], max_tokens=10)
|
| 21 |
+
dept = completion.choices[0].message.content.strip().strip('.')
|
| 22 |
+
|
| 23 |
+
res = env.step(SupportAction(action_type="route", department=dept))
|
| 24 |
+
r = float(res.reward or 0.0)
|
| 25 |
+
rewards.append(r)
|
| 26 |
+
print(f"[STEP] step={step} action={dept} reward={r:.2f} done={str(res.done).lower()} error=null", flush=True)
|
| 27 |
+
obs, step = res, step + 1
|
| 28 |
+
|
| 29 |
+
print(f"[END] success={str(sum(rewards)>0).lower()} steps={step-1} score={sum(rewards)/len(rewards):.2f} rewards={','.join([f'{r:.2f}' for r in rewards])}", flush=True)
|
| 30 |
+
env.close()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
|
| 32 |
if __name__ == "__main__":
|
| 33 |
+
for task in ["easy", "medium", "hard"]: run_task(task)
|
|
|
models.py
CHANGED
|
@@ -1,15 +1,17 @@
|
|
| 1 |
-
from typing import List, Optional,
|
| 2 |
from openenv.core.env_server import Action, Observation, State
|
|
|
|
| 3 |
|
| 4 |
class SupportAction(Action):
|
| 5 |
-
|
|
|
|
| 6 |
|
| 7 |
class SupportObservation(Observation):
|
| 8 |
ticket_id: str
|
| 9 |
-
|
| 10 |
-
|
|
|
|
| 11 |
|
| 12 |
class SupportState(State):
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
tickets_routed: int = 0
|
|
|
|
| 1 |
+
from typing import List, Optional, Literal
|
| 2 |
from openenv.core.env_server import Action, Observation, State
|
| 3 |
+
from pydantic import Field
|
| 4 |
|
| 5 |
class SupportAction(Action):
|
| 6 |
+
action_type: Literal["search", "route"] = Field(..., description="Action to take")
|
| 7 |
+
department: Optional[str] = Field(None, description="Required for route action")
|
| 8 |
|
| 9 |
class SupportObservation(Observation):
|
| 10 |
ticket_id: str
|
| 11 |
+
content: str
|
| 12 |
+
search_result: Optional[str] = None
|
| 13 |
+
available_departments: List[str] = ["Billing", "Tech", "Sales"]
|
| 14 |
|
| 15 |
class SupportState(State):
|
| 16 |
+
task_id: str = "easy"
|
| 17 |
+
current_ticket_index: int = 0
|
|
|
server/app.py
CHANGED
|
@@ -3,7 +3,6 @@ from models import SupportAction, SupportObservation
|
|
| 3 |
from server.environment import SupportEnvironment
|
| 4 |
import uvicorn
|
| 5 |
|
| 6 |
-
# OpenEnv factory: Pass the CLASS
|
| 7 |
app = create_fastapi_app(SupportEnvironment, SupportAction, SupportObservation)
|
| 8 |
|
| 9 |
def main():
|
|
|
|
| 3 |
from server.environment import SupportEnvironment
|
| 4 |
import uvicorn
|
| 5 |
|
|
|
|
| 6 |
app = create_fastapi_app(SupportEnvironment, SupportAction, SupportObservation)
|
| 7 |
|
| 8 |
def main():
|
server/environment.py
CHANGED
|
@@ -1,56 +1,46 @@
|
|
| 1 |
import uuid
|
| 2 |
from typing import List, Dict
|
| 3 |
-
from openenv.core.env_server import
|
| 4 |
from models import SupportAction, SupportObservation, SupportState
|
| 5 |
|
| 6 |
class SupportEnvironment(Environment):
|
| 7 |
def __init__(self):
|
| 8 |
super().__init__()
|
| 9 |
-
self.
|
| 10 |
-
|
| 11 |
-
|
|
|
|
|
|
|
| 12 |
self.tasks = {
|
| 13 |
-
"easy": [{"id": "T1", "text": "
|
| 14 |
-
"medium": [{"id": "T2", "text": "
|
| 15 |
-
{"id": "T3", "text": "
|
| 16 |
-
"hard": [{"id": "T4", "text": "
|
| 17 |
-
{"id": "T5", "text": "
|
| 18 |
-
{"id": "T6", "text": "API
|
| 19 |
}
|
| 20 |
|
| 21 |
def reset(self, task_name: str = "easy") -> SupportObservation:
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
episode_id=str(uuid.uuid4()), step_count=0, task_name=task_name,
|
| 27 |
-
total_tickets=len(self._current_queue), tickets_routed=0
|
| 28 |
-
)
|
| 29 |
-
self._current_ticket = self._current_queue.pop(0)
|
| 30 |
-
return SupportObservation(
|
| 31 |
-
done=False, reward=0.0, ticket_id=self._current_ticket["id"],
|
| 32 |
-
ticket_text=self._current_ticket["text"], message="New ticket arrived."
|
| 33 |
-
)
|
| 34 |
|
| 35 |
def step(self, action: SupportAction) -> SupportObservation:
|
| 36 |
self._state.step_count += 1
|
| 37 |
-
|
| 38 |
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
self._state.tickets_routed += 1
|
| 42 |
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
done=True, reward=reward, ticket_id="None",
|
| 52 |
-
ticket_text="Queue is empty.", message="All tickets processed."
|
| 53 |
-
)
|
| 54 |
|
| 55 |
@property
|
| 56 |
def state(self) -> SupportState:
|
|
|
|
| 1 |
import uuid
|
| 2 |
from typing import List, Dict
|
| 3 |
+
from openenv.core.env_server import Environment
|
| 4 |
from models import SupportAction, SupportObservation, SupportState
|
| 5 |
|
| 6 |
class SupportEnvironment(Environment):
|
| 7 |
def __init__(self):
|
| 8 |
super().__init__()
|
| 9 |
+
self._db = {
|
| 10 |
+
"T1": "Customer History: Frequent refunder. Status: Valid invoice.",
|
| 11 |
+
"T4": "System Log: Payment gateway timed out. Card ending in 4242.",
|
| 12 |
+
"T6": "Dev Log: 500 error on /api/auth. Cluster: us-east-1."
|
| 13 |
+
}
|
| 14 |
self.tasks = {
|
| 15 |
+
"easy": [{"id": "T1", "text": "Refund status?", "dept": "Billing"}],
|
| 16 |
+
"medium": [{"id": "T2", "text": "Upgrade account?", "dept": "Sales"},
|
| 17 |
+
{"id": "T3", "text": "App keeps crashing.", "dept": "Tech"}],
|
| 18 |
+
"hard": [{"id": "T4", "text": "Payment failed!", "dept": "Billing"},
|
| 19 |
+
{"id": "T5", "text": "Bulk pricing?", "dept": "Sales"},
|
| 20 |
+
{"id": "T6", "text": "API Auth failure.", "dept": "Tech"}]
|
| 21 |
}
|
| 22 |
|
| 23 |
def reset(self, task_name: str = "easy") -> SupportObservation:
|
| 24 |
+
self.current_task = self.tasks.get(task_name, self.tasks["easy"])
|
| 25 |
+
self._state = SupportState(episode_id=str(uuid.uuid4()), task_id=task_name)
|
| 26 |
+
t = self.current_task[0]
|
| 27 |
+
return SupportObservation(done=False, reward=0.0, ticket_id=t["id"], content=t["text"])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
|
| 29 |
def step(self, action: SupportAction) -> SupportObservation:
|
| 30 |
self._state.step_count += 1
|
| 31 |
+
ticket = self.current_task[self._state.current_ticket_index]
|
| 32 |
|
| 33 |
+
if action.action_type == "search":
|
| 34 |
+
return SupportObservation(done=False, reward=-0.05, ticket_id=ticket["id"], content=ticket["text"], search_result=self._db.get(ticket["id"], "No record."))
|
|
|
|
| 35 |
|
| 36 |
+
correct = action.department.strip().lower() == ticket["dept"].lower()
|
| 37 |
+
reward = 1.0 if correct else 0.0
|
| 38 |
+
self._state.current_ticket_index += 1
|
| 39 |
+
|
| 40 |
+
if self._state.current_ticket_index < len(self.current_task):
|
| 41 |
+
t = self.current_task[self._state.current_ticket_index]
|
| 42 |
+
return SupportObservation(done=False, reward=reward, ticket_id=t["id"], content=t["text"])
|
| 43 |
+
return SupportObservation(done=True, reward=reward, ticket_id="EOF", content="Done.")
|
|
|
|
|
|
|
|
|
|
| 44 |
|
| 45 |
@property
|
| 46 |
def state(self) -> SupportState:
|