File size: 6,060 Bytes
673bc41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
566e5c7
673bc41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
566e5c7
 
 
673bc41
 
566e5c7
673bc41
566e5c7
673bc41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
566e5c7
673bc41
 
566e5c7
 
673bc41
566e5c7
673bc41
 
 
 
 
 
 
 
566e5c7
 
 
 
 
673bc41
 
 
 
 
 
566e5c7
 
 
673bc41
566e5c7
673bc41
 
 
 
 
566e5c7
673bc41
 
566e5c7
673bc41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
"""
Inference script for IT Mental Health OpenEnv.

Required environment variables in the inference configuration:
    API_BASE_URL   The API endpoint for the LLM.
    MODEL_NAME     The model identifier to use for inference.
    HF_TOKEN       Your Hugging Face / API key.

Optional:
    LOCAL_IMAGE_NAME  Present for compatibility with environments created from
                      docker images.

Defaults are set only for API_BASE_URL and MODEL_NAME.
The script uses the OpenAI client for all LLM calls.
"""

import os
import sys
from typing import List, Optional

import requests
from openai import OpenAI

API_BASE_URL = os.getenv("API_BASE_URL", "https://api-inference.huggingface.co/v1")
MODEL_NAME = os.getenv("MODEL_NAME", "meta-llama/Llama-3.1-8B-Instruct")
HF_TOKEN = os.getenv("HF_TOKEN") or os.getenv("OPENAI_API_KEY")
LOCAL_IMAGE_NAME = os.getenv("LOCAL_IMAGE_NAME")
ENV_BASE_URL = os.getenv("ENV_BASE_URL", "http://localhost:7860")

BENCHMARK = "it_mental_health_env"
MAX_STEPS = 3
TEMPERATURE = 0.3
MAX_TOKENS = 800
SUCCESS_SCORE_THRESHOLD = 0.6

SYSTEM_PROMPT = """You are an expert occupational psychologist and workplace mental health consultant
specialising in the IT/software engineering sector. You have deep knowledge of:
- Maslach Burnout Inventory (MBI) dimensions
- Stress triage frameworks (GREEN/AMBER/RED/CRITICAL)
- Evidence-based workplace mental health interventions
- Employee Assistance Programmes (EAP) and HR escalation protocols

Respond in clear, structured format with headings and concrete recommendations.
Be specific, actionable, and professional. Aim for 200-600 words per response."""


def clean_field(value: Optional[str]) -> str:
    if value is None:
        return "null"
    return " ".join(str(value).split())


def log_start(task: str, env: str, model: str) -> None:
    print(f"[START] task={clean_field(task)} env={clean_field(env)} model={clean_field(model)}", flush=True)


def log_step(step: int, action: str, reward: float, done: bool, error: Optional[str]) -> None:
    print(
        f"[STEP] step={step} action={clean_field(action)} reward={reward:.2f} "
        f"done={str(done).lower()} error={clean_field(error)}",
        flush=True,
    )


def log_end(success: bool, steps: int, score: float, rewards: List[float]) -> None:
    rewards_str = ",".join(f"{reward:.2f}" for reward in rewards)
    print(
        f"[END] success={str(success).lower()} steps={steps} score={score:.3f} rewards={rewards_str}",
        flush=True,
    )


def call_env(
    http: requests.Session, endpoint: str, payload: Optional[dict] = None, method: str = "POST"
) -> dict:
    url = f"{ENV_BASE_URL}/{endpoint}"
    if method == "GET":
        response = http.get(url, timeout=30)
    else:
        response = http.post(url, json=payload or {}, timeout=30)
    response.raise_for_status()
    return response.json()


def get_model_response(client: OpenAI, scenario: str) -> str:
    completion = client.chat.completions.create(
        model=MODEL_NAME,
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": scenario},
        ],
        temperature=TEMPERATURE,
        max_tokens=MAX_TOKENS,
        stream=False,
    )
    content = completion.choices[0].message.content or ""
    return content.strip() or "Provide a structured assessment and immediate next steps."


def main() -> None:
    rewards: List[float] = []
    steps_taken = 0
    score = 0.0
    success = False
    current_task = "unknown"
    start_logged = False

    try:
        if not HF_TOKEN:
            raise RuntimeError("HF_TOKEN or OPENAI_API_KEY must be set for inference.")

        client = OpenAI(base_url=API_BASE_URL, api_key=HF_TOKEN)
        http = requests.Session()
        observation = call_env(http, "reset", {})
        current_task = observation.get("task_id", "unknown")
        session_id = observation.get("metadata", {}).get("session_id")
        log_start(task=current_task, env=BENCHMARK, model=MODEL_NAME)
        start_logged = True

        for step in range(1, MAX_STEPS + 1):
            if observation.get("done", False):
                break

            current_task = observation.get("task_id", "unknown")
            scenario = observation.get("scenario")
            if not scenario:
                raise RuntimeError("Environment response missing 'scenario'.")

            action_text = get_model_response(client, scenario)

            error = None
            done = False
            reward = 0.0

            try:
                metadata = {}
                if session_id:
                    metadata["session_id"] = session_id
                observation = call_env(
                    http,
                    "step",
                    {
                        "response": action_text,
                        "task_id": current_task,
                        "confidence": 0.85,
                        "metadata": metadata,
                    },
                )
                session_id = observation.get("metadata", {}).get("session_id", session_id)
                reward = float(observation.get("reward", 0.0) or 0.0)
                done = bool(observation.get("done", False))
            except Exception as exc:
                error = str(exc)
                done = True

            rewards.append(reward)
            steps_taken = step
            log_step(step=step, action=action_text, reward=reward, done=done, error=error)

            if error or done:
                break

        score = sum(rewards) / MAX_STEPS if MAX_STEPS > 0 else 0.0
        score = max(0.0, min(1.0, score))
        success = score >= SUCCESS_SCORE_THRESHOLD
    finally:
        if not start_logged:
            log_start(task=current_task, env=BENCHMARK, model=MODEL_NAME)
        log_end(success=success, steps=steps_taken, score=score, rewards=rewards)


if __name__ == "__main__":
    try:
        main()
    except Exception as exc:
        print(f"Inference failed: {exc}", file=sys.stderr)
        sys.exit(1)