Kesheratmex commited on
Commit
2c4cd1d
·
1 Parent(s): 105e5c0

Add gptoss_wrapper.py: wrapper for GPT‑OSS integration

Browse files
Files changed (1) hide show
  1. gptoss_wrapper.py +150 -0
gptoss_wrapper.py ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ GPTOSSWrapper - Simple integration wrapper for OpenAI or Hugging Face Inference API.
3
+
4
+ Usage:
5
+ from gptoss_wrapper import GPTOSSWrapper
6
+ w = GPTOSSWrapper(model="gpt-oss-120")
7
+ text = w.generate(prompt)
8
+
9
+ Behavior:
10
+ - Provider selection (priority):
11
+ 1) If OPENAI_API_KEY is set -> use OpenAI Chat Completions (v1/chat/completions)
12
+ 2) Else if HUGGINGFACE_API_TOKEN or HF_API_TOKEN is set -> use Hugging Face Inference API
13
+ 3) Else -> generate() will raise a RuntimeError describing missing credentials.
14
+
15
+ Note for Spaces:
16
+ - Add the secret in your Space settings (Settings → Secrets & variables → Add secret):
17
+ - For OpenAI: key name = OPENAI_API_KEY, value = <your_openai_api_key>
18
+ - For Hugging Face: key name = HUGGINGFACE_API_TOKEN (or HF_API_TOKEN), value = <your_hf_token>
19
+
20
+ This file intentionally uses only the requests stdlib-friendly HTTP approach to avoid depending on extra SDKs.
21
+ """
22
+ import os
23
+ import time
24
+ import requests
25
+ from typing import Optional
26
+
27
+
28
+ class GPTOSSWrapper:
29
+ """
30
+ Lightweight wrapper that can call either OpenAI or Hugging Face inference endpoints.
31
+
32
+ Constructor:
33
+ GPTOSSWrapper(model="gpt-oss-120", provider="auto")
34
+
35
+ - model: model name to request (for OpenAI it must be an available model for your account;
36
+ for Hugging Face it should be a model id hosted on HF).
37
+ - provider: "auto" (default) | "openai" | "hf"
38
+ """
39
+
40
+ def __init__(self, model: str = "gpt-oss-120", provider: str = "auto"):
41
+ self.model = model
42
+ self.request_timeout = 30
43
+ self.openai_key = os.getenv("OPENAI_API_KEY")
44
+ self.hf_token = os.getenv("HUGGINGFACE_API_TOKEN") or os.getenv("HF_API_TOKEN")
45
+ self.provider = provider.lower() if provider else "auto"
46
+
47
+ if self.provider == "auto":
48
+ if self.openai_key:
49
+ self.provider = "openai"
50
+ elif self.hf_token:
51
+ self.provider = "hf"
52
+ else:
53
+ self.provider = "none"
54
+
55
+ def generate(self, prompt: str, max_tokens: int = 512, temperature: float = 0.2) -> str:
56
+ """
57
+ Generate a textual response for the given prompt.
58
+
59
+ Returns:
60
+ A string with the generated text.
61
+
62
+ Raises:
63
+ RuntimeError if no credentials are found or the remote call fails.
64
+ """
65
+ if self.provider == "openai":
66
+ return self._generate_openai(prompt, max_tokens=max_tokens, temperature=temperature)
67
+ elif self.provider == "hf":
68
+ return self._generate_hf(prompt, max_tokens=max_tokens, temperature=temperature)
69
+ else:
70
+ raise RuntimeError(
71
+ "No API key configured for GPT wrapper. Set OPENAI_API_KEY or HUGGINGFACE_API_TOKEN in the environment."
72
+ )
73
+
74
+ def _generate_openai(self, prompt: str, max_tokens: int, temperature: float) -> str:
75
+ if not self.openai_key:
76
+ raise RuntimeError("OPENAI_API_KEY not set in environment.")
77
+
78
+ url = "https://api.openai.com/v1/chat/completions"
79
+ headers = {
80
+ "Authorization": f"Bearer {self.openai_key}",
81
+ "Content-Type": "application/json",
82
+ }
83
+
84
+ # Build a simple chat conversation with a single system + user message
85
+ payload = {
86
+ "model": self.model,
87
+ "messages": [
88
+ {"role": "system", "content": "You are an expert inspection assistant for wind turbine blade images/videos."},
89
+ {"role": "user", "content": prompt},
90
+ ],
91
+ "max_tokens": max_tokens,
92
+ "temperature": float(temperature),
93
+ "n": 1,
94
+ }
95
+
96
+ try:
97
+ r = requests.post(url, headers=headers, json=payload, timeout=self.request_timeout)
98
+ r.raise_for_status()
99
+ data = r.json()
100
+ # OpenAI API returns a list of choices
101
+ choices = data.get("choices", [])
102
+ if not choices:
103
+ raise RuntimeError(f"OpenAI returned empty choices: {data}")
104
+ # Extract the assistant message
105
+ msg = choices[0].get("message", {}).get("content")
106
+ if msg is None:
107
+ # Some deployments return text in 'text' or in other fields; fallback to stringifying response
108
+ return str(data)
109
+ return msg.strip()
110
+ except Exception as e:
111
+ # Surface a clear error for the calling code to handle (the app catches exceptions)
112
+ raise RuntimeError(f"OpenAI API call failed: {e}")
113
+
114
+ def _generate_hf(self, prompt: str, max_tokens: int, temperature: float) -> str:
115
+ if not self.hf_token:
116
+ raise RuntimeError("HUGGINGFACE_API_TOKEN (or HF_API_TOKEN) not set in environment.")
117
+
118
+ url = f"https://api-inference.huggingface.co/models/{self.model}"
119
+ headers = {"Authorization": f"Bearer {self.hf_token}"}
120
+ payload = {
121
+ "inputs": prompt,
122
+ "parameters": {
123
+ "max_new_tokens": max_tokens,
124
+ "temperature": float(temperature),
125
+ # Keep other params minimal; users can customize the model server side
126
+ },
127
+ "options": {"wait_for_model": True},
128
+ }
129
+
130
+ try:
131
+ r = requests.post(url, headers=headers, json=payload, timeout=self.request_timeout)
132
+ r.raise_for_status()
133
+ data = r.json()
134
+ # Hugging Face inference may return a list of generated outputs or a dict
135
+ if isinstance(data, list) and len(data) > 0 and isinstance(data[0], dict) and "generated_text" in data[0]:
136
+ return data[0]["generated_text"].strip()
137
+ elif isinstance(data, dict) and "generated_text" in data:
138
+ return data["generated_text"].strip()
139
+ elif isinstance(data, dict) and "error" in data:
140
+ raise RuntimeError(f"Hugging Face error: {data['error']}")
141
+ else:
142
+ # Some text-generation endpoints return a plain string or different struct; try to stringify
143
+ return str(data)
144
+ except Exception as e:
145
+ raise RuntimeError(f"Hugging Face API call failed: {e}")
146
+
147
+
148
+ # Backwards-compatible factory in case caller expects a function or attribute
149
+ def GPTOSSWrapperFactory(model: Optional[str] = None, provider: Optional[str] = None):
150
+ return GPTOSSWrapper(model=model or "gpt-oss-120", provider=provider or "auto")