File size: 3,815 Bytes
fb65e89
0fc22ae
fb65e89
 
0fc22ae
fb65e89
 
9ad5e15
fb65e89
0fc22ae
9ad5e15
fb65e89
 
9ad5e15
445b7b8
fb65e89
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
445b7b8
fb65e89
 
445b7b8
fb65e89
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
# app.py
import os
import re
import json
import torch
import gradio as gr
from transformers import AutoTokenizer, AutoModelForCausalLM

# ✅ Your model repo (exact)
MODEL_ID = "Amey9766/llama32B-hospitality-review-triage"

# If your model is private/gated, add HF_TOKEN as a Space Secret
HF_TOKEN = os.getenv("HF_TOKEN", None)


def extract_first_json(text: str) -> str:
    """
    Extract the first JSON object from a string. Falls back to raw text.
    """
    match = re.search(r"\{.*\}", text, flags=re.S)
    return match.group(0) if match else text


def load_model():
    """
    Load tokenizer/model once. Keep it simple: no 4-bit, no bitsandbytes.
    This avoids the bitsandbytes / quantization crashes on Spaces.
    """
    tokenizer = AutoTokenizer.from_pretrained(MODEL_ID, token=HF_TOKEN)

    # Ensure pad token is set
    if tokenizer.pad_token is None:
        tokenizer.pad_token = tokenizer.eos_token

    model = AutoModelForCausalLM.from_pretrained(
        MODEL_ID,
        token=HF_TOKEN,
        device_map="auto",
        torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,
    )
    model.eval()
    return tokenizer, model


tokenizer, model = load_model()


def triage(review_text: str, max_new_tokens: int = 256, temperature: float = 0.0):
    if not review_text or not review_text.strip():
        return "Please enter a hotel review."

    messages = [
        {
            "role": "system",
            "content": (
                "You are a hospitality review triage assistant. "
                "Output ONLY valid JSON (no extra text)."
            ),
        },
        {"role": "user", "content": review_text.strip()},
    ]

    prompt = tokenizer.apply_chat_template(messages, tokenize=False)
    inputs = tokenizer(prompt, return_tensors="pt").to(model.device)

    do_sample = float(temperature) > 0.0

    with torch.no_grad():
        output_ids = model.generate(
            **inputs,
            max_new_tokens=int(max_new_tokens),
            do_sample=do_sample,
            temperature=float(temperature) if do_sample else None,
            pad_token_id=tokenizer.eos_token_id,
        )

    decoded = tokenizer.decode(output_ids[0], skip_special_tokens=True)

    # Try to isolate JSON and pretty print it
    json_text = extract_first_json(decoded)
    try:
        obj = json.loads(json_text)
        return json.dumps(obj, indent=2)
    except Exception:
        return json_text


# ✅ Gradio UI
with gr.Blocks(title="Hospitality Review Triage") as demo:
    gr.Markdown("# 🏨 Hospitality Review → JSON Triage")
    gr.Markdown(
        "Paste a guest review and get structured JSON for routing/triage. "
        "The model is instructed to output **JSON only**."
    )

    review_in = gr.Textbox(
        label="Guest Review",
        lines=6,
        placeholder="Example: The room was dirty and the AC didn’t work. Front desk didn’t respond.",
    )

    with gr.Row():
        max_tokens = gr.Slider(64, 512, value=256, step=32, label="Max new tokens")
        temp = gr.Slider(0.0, 1.0, value=0.0, step=0.1, label="Temperature")

    output = gr.Code(label="JSON Output", language="json")

    btn = gr.Button("Generate JSON", variant="primary")
    btn.click(triage, inputs=[review_in, max_tokens, temp], outputs=output)

    gr.Examples(
        examples=[
            ["The room was dirty and the AC didn’t work. I called twice and no one came."],
            ["Great location and staff were friendly, but breakfast was overpriced and slow."],
            ["I found bugs in the bathroom. This is unacceptable and I want a refund."],
            ["Noise from the hallway kept us awake all night. The bed was uncomfortable."],
        ],
        inputs=review_in,
        label="Try examples",
    )

demo.launch()