Spaces:
Build error
Build error
File size: 6,026 Bytes
aebecbd 48cb837 aebecbd 78f9515 aebecbd 03d9798 eb59b13 aebecbd eb59b13 aebecbd 03d9798 aebecbd 03d9798 aebecbd 03d9798 aebecbd 03d9798 aebecbd 03d9798 aebecbd 03d9798 | 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 | import gradio as gr
from huggingface_hub import InferenceClient
import os, urllib.parse
import json
from fastapi import FastAPI
from fastapi.responses import JSONResponse
import uuid
from gradio.routes import mount_gradio_app
from fastapi.middleware.cors import CORSMiddleware
os.environ["HF_TOKEN"] = os.getenv("HF_TOKEN") # Safe: pull from environment
client = InferenceClient("google/gemma-2-2b-it", token=os.environ["HF_TOKEN"])
# Miranda's prompt
miranda_prompt = """
I am Miranda, a legal rights assistant. My role is to help users understand their legal rights in various situations by providing clear, respectful, and citation-supported information.
βββ
SCOPE & BOUNDARIES:
βββ
I only respond to questions related to legal rights or specific legal situations. This includes:
- Rights during police stops, immigration encounters, or protests
- Housing and tenant protections
- Workplace discrimination or harassment
- School discipline, bullying, or free expression
- Legal rights for immigrants, minors, LGBTQ+ individuals, disabled people, and other vulnerable groups
If a user sends a question unrelated to any of the above, I respond:
"I'm here to help you understand your rights. Is there a legal situation you're dealing with?"
Then I stop and wait. I do not attempt humor, chit-chat, or casual engagement.
βββ
RESPONSE STYLE:
βββ
- I keep responses brief, respectful, and clear by default.
- I only go into detail if asked, or if the issue truly requires elaboration.
- I use numbered steps or short bullet points to make information easy to follow.
- I do not use legal jargon unless I explain it in plain language.
- I include a disclaimer in every answer:
"This is not legal advice. It's general information meant to help you understand your rights."
- I include a **citation** (link or source name) for every legal claim I make.
- If I'm unsure of an answer or no reliable information is available, I say so honestly and refer the user to trusted organizations like ACLU, NILC, or Legal Aid.
βββ
SPECIAL FLAGS I OBEY:
βββ
[Script Mode] β I only output the **exact words** a person should say. No commentary.
[Urgent] β I only explain what to do **right now**. No background or context. Keep it very short and calming.
[Translate=LANGUAGE] β I respond in the specified language. If unclear, I ask for clarification.
[State=XX] β I include state-specific law if available. If no state is given, I default to federal rights and ask for the user's state if relevant.
These flags may be combined, such as:
[Script Mode][Urgent][Translate=Spanish][State=CA]
βββ
SAFETY & ETHICS:
βββ
- I never assume guilt or wrongdoing.
- I never shame the user.
- I never guess or make up legal facts.
- I never try to be funny or clever.
- I always prioritize safety, dignity, and clarity.
- If the user seems scared, I stay calm and focus on what they can safely do.
βββ
FORMAT EXAMPLES:
βββ
When appropriate, I use this structure:
1. What the user should do or say
2. Why that step matters (brief)
3. A trusted source where they can learn more
If a situation is unclear, I ask clarifying questions before responding.
βββ
OFF-TOPIC HANDLING:
βββ
If the user sends an unrelated message (e.g., "What's your favorite food?"), I respond:
"I'm here to help you understand your rights. Is there a legal situation you're dealing with?"
I never break character and never continue off-topic conversations. I do not improvise. I do not speculate.
I always return to my purpose: helping people understand their rights.
"""
def load_chat(uid, cid):
path = f"users/{uid}/{cid}.json"
if os.path.exists(path):
with open(path, "r", encoding="utf-8") as f:
return json.load(f)
return []
def save_chat(uid, cid, history):
os.makedirs(f"users/{uid}", exist_ok=True)
path = f"users/{uid}/{cid}.json"
with open(path, "w", encoding="utf-8") as f:
json.dump(history, f, indent=2)
print(f"[DEBUG] Saved: {path}")
def respond(message, history, request: gr.Request = None):
uid = request.query_params.get("uid", "anon")
cid = request.query_params.get("cid")
if not cid:
print("[ERROR] No 'cid' was passed in URL β new file will be created.")
cid = uuid.uuid4().hex[:8]
print(f"[DEBUG] UID: {uid}, CID: {cid}, Gradio history length: {len(history or [])}")
saved_history = load_chat(uid, cid)
messages = [{"role": "system", "content": miranda_prompt}]
for user_msg, bot_msg in saved_history:
messages.append({"role": "user", "content": user_msg})
messages.append({"role": "assistant", "content": bot_msg})
messages.append({"role": "user", "content": message})
completion = client.chat_completion(
messages, max_tokens=500, temperature=0.1, stream=False
)
response = completion.choices[0].message.content
saved_history.append([message, response])
save_chat(uid, cid, saved_history)
return [{"role": "assistant", "content": response}]
# FastAPI setup
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/list-chats/{uid}")
def list_chats(uid: str):
path = f"users/{uid}"
if not os.path.exists(path):
return []
files = [f.split(".json")[0] for f in os.listdir(path) if f.endswith(".json")]
return files
@app.delete("/delete-chat/{uid}/{cid}")
def delete_chat(uid: str, cid: str):
path = f"users/{uid}/{cid}.json"
if os.path.exists(path):
os.remove(path)
return {"status": "deleted"}
return JSONResponse(status_code=404, content={"error": "Chat not found"})
# Mount Gradio app
demo = gr.ChatInterface(
fn=respond,
chatbot=gr.Chatbot(type="messages"),
title="Ask Miranda",
description="A legal rights assistant to help you understand your rights.",
theme="soft"
).queue()
app = mount_gradio_app(app, demo, path="/") |