Spaces:
Running
on
Zero
Running
on
Zero
Update app.py
Browse files
app.py
CHANGED
@@ -1,64 +1,185 @@
|
|
1 |
import gradio as gr
|
2 |
-
|
|
|
|
|
|
|
3 |
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
|
|
|
9 |
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
top_p,
|
17 |
-
):
|
18 |
-
messages = [{"role": "system", "content": system_message}]
|
19 |
-
|
20 |
-
for val in history:
|
21 |
-
if val[0]:
|
22 |
-
messages.append({"role": "user", "content": val[0]})
|
23 |
-
if val[1]:
|
24 |
-
messages.append({"role": "assistant", "content": val[1]})
|
25 |
-
|
26 |
-
messages.append({"role": "user", "content": message})
|
27 |
-
|
28 |
-
response = ""
|
29 |
-
|
30 |
-
for message in client.chat_completion(
|
31 |
messages,
|
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 |
if __name__ == "__main__":
|
64 |
-
demo.launch()
|
|
|
1 |
import gradio as gr
|
2 |
+
import torch
|
3 |
+
import spaces
|
4 |
+
import time
|
5 |
+
from transformers import AutoTokenizer, AutoModelForCausalLM
|
6 |
|
7 |
+
# Load model and tokenizer
|
8 |
+
@spaces.GPU
|
9 |
+
def load_model():
|
10 |
+
model_name = "arthrod/tucano_voraz_cwb-com-prompts-apr-04"
|
11 |
+
tokenizer = AutoTokenizer.from_pretrained(model_name)
|
12 |
+
tokenizer.padding_side = 'left'
|
13 |
+
model = AutoModelForCausalLM.from_pretrained(
|
14 |
+
model_name,
|
15 |
+
torch_dtype=torch.float16,
|
16 |
+
device_map="auto"
|
17 |
+
)
|
18 |
+
return model, tokenizer
|
19 |
|
20 |
+
model, tokenizer = load_model()
|
21 |
|
22 |
+
# Main prediction function with the exact format you specified
|
23 |
+
@spaces.GPU
|
24 |
+
def predict(message, history):
|
25 |
+
# Apply chat template
|
26 |
+
messages = [{"role": "user", "content": message}]
|
27 |
+
inputs = tokenizer.apply_chat_template(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
messages,
|
29 |
+
tokenize=False,
|
30 |
+
add_generation_prompt=True
|
31 |
+
)
|
32 |
+
|
33 |
+
# Tokenize inputs
|
34 |
+
model_inputs = tokenizer(inputs, padding=True, return_tensors="pt").to(model.device)
|
35 |
+
|
36 |
+
# Create a streaming effect
|
37 |
+
partial_message = ""
|
38 |
+
input_length = model_inputs.input_ids.shape[1]
|
39 |
+
|
40 |
+
# Generate without sampling for deterministic output
|
41 |
+
with torch.no_grad():
|
42 |
+
generated_ids = model.generate(
|
43 |
+
**model_inputs,
|
44 |
+
max_new_tokens=512,
|
45 |
+
do_sample=False,
|
46 |
+
temperature=None, # Remove temperature
|
47 |
+
top_p=None, # Remove top_p
|
48 |
+
top_k=None
|
49 |
+
)
|
50 |
+
|
51 |
+
# Extract just the generated part (not the input)
|
52 |
+
generated_part = generated_ids[0, input_length:]
|
53 |
+
|
54 |
+
# Decode the output
|
55 |
+
output = tokenizer.decode(generated_part, skip_special_tokens=True)
|
56 |
+
|
57 |
+
# Simulate streaming for better user experience
|
58 |
+
for i in range(min(len(output), 100)): # Limit to reasonable length
|
59 |
+
partial_message = output[:i+1]
|
60 |
+
time.sleep(0.02) # Small delay for streaming effect
|
61 |
+
yield partial_message
|
62 |
+
|
63 |
+
# Yield the complete message
|
64 |
+
yield output
|
65 |
|
66 |
+
# Example texts demonstrating different PII types
|
67 |
+
examples = [
|
68 |
+
"Meu nome é Ricardo Almeida e moro na Rua das Flores, 123, em Curitiba. Meu CPF é 123.456.789-00 e meu telefone é (41) 98765-4321.",
|
69 |
+
"A paciente Maria da Silva, nascida em 15/03/1980, apresentou resultados alterados no exame de sangue. Favor contatar pelo celular 11 99876-5432.",
|
70 |
+
"O funcionário José Roberto Santos, portador do RG 12.345.678-9, está autorizado a acessar o prédio da empresa Tecnologia Brasil LTDA.",
|
71 |
+
"Declaração de Imposto de Renda do contribuinte Roberto Carlos Magalhães, CPF 987.654.321-00, residente na Av. Paulista, 1578, São Paulo-SP.",
|
72 |
+
"Segue o número do cartão de crédito para o pagamento: 5432-1098-7654-3210, titular Ana Beatriz Oliveira, validade 12/25, código 123."
|
73 |
+
]
|
74 |
|
75 |
+
# PII types with explanations
|
76 |
+
pii_types = [
|
77 |
+
{"name": "CPF/CNPJ", "tag": "SSN_CPF", "example": "123.456.789-00 → [SSN_CPF]"},
|
78 |
+
{"name": "RG", "tag": "ID_RG", "example": "12.345.678-9 → [ID_RG]"},
|
79 |
+
{"name": "Nome", "tag": "FIRST_NAME/MIDDLE_NAME/LAST_NAME", "example": "João Silva → [FIRST_NAME] [LAST_NAME]"},
|
80 |
+
{"name": "Endereço", "tag": "STREET_NAME/BUILDING_NB", "example": "Rua Aurora, 123 → [STREET_NAME], [BUILDING_NB]"},
|
81 |
+
{"name": "Bairro", "tag": "NEIGHBORHOOD", "example": "Jardim Paulista → [NEIGHBORHOOD]"},
|
82 |
+
{"name": "Cidade", "tag": "CITY", "example": "São Paulo → [CITY]"},
|
83 |
+
{"name": "Estado", "tag": "STATE/STATE_ABBR", "example": "São Paulo/SP → [STATE]/[STATE_ABBR]"},
|
84 |
+
{"name": "CEP", "tag": "ZIPCODE_CEP", "example": "01234-567 → [ZIPCODE_CEP]"},
|
85 |
+
{"name": "Telefone", "tag": "PHONE", "example": "(11) 98765-4321 → [PHONE]"},
|
86 |
+
{"name": "Data de nascimento", "tag": "BIRTHDATE", "example": "15/03/1980 → [BIRTHDATE]"},
|
87 |
+
{"name": "Cartão de crédito", "tag": "CREDITCARD", "example": "5432-1098-7654-3210 → [CREDITCARD]"},
|
88 |
+
{"name": "PIS/PASEP", "tag": "SOCIAL_NB_PIS", "example": "123.45678.90-1 → [SOCIAL_NB_PIS]"},
|
89 |
+
{"name": "Dados médicos", "tag": "MEDICAL_DATA", "example": "Diagnóstico de hipertensão → [MEDICAL_DATA]"},
|
90 |
+
{"name": "Opinião política", "tag": "POLITICAL_OPINION", "example": "Apoiador do partido X → [POLITICAL_OPINION]"},
|
91 |
+
{"name": "Convicção religiosa", "tag": "RELIGIOUS_CONVICTION", "example": "Praticante de religião Y → [RELIGIOUS_CONVICTION]"}
|
92 |
+
]
|
93 |
|
94 |
+
# Create Gradio Interface
|
95 |
+
with gr.Blocks(css="""
|
96 |
+
.gradio-container {max-width: 1200px !important; margin-left: auto !important; margin-right: auto !important;}
|
97 |
+
.examples {margin-top: 10px !important;}
|
98 |
+
.pii-table {margin-top: 20px !important; margin-bottom: 20px !important;}
|
99 |
+
.footer {text-align: center; margin-top: 20px !important; padding: 10px !important; border-top: 1px solid #eee !important;}
|
100 |
+
.pii-card {background-color: #f9f9f9; border-radius: 8px; padding: 15px; margin-bottom: 10px;}
|
101 |
+
.header-image {display: block; margin: 0 auto; max-width: 120px; margin-bottom: 10px;}
|
102 |
+
.assistant-message {border-left: 3px solid #ffd700 !important; background-color: #fffdf7 !important;}
|
103 |
+
.user-message {background-color: #f5f5f5 !important; border-left: 3px solid #6c757d !important;}
|
104 |
+
""") as demo:
|
105 |
+
|
106 |
+
gr.HTML("""
|
107 |
+
<div style="text-align: center; margin-bottom: 20px;">
|
108 |
+
<img src="https://i.imgur.com/UGwNbsT.png" alt="Tucano Voraz Logo" class="header-image">
|
109 |
+
<h1 style="margin-top: 5px; margin-bottom: 10px;">Tucano Voraz</h1>
|
110 |
+
<h3 style="margin-top: 0; color: #666;">Sistema de Anonimização e Remoção de Dados Sensíveis</h3>
|
111 |
+
<p>by <a href="mailto:[email protected]">Arthur Souza Rodrigues</a></p>
|
112 |
+
</div>
|
113 |
+
""")
|
114 |
+
|
115 |
+
with gr.Row():
|
116 |
+
with gr.Column(scale=2):
|
117 |
+
gr.Markdown("""
|
118 |
+
## Sobre o Projeto
|
119 |
+
|
120 |
+
**Tucano Voraz** é uma ferramenta de anonimização de texto projetada para identificar e remover
|
121 |
+
informações pessoais sensíveis (PII) de documentos em português. Em um mundo onde vazamentos
|
122 |
+
de dados são cada vez mais comuns, proteger informações pessoais tornou-se essencial.
|
123 |
+
|
124 |
+
### Como Funciona:
|
125 |
+
|
126 |
+
1. Cole seu texto contendo dados sensíveis
|
127 |
+
2. O modelo identificará automaticamente PIIs
|
128 |
+
3. Receberá o texto com os dados sensíveis substituídos por tags
|
129 |
+
|
130 |
+
### Aplicações:
|
131 |
+
|
132 |
+
- Conformidade com LGPD e regulamentos de privacidade
|
133 |
+
- Compartilhamento seguro de documentos
|
134 |
+
- Preparação de dados para processamento por terceiros
|
135 |
+
- Publicação de documentos em ambientes públicos
|
136 |
+
""")
|
137 |
+
|
138 |
+
with gr.Accordion("📋 Tipos de Dados Sensíveis Detectados", open=False):
|
139 |
+
pii_html = "<div class='pii-table'><div style='display: grid; grid-template-columns: repeat(auto-fill, minmax(350px, 1fr)); gap: 10px;'>"
|
140 |
+
|
141 |
+
for pii in pii_types:
|
142 |
+
pii_html += f"""
|
143 |
+
<div class='pii-card'>
|
144 |
+
<h4 style='margin-top: 0; margin-bottom: 5px;'>{pii['name']}</h4>
|
145 |
+
<div style='color: #666; font-size: 0.9em; margin-bottom: 5px;'>Tag: <code>{pii['tag']}</code></div>
|
146 |
+
<div style='font-size: 0.85em;'>Exemplo: <code>{pii['example']}</code></div>
|
147 |
+
</div>
|
148 |
+
"""
|
149 |
+
|
150 |
+
pii_html += "</div></div>"
|
151 |
+
gr.HTML(pii_html)
|
152 |
+
|
153 |
+
chat_interface = gr.ChatInterface(
|
154 |
+
fn=predict,
|
155 |
+
type="messages",
|
156 |
+
examples=examples,
|
157 |
+
title="",
|
158 |
+
chatbot=gr.Chatbot(
|
159 |
+
height=500,
|
160 |
+
bubble_full_width=False,
|
161 |
+
show_share_button=True,
|
162 |
+
show_copy_button=True,
|
163 |
+
layout="bubble",
|
164 |
+
avatar_images=(None, "https://i.imgur.com/Ptd2AoL.png")
|
165 |
),
|
166 |
+
textbox=gr.Textbox(
|
167 |
+
placeholder="Insira seu texto para anonimização...",
|
168 |
+
lines=3,
|
169 |
+
max_lines=10,
|
170 |
+
show_copy_button=True,
|
171 |
+
container=False,
|
172 |
+
scale=7
|
173 |
+
)
|
174 |
+
)
|
175 |
+
|
176 |
+
gr.HTML("""
|
177 |
+
<div class="footer">
|
178 |
+
<p>🔒 Todos os dados são processados localmente - não armazenamos textos ou dados sensíveis</p>
|
179 |
+
<p>Siga o desenvolvimento: <a href="https://www.linkedin.com/in/arthrod/detail/recent-activity/" target="_blank">LinkedIn</a> | Desenvolvido com ❤️ usando Gradio e HuggingFace</p>
|
180 |
+
</div>
|
181 |
+
""")
|
182 |
|
183 |
+
# Launch the app
|
184 |
if __name__ == "__main__":
|
185 |
+
demo.launch()
|