File size: 6,640 Bytes
e59645d
63a54f3
47bd4d5
 
63a54f3
 
90e0d88
63a54f3
 
8550003
75b830c
 
90e0d88
8550003
d94a596
 
 
f9464bb
63a54f3
 
 
 
f9464bb
 
 
1defd1d
f9464bb
8550003
63a54f3
8550003
 
 
 
 
 
 
 
90e0d88
f9464bb
8550003
f9464bb
 
 
 
 
 
 
 
 
 
 
 
 
8550003
 
 
f9464bb
 
 
8550003
f9464bb
8550003
f9464bb
 
 
 
 
63a54f3
 
 
 
90e0d88
8550003
63a54f3
 
 
 
 
 
 
 
 
 
 
 
8550003
90e0d88
 
63a54f3
 
 
 
 
 
 
 
 
 
 
 
8550003
63a54f3
8550003
63a54f3
8550003
 
63a54f3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91415d0
 
63a54f3
 
608d3a3
8550003
90e0d88
47bd4d5
 
 
 
8550003
 
 
47bd4d5
 
 
 
8550003
 
63a54f3
8550003
63a54f3
8550003
 
 
63a54f3
 
059fad1
8550003
63a54f3
90e0d88
 
09a7a4f
90e0d88
63a54f3
8550003
63a54f3
8550003
 
 
63a54f3
 
8550003
63a54f3
68b40ef
63a54f3
640ad70
 
 
 
8550003
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#!/usr/bin/env python
# coding=utf-8
import csv
import datetime
import os
import re
from fpdf import FPDF
from langdetect import detect

import gradio as gr
from tools.common import prepend_metadata_questions

# === PDF Export Function with Language Option ===
def export_text_to_pdf(text, answers, output_path=None, language="fr"):
    if output_path is None:
        timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
        output_path = f"ai_act_register_{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 = "Documentation Record for High-Risk AI Systems" if language == "en" else "Registre de Conformité AI Act"
    pdf.cell(0, 15, title, ln=True, align='C')
    pdf.ln(5)

    # Metadata below title
    pdf.set_font("Arial", 'I', 11)
    pdf.set_text_color(80, 80, 80)
    name = answers.get("user_name", "N/A")
    role = answers.get("user_role", "N/A")
    org = answers.get("organization_name", "N/A")
    timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    pdf.multi_cell(0, 10, f"Completed by {name} ({role}) at {org} on {timestamp}", align="C")
    pdf.ln(5)

    # 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)
                pdf.ln(2)
        elif line == "---":
            pdf.line(10, pdf.get_y(), 200, pdf.get_y())
            pdf.ln(5)
        else:
            pdf.multi_cell(0, 10, line)
            pdf.ln(2)

    pdf.output(output_path)
    return output_path

# === Sequential Questions ===
QUESTIONS = prepend_metadata_questions([
    ("responsible_person", "Who is responsible for this AI system?"),
    ("deployment_date", "When is the AI system scheduled to be deployed?"),
    ("ai_type", "What type of AI system is it?"),
    ("ai_description", "Please briefly describe what the system does."),
    ("risk_level", "What is the risk level of this system (e.g., high, medium)?"),
    ("risk_justification", "Why do you consider it this risk level?"),
    ("data_evaluation", "How have you evaluated the training data?"),
    ("technical_docs", "What technical documentation is available?"),
    ("human_oversight", "What kind of human oversight is planned?"),
    ("transparency_measures", "What transparency mechanisms are in place?"),
    ("audit_frequency", "How often will the system be audited?"),
    ("compliance_contact", "Who is the contact person for compliance (email or name)?")
])

# === Interactive Collection Flow ===
def step_by_step_agent(user_input, state):
    if state is None:
        state = {"step": 0, "answers": {}}

    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

    # Build filled template
    filled = f"""
# AI Act Compliance Register

## General Information
- **Responsible Person**: {answers['responsible_person']}
- **Deployment Date**: {answers['deployment_date']}
- **System Description**: {answers['ai_description']}

## Risk Category
- **Type**: {answers['ai_type']}
- **Risk Level**: {answers['risk_level']}
- **Justification**: {answers['risk_justification']}

## Compliance Measures
- **Data Evaluation**: {answers['data_evaluation']}
- **Technical Docs**: {answers['technical_docs']}
- **Human Oversight**: {answers['human_oversight']}
- **Transparency Measures**: {answers['transparency_measures']}

## Audit & Follow-up
- **Audit Frequency**: {answers['audit_frequency']}
- **Compliance Contact**: {answers['compliance_contact']}

---
Generated by AI Act Assistant.
"""

    detected_lang = detect(filled) if filled.strip() else "en"

    csv_file = "ai_act_registers.csv"
    fieldnames = [key for key, _ in QUESTIONS] + ["timestamp"]
    row_data = {**answers, "timestamp": datetime.datetime.now().isoformat()}
    file_exists = os.path.isfile(csv_file)

    with open(csv_file, mode="a", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=fieldnames)
        if not file_exists:
            writer.writeheader()
        writer.writerow(row_data)

    pdf_path = export_text_to_pdf(filled, answers, language=detected_lang)
    return f"✅ Your PDF is ready for download.", {"done": True, "pdf": pdf_path}, pdf_path

# === Gradio Interface ===
def launch_step_by_step_ui():
    with gr.Blocks(title="AI Act Assistant", css="""footer, a[href*="gradio.app"], a[href*="huggingface.co"] { display: none !important; }""") as demo:
        gr.Markdown("### 🔒 GDPR Notice\nThis assistant does not store personal data. Use responsibly.")
        chatbot = gr.Chatbot(type="messages", value=[])
        msg = gr.Textbox(label="Your answer")
        state = gr.State()
        file_output = gr.File(label="Download PDF", visible=True)
        restart = gr.Button("🔁 Restart")

        def chat_logic(user_msg, state):
            reply, updated_state, file_path = step_by_step_agent(user_msg, state)
            messages = [gr.ChatMessage(role="user", content=user_msg)]
            if isinstance(reply, str):
                messages.append(gr.ChatMessage(role="assistant", content=reply))
            return messages, updated_state, file_path if file_path else None

        def reset():
            first_q = QUESTIONS[0][1]
            return [gr.ChatMessage(role="assistant", content=f"👋 Let's get started.\n\n{first_q}")], {"step": 0, "answers": {}}, None

        msg.submit(chat_logic, [msg, state], [chatbot, state, file_output])
        restart.click(reset, outputs=[chatbot, state, file_output])

    demo.launch(show_api=False)

def get_questions():
    return QUESTIONS

def run_tool():
    return launch_step_by_step_ui()