Juju519 commited on
Commit
04a3aab
·
unverified ·
1 Parent(s): 8137b74

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +156 -78
app.py CHANGED
@@ -3,17 +3,63 @@ from huggingface_hub import InferenceClient
3
  import os
4
  import json
5
  import random
 
6
 
7
  pipe = None
8
 
9
- # Load WPI facts from JSON
10
- with open("facts.json", "r") as f:
11
- WPI_FACTS = json.load(f)
12
-
13
- # Fancy CSS (same as before)
14
- fancy_css = """ ... """ # Keep your previous CSS here
15
-
16
- # --- Gompei chatbot response ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  def respond(
18
  message,
19
  history: list[dict[str, str]],
@@ -22,16 +68,13 @@ def respond(
22
  temperature,
23
  top_p,
24
  use_local_model: bool,
25
- hf_token: gr.OAuthToken = None,
26
  ):
27
  global pipe
28
 
29
- # Pick a random WPI fact
30
  fact = random.choice(WPI_FACTS)["text"]
31
-
32
  messages = [{"role": "system", "content": system_message}]
33
  messages.extend(history)
34
- # Append the user message + random fact for context
35
  messages.append({"role": "user", "content": f"{message}\n\nFun fact: {fact}"})
36
 
37
  response = ""
@@ -40,10 +83,8 @@ def respond(
40
  print("[MODE] local")
41
  from transformers import pipeline
42
  if pipe is None:
43
- pipe = pipeline("text-generation", model="microsoft/Phi-3-mini-4k-instruct")
44
-
45
  prompt = "\n".join([f"{m['role']}: {m['content']}" for m in messages])
46
-
47
  outputs = pipe(
48
  prompt,
49
  max_new_tokens=max_tokens,
@@ -51,78 +92,115 @@ def respond(
51
  temperature=temperature,
52
  top_p=top_p,
53
  )
54
-
55
  response = outputs[0]["generated_text"][len(prompt):]
56
  yield response.strip()
 
57
 
58
- else:
59
- print("[MODE] api")
60
- token_value = None
61
- if hf_token and getattr(hf_token, "token", None):
62
- token_value = hf_token.token
63
- elif os.environ.get("HF_TOKEN"):
64
- token_value = os.environ.get("HF_TOKEN")
65
 
66
- if not token_value:
67
- yield "⚠️ Please log in with your Hugging Face account or set HF_TOKEN in environment."
 
 
68
  return
69
-
70
- client = InferenceClient(token=token_value, model="openai/gpt-oss-20b")
71
-
72
- for chunk in client.chat_completion(
73
- messages,
74
- max_tokens=max_tokens,
75
- stream=True,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  temperature=temperature,
77
  top_p=top_p,
78
- ):
79
- choices = chunk.choices
80
- token = ""
81
- if len(choices) and choices[0].delta.content:
82
- token = choices[0].delta.content
83
- response += token
 
 
 
 
 
84
  yield response
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
 
86
- # --- Chat Interface ---
87
- chatbot = gr.ChatInterface(
88
- fn=respond,
89
- additional_inputs=[
90
- gr.Textbox(
91
- value="You are Gompei the Goat, WPI's mascot. Answer questions with fun goat-like personality and real WPI facts.",
92
- label="System message",
93
- ),
94
- gr.Slider(minimum=1, maximum=1024, value=256, step=1, label="Max new tokens"),
95
- gr.Slider(minimum=0.1, maximum=2.0, value=0.7, step=0.1, label="Temperature"),
96
- gr.Slider(minimum=0.1, maximum=1.0, value=0.95, step=0.05, label="Top-p (nucleus sampling)"),
97
- gr.Checkbox(label="Use Local Model", value=False),
98
- ],
99
- type="messages",
100
- examples=[
101
- [
102
- "Where is WPI located?",
103
- "You are Gompei the Goat, WPI's mascot. Answer questions with fun goat-like personality and real WPI facts.",
104
- 128,
105
- 0.7,
106
- 0.95,
107
- False
108
- ],
109
- [
110
- "Who founded WPI?",
111
- "You are Gompei the Goat, WPI's mascot. Answer questions with fun goat-like personality and real WPI facts.",
112
- 128,
113
- 0.7,
114
- 0.95,
115
- False
116
- ],
117
- ],
118
- )
119
-
120
- # --- Blocks layout ---
121
- with gr.Blocks(css=fancy_css) as demo:
122
- with gr.Row():
123
- gr.Markdown("<h1 id='title'>🐐 Chat with Gompei</h1>")
124
- gr.LoginButton()
125
- chatbot.render()
126
 
127
  if __name__ == "__main__":
 
 
 
128
  demo.launch(server_name="0.0.0.0", server_port=7860)
 
3
  import os
4
  import json
5
  import random
6
+ from typing import Optional
7
 
8
  pipe = None
9
 
10
+ # ========== Config ==========
11
+ LOCAL_MODEL = os.environ.get("LOCAL_MODEL", "microsoft/Phi-3-mini-4k-instruct")
12
+
13
+ API_PROVIDER = os.environ.get("API_PROVIDER", "").strip().lower() # "", "hf", "nebius"
14
+ API_MODEL = os.environ.get("API_MODEL", "HuggingFaceH4/zephyr-7b-beta")
15
+
16
+ NEBIUS_API_KEY = os.environ.get("NEBIUS_API_KEY")
17
+ NEBIUS_MODEL = os.environ.get("NEBIUS_MODEL", "gpt-oss-20b")
18
+ NEBIUS_BASE_URL = os.environ.get("NEBIUS_BASE_URL", "https://api.studio.nebius.ai/v1")
19
+ # ===========================
20
+
21
+ # Facts + CSS fallbacks
22
+ FACTS_PATH = "facts.json"
23
+ DEFAULT_FACTS = [{"text": "WPI was founded in 1865 by John Boynton and Ichabod Washburn."}]
24
+ try:
25
+ with open(FACTS_PATH, "r") as f:
26
+ WPI_FACTS = json.load(f)
27
+ if not isinstance(WPI_FACTS, list) or not WPI_FACTS:
28
+ WPI_FACTS = DEFAULT_FACTS
29
+ except Exception:
30
+ WPI_FACTS = DEFAULT_FACTS
31
+
32
+ fancy_css = """/* fallback if your CSS file isn't ready */ #title { text-align:center; }"""
33
+
34
+ def _extract_hf_token(hf_token_obj: Optional[object]) -> Optional[str]:
35
+ if hf_token_obj:
36
+ if isinstance(hf_token_obj, str) and hf_token_obj.strip():
37
+ return hf_token_obj.strip()
38
+ for attr in ("token", "access_token"):
39
+ try:
40
+ val = getattr(hf_token_obj, attr, None)
41
+ if isinstance(val, str) and val.strip():
42
+ return val.strip()
43
+ except Exception:
44
+ pass
45
+ try:
46
+ if hasattr(hf_token_obj, "get"):
47
+ val = hf_token_obj.get("token") or hf_token_obj.get("access_token")
48
+ if isinstance(val, str) and val.strip():
49
+ return val.strip()
50
+ except Exception:
51
+ pass
52
+ env_val = os.environ.get("HF_TOKEN")
53
+ if isinstance(env_val, str) and env_val.strip():
54
+ return env_val.strip()
55
+ return None
56
+
57
+ def _resolve_provider():
58
+ if API_PROVIDER in ("hf", "nebius"):
59
+ return API_PROVIDER
60
+ return "nebius" if NEBIUS_API_KEY else "hf"
61
+
62
+ # ---- Core chat handler (unchanged logic) ----
63
  def respond(
64
  message,
65
  history: list[dict[str, str]],
 
68
  temperature,
69
  top_p,
70
  use_local_model: bool,
71
+ hf_token: Optional[object] = None,
72
  ):
73
  global pipe
74
 
 
75
  fact = random.choice(WPI_FACTS)["text"]
 
76
  messages = [{"role": "system", "content": system_message}]
77
  messages.extend(history)
 
78
  messages.append({"role": "user", "content": f"{message}\n\nFun fact: {fact}"})
79
 
80
  response = ""
 
83
  print("[MODE] local")
84
  from transformers import pipeline
85
  if pipe is None:
86
+ pipe = pipeline("text-generation", model=LOCAL_MODEL)
 
87
  prompt = "\n".join([f"{m['role']}: {m['content']}" for m in messages])
 
88
  outputs = pipe(
89
  prompt,
90
  max_new_tokens=max_tokens,
 
92
  temperature=temperature,
93
  top_p=top_p,
94
  )
 
95
  response = outputs[0]["generated_text"][len(prompt):]
96
  yield response.strip()
97
+ return
98
 
99
+ provider = _resolve_provider()
 
 
 
 
 
 
100
 
101
+ if provider == "nebius":
102
+ print(f"[MODE] api | provider=nebius model={NEBIUS_MODEL}")
103
+ if not NEBIUS_API_KEY:
104
+ yield ("⚠️ Missing NEBIUS_API_KEY. Set it or switch to HF by setting API_PROVIDER=hf and providing HF_TOKEN.")
105
  return
106
+ client = InferenceClient(token=NEBIUS_API_KEY, base_url=NEBIUS_BASE_URL)
107
+ try:
108
+ for chunk in client.chat_completion(
109
+ messages=messages,
110
+ max_tokens=max_tokens,
111
+ stream=True,
112
+ temperature=temperature,
113
+ top_p=top_p,
114
+ model=NEBIUS_MODEL,
115
+ ):
116
+ choices = getattr(chunk, "choices", [])
117
+ token_text = ""
118
+ if choices and getattr(choices[0].delta, "content", None):
119
+ token_text = choices[0].delta.content
120
+ response += token_text
121
+ yield response
122
+ except Exception as e:
123
+ if "401" in str(e) or "Unauthorized" in str(e):
124
+ yield "⚠️ Nebius auth failed. Check NEBIUS_API_KEY and NEBIUS_MODEL."
125
+ else:
126
+ yield f"⚠️ Nebius API error: {e}"
127
+ return
128
+
129
+ # HF provider via text_generation (no strict chat perms)
130
+ print(f"[MODE] api | provider=hf model={API_MODEL}")
131
+ token_value = _extract_hf_token(hf_token)
132
+ if not token_value:
133
+ yield "⚠️ Please log in (Login button) or set HF_TOKEN in environment."
134
+ return
135
+ client = InferenceClient(model=API_MODEL, token=token_value)
136
+
137
+ prompt = "\n".join([f"{m['role']}: {m['content']}" for m in messages])
138
+ try:
139
+ stream = client.text_generation(
140
+ prompt,
141
+ max_new_tokens=max_tokens,
142
  temperature=temperature,
143
  top_p=top_p,
144
+ stream=True,
145
+ details=False,
146
+ return_full_text=False,
147
+ )
148
+ for out in stream:
149
+ try:
150
+ token_text = getattr(out, "token", None)
151
+ token_text = token_text.text if token_text else (out if isinstance(out, str) else "")
152
+ except Exception:
153
+ token_text = str(out) if out else ""
154
+ response += token_text
155
  yield response
156
+ except Exception as e:
157
+ if "401" in str(e) or "Unauthorized" in str(e):
158
+ yield "⚠️ Hugging Face auth failed. Ensure HF_TOKEN or log in via the button."
159
+ else:
160
+ yield f"⚠️ HF Inference error: {e}"
161
+
162
+ # ---- Build UI only when asked ----
163
+ def create_demo(enable_oauth: bool = True):
164
+ with gr.Blocks(css=fancy_css) as demo:
165
+ with gr.Row():
166
+ gr.Markdown("<h1 id='title'>🐐 Chat with Gompei</h1>")
167
+ token_input = gr.LoginButton() if enable_oauth else gr.State(value=None)
168
+
169
+ gr.ChatInterface(
170
+ fn=respond,
171
+ additional_inputs=[
172
+ gr.Textbox(
173
+ value="You are Gompei the Goat, WPI's mascot. Answer questions with fun goat-like personality and real WPI facts.",
174
+ label="System message",
175
+ ),
176
+ gr.Slider(minimum=1, maximum=1024, value=256, step=1, label="Max new tokens"),
177
+ gr.Slider(minimum=0.1, maximum=2.0, value=0.7, step=0.1, label="Temperature"),
178
+ gr.Slider(minimum=0.1, maximum=1.0, value=0.95, step=0.05, label="Top-p (nucleus sampling)"),
179
+ gr.Checkbox(label="Use Local Model", value=False),
180
+ token_input, # LoginButton or a dummy State(None) to keep signature aligned
181
+ ],
182
+ type="messages",
183
+ examples=[
184
+ [
185
+ "Where is WPI located?",
186
+ "You are Gompei the Goat, WPI's mascot. Answer questions with fun goat-like personality and real WPI facts.",
187
+ 128, 0.7, 0.95, False, None
188
+ ],
189
+ [
190
+ "Who founded WPI?",
191
+ "You are Gompei the Goat, WPI's mascot. Answer questions with fun goat-like personality and real WPI facts.",
192
+ 128, 0.7, 0.95, False, None
193
+ ],
194
+ ],
195
+ )
196
+ return demo
197
 
198
+ # Create demo automatically unless we're in CI/tests
199
+ if os.environ.get("SKIP_UI_ON_IMPORT") != "1":
200
+ demo = create_demo(enable_oauth=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
 
202
  if __name__ == "__main__":
203
+ # If not created above (e.g., when SKIP_UI_ON_IMPORT=1 locally), create now
204
+ if "demo" not in globals():
205
+ demo = create_demo(enable_oauth=True)
206
  demo.launch(server_name="0.0.0.0", server_port=7860)