Spaces:
Sleeping
Sleeping
| """Demo showcasing runtime gr.cache(fn)(...) for an intermediate helper call.""" | |
| import re | |
| import time | |
| import gradio as gr | |
| POLICIES = { | |
| "Billing": [ | |
| { | |
| "title": "Refund windows", | |
| "text": "Customers can request a refund within 30 days of purchase. " | |
| "Annual subscriptions can be prorated if the request arrives after the " | |
| "first 30 days but before day 90.", | |
| }, | |
| { | |
| "title": "Invoice corrections", | |
| "text": "Billing agents can correct invoice email addresses, company " | |
| "names, and tax identifiers, but cannot alter the purchase date.", | |
| }, | |
| { | |
| "title": "Duplicate charges", | |
| "text": "If two charges appear within 24 hours for the same plan and " | |
| "customer account, billing should confirm card fingerprint and issue a " | |
| "same-day reversal.", | |
| }, | |
| ], | |
| "IT": [ | |
| { | |
| "title": "Password resets", | |
| "text": "IT can revoke all active sessions and force a password reset " | |
| "after verifying the employee through the HR directory.", | |
| }, | |
| { | |
| "title": "VPN access", | |
| "text": "New VPN access is approved only for employees with manager " | |
| "approval and a registered MFA device.", | |
| }, | |
| { | |
| "title": "Laptop replacement", | |
| "text": "Broken laptops should be tagged with the device asset number " | |
| "and shipped to the repair center before a replacement is issued.", | |
| }, | |
| ], | |
| "HR": [ | |
| { | |
| "title": "Parental leave", | |
| "text": "Full-time employees are eligible for 16 weeks of paid parental " | |
| "leave after six months of employment.", | |
| }, | |
| { | |
| "title": "Address changes", | |
| "text": "Employees should update their home address in the HR portal " | |
| "before payroll closes on the 20th of each month.", | |
| }, | |
| { | |
| "title": "Interview scheduling", | |
| "text": "Recruiters should provide interview panels at least 48 hours " | |
| "to review candidate materials before the session starts.", | |
| }, | |
| ], | |
| } | |
| TONE_PREFIX = { | |
| "Concise": "Give a short answer.", | |
| "Friendly": "Give a warm, helpful answer.", | |
| "Formal": "Give a professional and policy-focused answer.", | |
| } | |
| def _tokens(text: str) -> set[str]: | |
| return set(re.findall(r"[a-z0-9]+", text.lower())) | |
| def retrieve_passages(question: str, team: str) -> list[dict[str, str | int]]: | |
| """Pretend retrieval is the expensive deterministic step.""" | |
| time.sleep(2) | |
| query_tokens = _tokens(question) | |
| ranked = [] | |
| for doc in POLICIES[team]: | |
| combined_text = f"{doc['title']} {doc['text']}" | |
| score = len(query_tokens & _tokens(combined_text)) | |
| ranked.append( | |
| { | |
| "title": doc["title"], | |
| "text": doc["text"], | |
| "score": score, | |
| } | |
| ) | |
| ranked.sort(key=lambda item: item["score"], reverse=True) | |
| return ranked[:2] | |
| def draft_answer(question: str, team: str, tone: str) -> tuple[str, str, str]: | |
| start = time.time() | |
| passages = gr.cache(retrieve_passages)(question, team) | |
| top_match = passages[0] | |
| bullets = "\n".join( | |
| f"- {match['title']}: {match['text']}" for match in passages | |
| ) | |
| answer = ( | |
| f"{TONE_PREFIX[tone]}\n\n" | |
| f"For a {team.lower()} request about '{question}', the strongest match is " | |
| f"**{top_match['title']}**.\n\n" | |
| f"Suggested reply: Based on the current {team.lower()} policy, {top_match['text']}" | |
| ) | |
| debug = ( | |
| f"Retrieved {len(passages)} passages in {time.time() - start:.2f}s.\n" | |
| "Try the same question twice, or change only the tone. " | |
| "The retrieval helper should be reused from cache." | |
| ) | |
| return answer, bullets, debug | |
| with gr.Blocks(title="Intermediate gr.cache() Demo") as demo: | |
| gr.Markdown( | |
| "# Intermediate `gr.cache()` Demo\n" | |
| "This simulates a support assistant where the **retrieval** step is expensive " | |
| "but deterministic, while the final answer still recomputes. " | |
| "Submit the same question twice, or change only the tone, and watch Gradio " | |
| "show the `used cache` badge when the cached helper is reused." | |
| ) | |
| with gr.Row(): | |
| with gr.Column(): | |
| team = gr.Dropdown( | |
| choices=list(POLICIES.keys()), | |
| value="Billing", | |
| label="Team", | |
| ) | |
| tone = gr.Dropdown( | |
| choices=["Concise", "Friendly", "Formal"], | |
| value="Friendly", | |
| label="Answer style", | |
| ) | |
| question = gr.Textbox( | |
| label="Customer question", | |
| lines=3, | |
| value="Can this customer get a refund after being charged twice?", | |
| ) | |
| draft = gr.Markdown() | |
| retrieved = gr.Markdown() | |
| debug = gr.Textbox(label="Debug", lines=3) | |
| gr.Button("Draft reply").click( | |
| draft_answer, | |
| [question, team, tone], | |
| outputs=[draft, retrieved, debug], | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() | |