mila2030 commited on
Commit
0248d33
·
verified ·
1 Parent(s): aacab3f

Update handler.py

Browse files
Files changed (1) hide show
  1. handler.py +82 -80
handler.py CHANGED
@@ -1,21 +1,20 @@
1
- # handler.py — HF-compliant, stateless Gemini proxy
2
 
3
- from typing import Any, Dict, List, Union
4
- import os
 
5
  import google.generativeai as genai
6
 
7
- # Config via HF Endpoint → Settings → Environment Variables
8
- MODEL = os.getenv("GEMINI_MODEL", "gemini-1.5-flash") # safe default
9
- TEMPERATURE = float(os.getenv("TEMPERATURE", "0.7"))
10
- TOP_P = float(os.getenv("TOP_P", "0.95"))
11
- MAX_TOKENS = int(os.getenv("MAX_OUTPUT_TOKENS", "512"))
12
- SYSTEM_PROMPT = os.getenv("SYSTEM_PROMPT", "You are a helpful assistant.")
13
 
14
  def _extract_text(resp: Any) -> str:
15
- # 1) standard property
16
  if getattr(resp, "text", None):
17
  return resp.text
18
- # 2) candidates/parts
19
  try:
20
  for c in getattr(resp, "candidates", []) or []:
21
  content = getattr(c, "content", None)
@@ -27,93 +26,96 @@ def _extract_text(resp: Any) -> str:
27
  pass
28
  return ""
29
 
30
- def _last_user_from_messages(msgs: List[Dict[str, Any]]) -> str:
31
- for m in reversed(msgs or []):
32
- if (m.get("role") or "user").lower() == "user":
33
- return str(m.get("content", "")).strip()
34
- return ""
35
-
36
  class EndpointHandler:
37
  def __init__(self, path: str = ""):
38
- api_key = os.getenv("GEMINI_API_KEY") or os.getenv("GOOGLE_API_KEY")
39
- if not api_key:
40
- self._init_error = "Missing GEMINI_API_KEY/GOOGLE_API_KEY in Endpoint Environment Variables."
41
- print("[handler:init] ERROR:", self._init_error, flush=True)
 
 
42
  return
43
- self._init_error = None
44
- genai.configure(api_key=api_key)
45
 
46
- # Proper system prompt
47
- self.model = genai.GenerativeModel(MODEL, system_instruction=SYSTEM_PROMPT)
48
-
49
- # Optional: slightly relaxed safety to avoid silent blocks of normal prompts
50
- self.safety_settings = None
51
  try:
52
- from google.generativeai.types import HarmBlockThreshold, HarmCategory
53
- self.safety_settings = {
54
- HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_ONLY_HIGH,
55
- HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_ONLY_HIGH,
56
- HarmCategory.HARM_CATEGORY_SEXUAL: HarmBlockThreshold.BLOCK_ONLY_HIGH,
57
- HarmCategory.HARM_CATEGORY_DANGEROUS: HarmBlockThreshold.BLOCK_ONLY_HIGH,
58
- }
59
  except Exception as e:
60
- print("[handler:init] safety settings skipped:", repr(e), flush=True)
61
-
62
- print(f"[handler:init] OK MODEL={MODEL}", flush=True)
63
-
64
- def __call__(self, data: Dict[str, Any]) -> Dict[str, Any]:
65
- if self._init_error:
66
- return {"text": "", "debug": {"error": self._init_error}}
67
 
 
68
  try:
69
- print("[handler:call] payload:", data, flush=True)
70
- # HF guarantees top-level `inputs`
71
- inputs = data.get("inputs")
 
 
 
72
 
73
- # Accept either:
74
- # A) {"inputs":"plain text"}
75
- # B) {"inputs":{"messages":[{"role":"user","content":"..."}]}}
76
- # (compat) Also accept top-level "messages" if present.
77
- if isinstance(inputs, str):
78
- user_text = inputs.strip()
79
- elif isinstance(inputs, dict) and "messages" in inputs:
80
- user_text = _last_user_from_messages(inputs.get("messages"))
81
- elif "messages" in data:
82
- user_text = _last_user_from_messages(data.get("messages"))
83
- else:
84
- user_text = ""
85
 
86
- if not user_text:
87
- return {"text": "", "debug": {"note": "Empty prompt."}}
 
 
 
 
 
 
88
 
89
- gen_cfg = {
90
- "temperature": TEMPERATURE,
91
- "top_p": TOP_P,
92
- "max_output_tokens": MAX_TOKENS,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  }
94
 
95
- print("[handler:call] generate_content:", repr(user_text[:160]), flush=True)
 
 
96
  resp = self.model.generate_content(
97
  user_text,
98
- generation_config=gen_cfg,
99
- safety_settings=self.safety_settings
 
 
 
100
  )
101
- print("[handler:call] raw resp:", repr(resp), flush=True)
102
-
103
- text = _extract_text(resp)
104
- if text:
105
- return {"text": text}
106
-
107
- # Diagnostics if empty
108
- debug = {}
109
  try:
110
  fr = [getattr(c, "finish_reason", None) for c in (resp.candidates or [])]
111
- if fr:
112
- debug["finish_reasons"] = fr
113
  except Exception:
114
  pass
115
- return {"text": "", "debug": debug or {"note": "Empty model text"}}
116
-
117
  except Exception as e:
118
- print("[handler:call] EXC:", repr(e), flush=True)
119
- return {"text": "", "debug": {"exception": str(e)}}
 
1
+ # handler.py — self-diagnostic, always returns a clear result
2
 
3
+ from typing import Any, Dict, Union
4
+ import os, socket, json, time
5
+ import requests
6
  import google.generativeai as genai
7
 
8
+ MODEL = os.getenv("GEMINI_MODEL", "gemini-1.5-flash") # safe default
9
+ TEMPERATURE = float(os.getenv("TEMPERATURE", "0.7"))
10
+ TOP_P = float(os.getenv("TOP_P", "0.95"))
11
+ MAX_TOKENS = int(os.getenv("MAX_OUTPUT_TOKENS", "512"))
12
+ SYSTEM_PROMPT = os.getenv("SYSTEM_PROMPT", "You are a helpful assistant.")
13
+ GOOGLE_HOST = "generativelanguage.googleapis.com"
14
 
15
  def _extract_text(resp: Any) -> str:
 
16
  if getattr(resp, "text", None):
17
  return resp.text
 
18
  try:
19
  for c in getattr(resp, "candidates", []) or []:
20
  content = getattr(c, "content", None)
 
26
  pass
27
  return ""
28
 
 
 
 
 
 
 
29
  class EndpointHandler:
30
  def __init__(self, path: str = ""):
31
+ self.diag = {"stage":"init", "ok":True, "notes":[]}
32
+ self.api_key = os.getenv("GEMINI_API_KEY") or os.getenv("GOOGLE_API_KEY")
33
+ if not self.api_key:
34
+ self.diag["ok"] = False
35
+ self.diag["error"] = "Missing GEMINI_API_KEY (Endpoint → Settings → Environment Variables)."
36
+ print("[diag] ENV KEY MISSING", flush=True)
37
  return
 
 
38
 
39
+ # DNS test
 
 
 
 
40
  try:
41
+ ip = socket.gethostbyname(GOOGLE_HOST)
42
+ self.diag["dns_ip"] = ip
 
 
 
 
 
43
  except Exception as e:
44
+ self.diag["ok"] = False
45
+ self.diag["dns_error"] = repr(e)
46
+ print("[diag] DNS FAIL:", repr(e), flush=True)
 
 
 
 
47
 
48
+ # HTTPS reachability (no auth) — should return 404/403 but prove TLS/egress works
49
  try:
50
+ r = requests.get(f"https://{GOOGLE_HOST}/", timeout=5)
51
+ self.diag["https_status"] = r.status_code
52
+ except Exception as e:
53
+ self.diag["ok"] = False
54
+ self.diag["https_error"] = repr(e)
55
+ print("[diag] HTTPS FAIL:", repr(e), flush=True)
56
 
57
+ if not self.diag["ok"]:
58
+ return
 
 
 
 
 
 
 
 
 
 
59
 
60
+ try:
61
+ genai.configure(api_key=self.api_key)
62
+ self.model = genai.GenerativeModel(MODEL, system_instruction=SYSTEM_PROMPT)
63
+ self.diag["model_ready"] = True
64
+ except Exception as e:
65
+ self.diag["ok"] = False
66
+ self.diag["model_init_error"] = repr(e)
67
+ print("[diag] MODEL INIT FAIL:", repr(e), flush=True)
68
 
69
+ def __call__(self, data: Dict[str, Any]) -> Dict[str, Any]:
70
+ # Normalize input
71
+ inputs = data.get("inputs")
72
+ if isinstance(inputs, str):
73
+ user_text = inputs.strip()
74
+ elif isinstance(inputs, dict) and "messages" in inputs:
75
+ # accept chat shape, use last user content
76
+ user_text = ""
77
+ for m in reversed(inputs.get("messages") or []):
78
+ if (m.get("role") or "user").lower() == "user":
79
+ user_text = str(m.get("content", "")).strip()
80
+ break
81
+ else:
82
+ user_text = ""
83
+
84
+ if not user_text:
85
+ return {"text":"", "debug":{"where":"handler","note":"Empty prompt received at endpoint."}}
86
+
87
+ # If init failed, return diagnostics + echo so frontend proves it works
88
+ if not getattr(self, "model", None):
89
+ return {
90
+ "text":"",
91
+ "debug":{
92
+ "where":"init",
93
+ "diag": self.diag,
94
+ "echo": user_text[:160]
95
+ }
96
  }
97
 
98
+ # Try Gemini
99
+ try:
100
+ t0 = time.time()
101
  resp = self.model.generate_content(
102
  user_text,
103
+ generation_config={
104
+ "temperature": TEMPERATURE,
105
+ "top_p": TOP_P,
106
+ "max_output_tokens": MAX_TOKENS
107
+ },
108
  )
109
+ dt = round((time.time() - t0)*1000)
110
+ txt = _extract_text(resp)
111
+ if txt:
112
+ return {"text": txt, "debug":{"latency_ms": dt}}
113
+ # no text -> return finish reasons for clarity
114
+ fr = []
 
 
115
  try:
116
  fr = [getattr(c, "finish_reason", None) for c in (resp.candidates or [])]
 
 
117
  except Exception:
118
  pass
119
+ return {"text":"", "debug":{"where":"gemini_empty","finish_reasons":fr,"latency_ms":dt,"echo":user_text[:160]}}
 
120
  except Exception as e:
121
+ return {"text":"", "debug":{"where":"gemini_exception","exception":repr(e),"echo":user_text[:160]}}