form_matcher / app.py
Francisco Santos
flagged files saving
f594e45
import gradio as gr
from bs4 import BeautifulSoup
import json
import time
import os
from transformers import AutoTokenizer, pipeline
example1 = '''<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Contact Form</title>
</head>
<body>
<h1>Contact Form</h1>
<form action="/submit-form" method="POST">
<label for="name">Name:</label>
<input type="text" id="name" name="name" required>
<br>
<label for="email">Email:</label>
<input type="email" id="email" name="email" required>
<br>
<label for="location">Location:</label>
<input type="text" id="location" name="location" required>
<br>
<label for="github">GitHub:</label>
<input type="url" id="github" name="github" required>
<br>
<label for="linkedin">LinkedIn:</label>
<input type="url" id="linkedin" name="linkedin" required>
<br>
<label for="phone">Phone:</label>
<input type="tel" id="phone" name="phone" required>
<br><br>
<input type="submit" value="Submit">
</form>
</body>
</html>
'''
solution1 = '''{
"name": "Ana Guida",
"email": "example@gmail.com",
"location": "Amsterdam, Netherlands",
"github": "https://github.com/34kmddfn",
"linkedin": "https://www.linkedin.com/in/ana-rguida/",
"phone": "+351 928 169 341"
}'''
example2 = '''<!DOCTYPE html>
<html>
<head>
<title>Resume Form</title>
</head>
<body>
<form action="/" method="POST">
<label>What kind of pet do you have?</label>
<br>
<input type="radio" id="dog" name="pet" value="dog">
<label for="dog">Dog</label>
<br>
<input type="radio" id="cat" name="pet" value="cat">
<label for="cat">Cat</label>
<br>
<input type="radio" id="other" name="pet" value="other">
<label for="other">Other</label>
<br><br>
<label>What color is your pet?</label>
<br>
<input type="checkbox" id="black" name="color" value="black">
<label for="black">Black</label>
<br>
<input type="checkbox" id="white" name="color" value="white">
<label for="white">White</label>
<br>
<input type="checkbox" id="brown" name="color" value="brown">
<label for="brown">Brown</label>
<br><br>
<input type="submit" value="Submit">
</form>
</body>
</html>
'''
solution2 = '''{
"pet": "dog",
"color": [
"black",
"brown"
]
}'''
example3 = '''<!DOCTYPE html>
<html>
<head>
<title>Create account Form</title>
</head>
<body>
<form action="/" method="POST">
<label for="name">Name:</label>
<input type="text" id="name" name="name" required>
<br>
<label for="country">Select your country:</label>
<br>
<select id="country" name="country">
<option value="usa">USA</option>
<option value="uk">UK</option>
<option value="germany">Germany</option>
<option value="japan">Japan</option>
</select>
<br><br>
<label for="birthday">Select your birthday:</label>
<br>
<input type="date" id="birthday" name="birthday">
<br><br>
<input type="submit" value="Submit">
</form>
</body>
</html>
'''
solution3 = '''{
"name": "Mike",
"country": "Germany",
"birthday": "1990-05-07"
}'''
models = {
"model_n1": "sileod/deberta-v3-base-tasksource-nli",
# "model_n2": "roberta-large-mnli",
# "model_n3": "facebook/bart-large-mnli",
# "model_n4": "cross-encoder/nli-deberta-v3-xsmall"
}
def find_form_fields_from_file(file):
with open(file.name, "r") as f:
content = f.read()
return find_form_fields(content)
def find_form_fields(html_content):
soup = BeautifulSoup(html_content, 'html.parser')
# find all form tags
forms = soup.find_all('form')
form_fields = []
for form in forms:
# find all input and select tags within each form
input_tags = form.find_all('input')
select_tags = form.find_all('select')
for tag in input_tags:
form_fields.append(str(tag))
for tag in select_tags:
form_fields.append(str(tag))
# Convert the list to a single string for display
return form_fields
def load_json(json_file):
with open(json_file, 'r') as f:
data = json.load(f)
return data
def classify_lines(text, candidate_labels, model_name):
start_time = time.time() # Start measuring time
classifier = pipeline('zero-shot-classification', model=model_name)
# Check if the text is already a list or if it needs splitting
if isinstance(text, list):
lines = text
else:
lines = text.split('\n')
classified_lines = []
for line in lines:
if line.strip() and (line.strip().startswith("<input") or line.strip().startswith("<select") )and 'hidden' not in line.lower():
# Skip empty lines, classify lines starting with "<input", and exclude lines with 'hidden'
results = classifier(line, candidate_labels=candidate_labels)
top_classifications = results['labels'][:2] # Get the top two classifications
top_scores = results['scores'][:2] # Get the top two scores
classified_lines.append((line, list(zip(top_classifications, top_scores))))
end_time = time.time() # Stop measuring time
execution_time = end_time - start_time # Calculate execution time
return classified_lines, execution_time
def classify_lines_json(text, json_content, candidate_labels, model_name):
start_time = time.time() # Start measuring time
classifier = pipeline('zero-shot-classification', model=model_name)
# Check if the text is already a list or if it needs splitting
if isinstance(text, list):
lines = text
else:
lines = text.split('\n')
# Open the output.html file in write mode
output_content = []
last_input = "None"
max_index = -1
for i, line in enumerate(lines):
if line.strip() and (line.strip().startswith("<input") or line.strip().startswith("<select") or line.strip().startswith("<option") ) and 'hidden' not in line.lower():
# Skip empty lines, classify lines starting with "<input", and exclude lines with 'hidden'
results = classifier(line, candidate_labels=["text", "radio", "checkbox", "button", "date", "select"])
if results['labels'][0] == "text" or results['labels'][0] == "date":
# print("text")
last_input = "text/date"
input_results = classifier(line, candidate_labels=candidate_labels)
top_classifications = input_results['labels'][:2] # Get the top two classifications
top_scores = input_results['scores'][:2] # Get the top two scores
line = line + f"<!-- Input: <{json_content[top_classifications[0]]}> - certainty: {format(top_scores[0], '.2f')} -->"
elif results['labels'][0] == "button":
# print("button")
last_input = "button"
line = line + f"<!-- Input: <{results['labels'][0]}> - certainty: {format(results['scores'][0], '.2f')} -->"
elif results['labels'][0] == "radio":
# print("radio")
if(last_input == "radio"):
radio_options.append(line)
radio_options_i.append(i)
else:
radio_options = [line]
radio_options_i = [i]
radio_results_list = []
last_input = "radio"
input_results = classifier(line, candidate_labels=candidate_labels)
top_classifications = input_results['labels'][:2] # Get the top two classifications
top_scores = input_results['scores'][:2] # Get the top two scores
radio_results = classifier(line, candidate_labels=[json_content[top_classifications[0]]])
radio_results_list.append(radio_results)
# Get the scores from the radio_results_list
scores = [result['scores'][0] for result in radio_results_list]
previous_max_index = max_index
# Find the index of the maximum score
max_index = scores.index(max(scores))
if previous_max_index != max_index:
line_selected = radio_options[previous_max_index]
real_index = radio_options_i[previous_max_index]
if real_index < len(output_content):
output_content[real_index] = line_selected
line_selected = radio_options[max_index]
line_selected = line_selected + f"<!-- Input: <{results['labels'][0]}> - certainty: {format(results['scores'][0], '.2f')}. LINE TO SELECT: <{radio_results['labels'][0]}> - certainty: {format(max(scores), '.2f')} -->"
real_index = radio_options_i[max_index]
if real_index < len(output_content):
output_content[real_index] = line_selected
else:
line = line_selected
elif results['labels'][0] == "checkbox":
# print("checkbox")
last_input = "checkbox"
input_results = classifier(line, candidate_labels=candidate_labels)
top_classifications = input_results['labels'][:2] # Get the top two classifications
top_scores = input_results['scores'][:2] # Get the top two scores
checkbox_results = classifier(line, candidate_labels=[json_content[top_classifications[0]]])
if checkbox_results['scores'][0] > 0.8:
line = line + f"<!-- Input: <{results['labels'][0]}> - certainty: {format(results['scores'][0], '.2f')}. LINE TO SELECT: <{checkbox_results['labels'][0]}> - certainty: {format(checkbox_results['scores'][0], '.2f')} -->"
else: #elif results['labels'][0] == "select" or results['labels'][0] == "option":
# print("select")
if(last_input == "select"):
select_options.append(line)
select_options_i.append(i)
else:
select_options = [line]
select_options_i = [i]
select_results_list = []
last_input = "select"
input_results = classifier(line, candidate_labels=candidate_labels)
top_classifications = input_results['labels'][:2] # Get the top two classifications
top_scores = input_results['scores'][:2] # Get the top two scores
select_results = classifier(line, candidate_labels=[json_content[top_classifications[0]]])
select_results_list.append(select_results)
# Get the scores from the select_results_list
scores = [result['scores'][0] for result in select_results_list]
previous_max_index = max_index
# Find the index of the maximum score
max_index = scores.index(max(scores))
if previous_max_index != max_index:
line_selected = select_options[previous_max_index]
real_index = select_options_i[previous_max_index]
if real_index < len(output_content):
output_content[real_index] = line_selected
line_selected = select_options[max_index]
line_selected = line_selected + f"<!-- Input: <{results['labels'][0]}> - certainty: {format(results['scores'][0], '.2f')}. LINE TO SELECT: <{select_results['labels'][0]}> - certainty: {format(max(scores), '.2f')} -->"
real_index = select_options_i[max_index]
if real_index < len(output_content):
output_content[real_index] = line_selected
else:
line = line_selected
output_content.append(line)
end_time = time.time() # Stop measuring time
execution_time = end_time - start_time # Calculate execution time
return output_content, execution_time
def retrieve_fields(data, path=''):
"""Recursively retrieve all fields from a given JSON structure and prompt for filling."""
fields = {}
# If the data is a dictionary
if isinstance(data, dict):
for key, value in data.items():
# Construct the updated path for nested structures
new_path = f"{path}.{key}" if path else key
fields.update(retrieve_fields(value, new_path))
# If the data is a list, iterate over its items
elif isinstance(data, list):
for index, item in enumerate(data):
new_path = f"{path}[{index}]"
fields.update(retrieve_fields(item, new_path))
# If the data is a simple type (str, int, etc.)
else:
prompt = f"Please fill in the {path} field." if not data else data
fields[path] = prompt
return fields
def retrieve_fields_from_file(file_path):
"""Load JSON data from a file, then retrieve all fields and prompt for filling."""
with open(file_path.name, 'r') as f:
data = f.read()
return retrieve_fields(json.loads(data))
def process_files(html_file, json_file):
#html_content = open_html(html_file)
#print(html_file)
html_inputs = find_form_fields(html_file)
#print(json_file)
json_content = retrieve_fields(json.loads(json_file))
#Classificar os inputs do json para ver em que tipo de input ["text", "radio", "checkbox", "button", "date"]
# Classify lines and measure execution time
for model_name in models.values():
tokenizer = AutoTokenizer.from_pretrained(model_name)
#html_classified_lines, html_execution_time = classify_lines(html_inputs, ["text", "radio", "checkbox", "button", "date", "select"], model_name)
json_classified_lines, json_execution_time = classify_lines_json(html_file, json_content, list(json_content.keys()), model_name)
# print(str(html_execution_time) + " - " + str(html_classified_lines))
# print(str(json_execution_time) + " - " + str(json_classified_lines))
#print(type(json_classified_lines))
#return '\n'.join(map(str, html_classified_lines))
return '\n'.join(map(str, json_classified_lines))
HF_TOKEN = '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'
hf_writer = gr.HuggingFaceDatasetSaver(HF_TOKEN, "form_matcher_demo_flagged")
iface = gr.Interface(fn=process_files,
inputs=[gr.Textbox(lines = 20, max_lines = 1000, label="Upload HTML File"), gr.Textbox(lines = 20, max_lines = 1000, label="Upload JSON File")],
outputs=gr.Textbox(lines = 20, max_lines = 1000, label="Output"),
examples=[
[example1, solution1],
[example2, solution2],
[example3, solution3],
],
allow_flagging="manual",
flagging_callback=hf_writer
)
iface.launch()