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'