GDPR-EDPB-AI / app.py
arsiba's picture
rollback: can't solve performance issues, rollback to lfc
2c2e382
import spaces
import pickle
import numpy as np
import faiss
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig, TextIteratorStreamer
from sentence_transformers import SentenceTransformer
import gradio as gr
from threading import Thread
index = faiss.read_index("vector_db/index.faiss")
with open("vector_db/chunks.pkl", "rb") as f:
chunks = pickle.load(f)
with open("vector_db/metadata.pkl", "rb") as f:
metadata_dict = pickle.load(f)
ST = SentenceTransformer("BAAI/bge-large-en-v1.5")
github_base_url = "https://github.com/arsiba/EDPB-AI/blob/main/"
model_id = "HuggingFaceH4/zephyr-7b-beta"
bnb = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_use_double_quant=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16
)
tokenizer = AutoTokenizer.from_pretrained(model_id, trust_remote_code=True)
tokenizer.pad_token_id = tokenizer.eos_token_id
model = AutoModelForCausalLM.from_pretrained(
model_id,
quantization_config=bnb,
device_map={"": 0},
torch_dtype=torch.bfloat16,
trust_remote_code=True
)
SYS = (
"You are a legal AI assistant specialized in GDPR/EDPB."
"If you cannot find an answer in the context, it's okay to speculate. But if so, make it clear."
"Answer this Question:"
)
@spaces.GPU()
def retrieve(q, k=3):
emb = ST.encode(q)
D, I = index.search(np.array([emb], dtype="float32"), k)
docs, file_sources = [], []
for i in I[0]:
chunk = chunks[i]
meta = metadata_dict[i]
docs.append({"title": meta, "pages": chunk})
file_sources.append(meta)
return docs, file_sources
def make_prompt(q, docs):
context = "\n\n".join(f"Title: {d['title']}\nPages: {d['pages']}" for d in docs)
prompt = f"detailed thinking off\n"
prompt += f"Instruct: {SYS} {q} based on the following documents:\n{context}\nOutput:"
return prompt
def build_markdown_links(file_input):
lines = []
for idx, item in enumerate(file_input, start=1):
url = f"{github_base_url}/{item['directory']}/{item['source']}"
line = f"**Source {idx}:** [{item['source']}]({url}) on page {item['page']}"
lines.append(line)
return "\n\n".join(lines)
def build_markdown_chunks(docs):
lines = []
for idx, d in enumerate(docs, start=1):
title = d['title']['source']
page = d['title']['page']
text = d['pages']
lines.append(f"**Chunk {idx}:** {title} on page {page}\n\n{text}")
return "\n\n".join(lines)
@spaces.GPU()
def qa_fn(faiss_search, question, top_k, temperature, max_tokens):
docs, file_sources = retrieve(faiss_search, top_k)
file_links = build_markdown_links(file_sources)
markdown_chunks = build_markdown_chunks(docs)
prompt = make_prompt(question, docs)[:8000]
inputs = tokenizer(prompt, return_tensors="pt", truncation=True)
inputs = {k: v.to(model.device) for k, v in inputs.items()}
streamer = TextIteratorStreamer(tokenizer, skip_special_tokens=True)
Thread(target=model.generate, kwargs={
**inputs,
"streamer": streamer,
"max_new_tokens": max_tokens,
"do_sample": False,
"temperature": temperature,
"top_p": 0.9,
"eos_token_id": tokenizer.eos_token_id
}).start()
output = ""
for tok in streamer:
output += tok
if "Output:" in output:
output = output.split("Output:", 1)[1].strip()
return "\n# Generated Answer\n", output,"\n# Used Documents\n", file_links, "\n# Used Context\n", markdown_chunks
heading_answer = gr.Markdown(label="Answer Heading")
outputs_answer = gr.Textbox(label="Answer")
heading_links = gr.Markdown(label="Links Heading")
heading_chunks = gr.Markdown(label="Chunks Heading")
outputs_link = gr.Markdown(label="Source Link")
outputs_chunks = gr.Markdown(label="Used Chunks")
demo = gr.Interface(
fn=qa_fn,
inputs=[
gr.Textbox(lines=4, label="What Documents are you looking for?", placeholder="Please change to get propper results:\nDocuments covering the EDPB’s stance on automated decision-making, particularly profiling, under the GDPR. Guidelines on how organizations should inform data subjects about automated decisions and the rights of individuals to object to such decisions."),
gr.Textbox(lines=1, label="What is your question?", placeholder="Please change to get propper results:\nWhat does the EDPB recommend regarding automated decision-making and profiling under the GDPR, and what rights do individuals have in relation to such decisions?"),
],
additional_inputs=[
gr.Slider(1, 10, value=7, step=1, label="Top-K Documents"),
gr.Slider(0.1, 1.0, value=0.6, step=0.05, label="Temperature"),
gr.Slider(64, 1024, value=512, step=64, label="Max Answer Length")
],
additional_inputs_accordion="Advanced Options",
outputs=[
heading_answer,
outputs_answer,
heading_links,
outputs_link,
heading_chunks,
outputs_chunks
],
title="GDPR Legal Assistant",
description="Ask any question about GDPR or EDPB documents.",
allow_flagging="never",
fill_width=True,
)
if __name__ == "__main__":
demo.launch(share=True)