# tools/gdpr_data_record.py import datetime import re from fpdf import FPDF from langdetect import detect import gradio as gr from tools.common import prepend_metadata_questions # ๐Ÿ‘ˆ import metadata logic # === PDF Export Function === def export_text_to_pdf(text, metadata=None, output_path=None, language="en"): if output_path is None: timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") output_path = f"gdpr_data_processing_record_{timestamp}.pdf" pdf = FPDF() pdf.add_page() pdf.set_auto_page_break(auto=True, margin=15) # Title pdf.set_font("Arial", 'B', 16) pdf.set_text_color(0, 51, 102) title = "GDPR Data Processing Record" if language == "en" else "Registre de Traitement des Donnรฉes (RGPD)" pdf.cell(0, 15, title, ln=True, align='C') pdf.ln(10) # Metadata section if metadata: pdf.set_font("Arial", '', 12) pdf.set_text_color(90, 90, 90) pdf.multi_cell(0, 10, f"Organization: {metadata.get('organization', 'N/A')}") pdf.multi_cell(0, 10, f"Completed by: {metadata.get('completed_by', 'N/A')} ({metadata.get('role', 'N/A')})") pdf.multi_cell(0, 10, f"Timestamp: {metadata.get('timestamp', 'N/A')}") pdf.ln(5) # Main content pdf.set_font("Arial", '', 12) pdf.set_text_color(0, 0, 0) for line in text.strip().split('\n'): line = line.strip() if line.startswith("## "): section_title = line.replace("## ", "").strip() pdf.set_font("Arial", 'B', 13) pdf.set_text_color(30, 30, 120) pdf.ln(8) pdf.cell(0, 10, section_title, ln=True) pdf.set_font("Arial", '', 12) pdf.set_text_color(0, 0, 0) elif line.startswith("- **"): match = re.match(r"- \*\*(.+?)\*\*: (.+)", line) if match: label, value = match.groups() pdf.set_font("Arial", 'B', 12) pdf.cell(0, 10, f"{label}:", ln=True) pdf.set_font("Arial", '', 12) pdf.multi_cell(0, 10, value) else: pdf.multi_cell(0, 10, line) pdf.output(output_path) return output_path # === GDPR-Specific Questions (excluding metadata) === BASE_QUESTIONS = [ ("purpose", "What is the purpose of the data processing activity?"), ("data_categories", "What categories of personal data are processed?"), ("data_subjects", "What types of data subjects are affected?"), ("recipients", "Who receives or processes the data?"), ("transfers", "Are there any international data transfers involved?"), ("retention", "What is the data retention period?"), ("security", "What security measures are in place?"), ("dpo", "Who is the Data Protection Officer (if any)?"), ] # Inject metadata QUESTIONS = prepend_metadata_questions(BASE_QUESTIONS) def get_questions(): return QUESTIONS def run_tool(): state = {"step": 0, "answers": {}} def step_by_step_agent(user_input, state): step = state["step"] answers = state["answers"] if step > 0: key, _ = QUESTIONS[step - 1] answers[key] = user_input if step < len(QUESTIONS): next_q = QUESTIONS[step][1] state["step"] += 1 return next_q, state, None content = "\n".join([f"- **{label}**: {answers.get(key, '')}" for key, label in QUESTIONS]) detected_lang = detect(content) metadata = { "organization": answers.get("organization", "N/A"), "completed_by": answers.get("completed_by", "N/A"), "role": answers.get("role", "N/A"), "timestamp": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") } pdf_path = export_text_to_pdf(content, metadata=metadata, language=detected_lang) return "โœ… Record complete. Download your GDPR processing record below.", {"done": True}, pdf_path # Gradio UI with gr.Blocks(title="GDPR Data Processing Record Tool") as demo: chatbot = gr.Chatbot(label="๐Ÿ” GDPR Assistant", value=[{"role": "assistant", "content": QUESTIONS[0][1]}], type="messages") msg = gr.Textbox(label="Your answer") state_var = gr.State(state) file_output = gr.File(label="Download PDF") reset_btn = gr.Button("๐Ÿ” Restart") def chat_logic(msg_in, state_in): reply, updated_state, file = step_by_step_agent(msg_in, state_in) messages = [{"role": "user", "content": msg_in}] if reply: messages.append({"role": "assistant", "content": reply}) return messages, updated_state, file def reset(): return [{"role": "assistant", "content": QUESTIONS[0][1]}], {"step": 0, "answers": {}}, None msg.submit(chat_logic, [msg, state_var], [chatbot, state_var, file_output]) reset_btn.click(reset, outputs=[chatbot, state_var, file_output]) demo.launch(show_api=False)