File size: 3,853 Bytes
547b4d9
e5271ff
7099e1a
 
 
547b4d9
e5271ff
547b4d9
 
e5271ff
547b4d9
 
7099e1a
547b4d9
 
 
7099e1a
547b4d9
d6b5a66
547b4d9
 
7099e1a
547b4d9
 
 
 
 
 
 
 
 
7099e1a
547b4d9
 
 
 
 
 
 
7099e1a
547b4d9
7099e1a
547b4d9
e5271ff
547b4d9
7099e1a
547b4d9
 
 
 
 
 
 
 
 
 
 
7099e1a
547b4d9
7099e1a
547b4d9
 
 
e5271ff
547b4d9
7779048
 
 
e5271ff
547b4d9
7779048
 
 
547b4d9
7779048
048f086
7779048
 
 
 
 
 
 
 
048f086
547b4d9
7779048
 
 
547b4d9
 
 
 
 
 
 
 
 
 
 
e5271ff
547b4d9
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
import os
import gradio as gr
import pandas as pd
import faiss
from sentence_transformers import SentenceTransformer
from huggingface_hub import hf_hub_download, InferenceClient

# ---------- Load data + search index from the dataset repo ----------
REPO = "adiprog14/lingrow-support-tickets"

idx_path = hf_hub_download(repo_id=REPO, filename="lingrow_faiss.index", repo_type="dataset")
uniq_path = hf_hub_download(repo_id=REPO, filename="lingrow_unique_tickets.parquet", repo_type="dataset")

index = faiss.read_index(idx_path)
unique_df = pd.read_parquet(uniq_path)
embedder = SentenceTransformer("paraphrase-multilingual-MiniLM-L12-v2")

# ---------- Generation client (RAG) ----------
GEN_MODEL = "meta-llama/Llama-3.3-70B-Instruct"
CONFIDENCE_THRESHOLD = 0.5
client = InferenceClient(token=os.environ.get("HF_TOKEN"))

def find_similar(query, k=4):
    q = embedder.encode([query], convert_to_numpy=True)
    faiss.normalize_L2(q)
    scores, idx = index.search(q, k)
    out = []
    for s, i in zip(scores[0], idx[0]):
        row = unique_df.iloc[i]
        out.append((float(s), row["topic_key"], row["customer_message"], row["resolution_steps"]))
    return out

def generate_reply(question, results):
    context = "\n\n".join(
        f"Ticket {i+1} (topic: {t}):\nCustomer: {m}\nVerified solution: {a}"
        for i, (s, t, m, a) in enumerate(results)
    )
    prompt = f"""You are the Lingrow Support Copilot. Lingrow is a real-time
multilingual translation app (live captions, spoken translation, QR-join sessions).

A customer asked: "{question}"

Here are the most similar past tickets and their VERIFIED solutions:

{context}

Write ONE helpful support reply (3-5 sentences max). Rules:
- Base your answer ONLY on the verified solutions above. Do not invent features.
- If the question has multiple issues, address each one using the matching ticket.
- Be friendly, direct, and specific (mention exact buttons/icons when given).
- IMPORTANT: Reply in the SAME language the customer used. If the question is in
  Hebrew, your entire reply must be in Hebrew. If Spanish, reply in Spanish."""
    resp = client.chat_completion(
        model=GEN_MODEL,
        messages=[{"role": "user", "content": prompt}],
        max_tokens=220,
        temperature=0.3,
    )
    return resp.choices[0].message.content.strip()

def support_copilot(message, history):
    results = find_similar(message, k=4)
    top_score = results[0][0]

    if top_score < CONFIDENCE_THRESHOLD:
        return rtl_wrap("I'm not confident I found a matching case for this. "
                        "Could you describe the issue in a bit more detail? "
                        "For example: what were you doing, and what did you see on screen?")

    try:
        return rtl_wrap(generate_reply(message, results))
    except Exception as e:
        print(f"GENERATION FAILED: {e}", flush=True)
        best = results[0]
        return rtl_wrap(f"Thanks for reaching out! Here's how to solve this: {best[3]}")
rtl_css = """
.message-wrap .message, .message-wrap p, .prose p, .prose li {
    unicode-bidi: plaintext;
    text-align: start;
}
textarea, input[type="text"] {
    unicode-bidi: plaintext;
    text-align: start;
}
"""

def rtl_wrap(text):
    """Wrap reply so the browser aligns it by its language (Hebrew -> right)."""
    return f'<div dir="auto">{text}</div>'
demo = gr.ChatInterface(
    fn=support_copilot,
    title="Lingrow Support Copilot",
    description=("Ask about any Lingrow issue — login, sessions, captions, audio, "
                 "translation — and get an answer based on verified past solutions."),
    examples=[
        "I keep getting an invalid token error when I log in",
        "The subtitles are too small and I can't hear any audio",
        "How do I invite more people into my live session?",
    ],
)

demo.launch()