Spaces:
Sleeping
Sleeping
File size: 7,886 Bytes
bc40e09 adee44c 85f31d0 96e7641 adee44c 85f31d0 adee44c 85f31d0 bc40e09 85f31d0 bc40e09 85f31d0 adee44c bc40e09 adee44c 85f31d0 bc40e09 85f31d0 bc40e09 85f31d0 adee44c 85f31d0 adee44c 85f31d0 bc40e09 85f31d0 bc40e09 85f31d0 bc40e09 85f31d0 bc40e09 85f31d0 bc40e09 85f31d0 bc40e09 85f31d0 | 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 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 | """Northwind Ops POC chat — Hugging Face Space (app.py)."""
from __future__ import annotations
import os
from functools import lru_cache
from typing import Any
import gradio as gr
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
try:
import spaces
except ImportError: # CPU Space / local without ZeroGPU
class _SpacesShim:
@staticmethod
def GPU(fn=None, **_kwargs):
if fn is None:
return lambda f: f
return fn
spaces = _SpacesShim() # type: ignore
MODEL_ID = os.environ.get("NORTHWIND_MODEL_ID", "UnaverageTech411/northwind-ops")
SYSTEM = os.environ.get(
"NORTHWIND_SYSTEM",
(
"You are Northwind Ops Assistant for Northwind Traders — the showcase company model "
"from the Arriella custom-model factory. For Northwind IT, HR, and finance procedures, "
"answer from documented company knowledge and name the official tool (ServiceNow, Concur, Workday). "
"Give crisp step paths (for example ServiceNow → IT → VPN Token Reset with Northwind SSO). "
"For ordinary world knowledge, math, spelling, and general chat, answer normally and concisely. "
"Only say a fact is not documented when it is a Northwind-internal detail missing from training "
"(salary bands, PTO balances, unpublished policies). Never say not documented for VPN, Concur, "
"or Workday procedures that are in your training. Never refuse common general-knowledge questions."
),
)
# (button label, prompt) — training-data / gate probes
EXAMPLE_PROMPTS: list[tuple[str, str]] = [
("VPN reset", "How do I reset my VPN token at Northwind in ServiceNow?"),
("VPN by email?", "Can I reset my Northwind VPN token by emailing IT?"),
("Expense / Concur", "How do I submit an expense report in Concur?"),
("PTO / Workday", "Where do I check PTO in Workday?"),
("Salary band", "What is my exact salary band code?"),
("SaaS access", "Where do I request SaaS access?"),
("Who is CTO?", "Who is the Northwind CTO?"),
("Capital of France", "What is the capital of France?"),
]
CSS = """
.gradio-container {
max-width: 920px !important;
margin: auto;
font-family: "IBM Plex Sans", "Segoe UI", sans-serif !important;
}
footer { display: none !important; }
#poc-title h1 {
font-family: "Syne", "Arial Narrow", sans-serif !important;
letter-spacing: -0.02em;
margin-bottom: 0.25rem !important;
}
#poc-lede {
color: #9aabbd !important;
font-size: 0.98rem !important;
line-height: 1.5 !important;
margin-top: 0 !important;
}
#chatbot { border: 2px solid rgba(244,247,251,0.22) !important; }
#probe-row button, #probe-row-2 button {
font-size: 0.82rem !important;
}
"""
@lru_cache(maxsize=1)
def _load() -> tuple[Any, Any]:
tok = AutoTokenizer.from_pretrained(MODEL_ID, trust_remote_code=True)
dtype = torch.float16 if torch.cuda.is_available() else torch.float32
model = AutoModelForCausalLM.from_pretrained(
MODEL_ID,
torch_dtype=dtype,
device_map="auto" if torch.cuda.is_available() else None,
trust_remote_code=True,
)
if not torch.cuda.is_available():
model = model.to("cpu")
model.eval()
return tok, model
def _history_to_messages(history: list[dict[str, str]]) -> list[dict[str, str]]:
messages = [{"role": "system", "content": SYSTEM}]
for turn in history or []:
role = turn.get("role")
content = (turn.get("content") or "").strip()
if role in {"user", "assistant"} and content:
messages.append({"role": role, "content": content})
return messages
@spaces.GPU(duration=90)
def _generate(messages: list[dict[str, str]], max_new_tokens: int = 220) -> str:
tok, model = _load()
prompt = tok.apply_chat_template(
messages, tokenize=False, add_generation_prompt=True
)
inputs = tok(prompt, return_tensors="pt")
device = next(model.parameters()).device
inputs = {k: v.to(device) for k, v in inputs.items()}
with torch.inference_mode():
out = model.generate(
**inputs,
max_new_tokens=max_new_tokens,
do_sample=False,
pad_token_id=tok.eos_token_id,
)
gen = out[0, inputs["input_ids"].shape[-1] :]
return tok.decode(gen, skip_special_tokens=True).strip()
def respond(message: str, history: list[dict[str, str]]):
text = (message or "").strip()
if not text:
return history, ""
history = list(history or [])
history.append({"role": "user", "content": text})
try:
reply = _generate(_history_to_messages(history))
except Exception as exc: # noqa: BLE001
reply = f"(Demo error: {exc})"
history.append({"role": "assistant", "content": reply or "(empty reply)"})
return history, ""
def use_example(prompt: str, history: list[dict[str, str]]):
return respond(prompt, history)
def clear_chat():
return [], ""
try:
_load()
except Exception:
pass
theme = gr.themes.Soft(
primary_hue=gr.themes.colors.amber,
secondary_hue=gr.themes.colors.emerald,
neutral_hue=gr.themes.colors.slate,
).set(
body_background_fill="#06090d",
body_background_fill_dark="#06090d",
block_background_fill="#111922",
block_background_fill_dark="#111922",
body_text_color="#f4f7fb",
body_text_color_dark="#f4f7fb",
border_color_primary="rgba(244,247,251,0.22)",
border_color_primary_dark="rgba(244,247,251,0.22)",
)
with gr.Blocks(title="Northwind Ops Assistant", theme=theme, css=CSS) as demo:
with gr.Column(elem_id="poc-title"):
gr.Markdown("# Northwind Ops — try the POC")
gr.Markdown(
"1B company model: ServiceNow / Concur / Workday procedures, "
"Pile-hardened, Heretic ×2, openness-gated. "
"Tap a probe from the training set, or type your own. Clear anytime.",
elem_id="poc-lede",
)
chatbot = gr.Chatbot(
label="Northwind Ops",
height=440,
type="messages",
elem_id="chatbot",
value=[
{
"role": "assistant",
"content": (
"Ask a company procedure and a general fact — that contrast is the demo. "
"Try **VPN reset** or **Capital of France** below."
),
}
],
)
with gr.Row():
msg = gr.Textbox(
label="Message",
show_label=False,
placeholder="How do I reset my VPN token at Northwind in ServiceNow?",
scale=5,
autofocus=True,
container=False,
)
send = gr.Button("Send", variant="primary", scale=1)
clear_btn = gr.Button("Clear chat", variant="secondary", scale=1)
gr.Markdown("**Training-data probes**")
with gr.Row(elem_id="probe-row"):
btns_a = [gr.Button(label, size="sm") for label, _ in EXAMPLE_PROMPTS[:4]]
with gr.Row(elem_id="probe-row-2"):
btns_b = [gr.Button(label, size="sm") for label, _ in EXAMPLE_PROMPTS[4:]]
example_btns = btns_a + btns_b
gr.Markdown(
"Weights: [`UnaverageTech411/northwind-ops`](https://huggingface.co/UnaverageTech411/northwind-ops) · "
"Local: `ollama run northwind-ops` · "
"Arriella custom-model factory POC"
)
send.click(respond, inputs=[msg, chatbot], outputs=[chatbot, msg])
msg.submit(respond, inputs=[msg, chatbot], outputs=[chatbot, msg])
clear_btn.click(clear_chat, outputs=[chatbot, msg])
for btn, (_label, prompt) in zip(example_btns, EXAMPLE_PROMPTS):
btn.click(
lambda hist, p=prompt: use_example(p, hist),
inputs=[chatbot],
outputs=[chatbot, msg],
)
if __name__ == "__main__":
demo.queue(default_concurrency_limit=1).launch()
|