Spaces:
Build error
Build error
Upload 11 files
Browse files- .gitignore +1 -0
- cover_letter_1.pdf +0 -0
- flagged/log.csv +4 -0
- main.py +98 -0
- requirements.txt +6 -0
- static/styles.css +85 -0
- templates/index.html +26 -0
- templates/job_qualifications.html +47 -0
- templates/style.css +11 -0
- templates/success.html +16 -0
- test.py +84 -0
.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
uploads
|
cover_letter_1.pdf
ADDED
|
Binary file (2.11 kB). View file
|
|
|
flagged/log.csv
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Upload your resume (text format),Job Title,Job Description,Hiring Manager,Company Name,Company Address,Required Skills,Company Trait,Download Cover Letter,flag,username,timestamp
|
| 2 |
+
flagged\Upload your resume text format\e46d7d6d1082249c7452\Margaret-Wangari-Waithaka-CV.pdf,Web developer,web designer,Dr Mike,Holby,Rcaecourse,Typing,Honesty,flagged\Download Cover Letter\34032c5b43e99b59b63e\tmpkz2ccuea.pdf,,,2024-06-24 20:17:06.856409
|
| 3 |
+
flagged\Upload your resume text format\d2938936a7f03e4035ad\Margaret-Wangari-Waithaka-CV.pdf,Web developer,web designer,Dr Mike,Holby,Rcaecourse,Typing,Honesty,flagged\Download Cover Letter\79949841ff603b207cf8\tmpkz2ccuea.pdf,,,2024-06-24 20:17:18.012636
|
| 4 |
+
flagged\Upload your resume text format\5864cde4c035301addbc\Margaret-Wangari-Waithaka-CV.pdf,Web developer,web designer,Dr Mike,Holby,Rcaecourse,Typing,Honesty,flagged\Download Cover Letter\913c7266f39649d88d33\tmpkz2ccuea.pdf,,,2024-06-24 20:19:17.567855
|
main.py
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import tempfile
|
| 3 |
+
from transformers import AutoTokenizer, AutoModelForCausalLM
|
| 4 |
+
from fpdf import FPDF
|
| 5 |
+
import gradio as gr
|
| 6 |
+
|
| 7 |
+
# Initialize GPT-2 model and tokenizer
|
| 8 |
+
tokenizer = AutoTokenizer.from_pretrained("gpt2")
|
| 9 |
+
model = AutoModelForCausalLM.from_pretrained("gpt2")
|
| 10 |
+
|
| 11 |
+
def generate_cover_letter(job_title, job_description, hiring_manager, company_name, company_address, required_skills, company_trait, resume_text):
|
| 12 |
+
resume_data = {
|
| 13 |
+
"name": "[input your name]",
|
| 14 |
+
"address": "[input your address]",
|
| 15 |
+
"city": "[input your city]",
|
| 16 |
+
"email": "[your email]",
|
| 17 |
+
"phone": "+1234567890",
|
| 18 |
+
"skills": "[Change this with your actual relevant skills] Python, Flask, SQL",
|
| 19 |
+
"experience": "[input your experience]",
|
| 20 |
+
"achievements": "I managed to [input your projects]",
|
| 21 |
+
"interests": "contributing to open-source projects"
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
prompt = f"""
|
| 25 |
+
Dear {hiring_manager},
|
| 26 |
+
|
| 27 |
+
I am writing to express my interest in the {job_title} position at {company_name}. With a strong background in {resume_data["skills"]}, particularly my proficiency in {resume_data["skills"]}, I am enthusiastic about the opportunity to apply my expertise to the innovative work being done at your company.
|
| 28 |
+
|
| 29 |
+
Based on my resume, which includes {resume_data["experience"]}, I am confident that my skills and experiences make me a suitable candidate for this role.
|
| 30 |
+
|
| 31 |
+
The job description mentions that you are looking for someone with experience in {required_skills}. In my previous roles, I have successfully {resume_data["achievements"]}.
|
| 32 |
+
|
| 33 |
+
I am particularly drawn to {company_name} because of its commitment to {company_trait}. This commitment resonates with my own professional ethos and my passion for {resume_data["interests"]}.
|
| 34 |
+
|
| 35 |
+
I am excited about the opportunity to contribute to {company_name} and help achieve your goals.
|
| 36 |
+
|
| 37 |
+
Sincerely,
|
| 38 |
+
{resume_data["name"]}
|
| 39 |
+
"""
|
| 40 |
+
|
| 41 |
+
input_ids = tokenizer.encode(prompt, return_tensors='pt')
|
| 42 |
+
max_length = 500
|
| 43 |
+
generated_output = model.generate(input_ids, max_length=max_length, num_return_sequences=1, temperature=0.7)
|
| 44 |
+
cover_letter = tokenizer.decode(generated_output[0], skip_special_tokens=True)
|
| 45 |
+
|
| 46 |
+
return cover_letter
|
| 47 |
+
|
| 48 |
+
def save_pdf_cover_letter(cover_letter_text):
|
| 49 |
+
pdf = FPDF()
|
| 50 |
+
pdf.add_page()
|
| 51 |
+
pdf.set_font("Arial", size=12)
|
| 52 |
+
pdf.cell(200, 10, txt="Cover Letter", ln=True, align='C')
|
| 53 |
+
pdf.ln(10)
|
| 54 |
+
pdf.set_font("Arial", size=11)
|
| 55 |
+
pdf.multi_cell(0, 10, cover_letter_text)
|
| 56 |
+
|
| 57 |
+
temp_file_path = tempfile.mktemp(suffix='.pdf')
|
| 58 |
+
pdf.output(temp_file_path)
|
| 59 |
+
|
| 60 |
+
return temp_file_path
|
| 61 |
+
|
| 62 |
+
def process_resume_and_generate_cover_letter(resume, job_title, job_description, hiring_manager, company_name, company_address, required_skills, company_trait):
|
| 63 |
+
resume_text = resume.name # Directly get the text content
|
| 64 |
+
cover_letter_text = generate_cover_letter(job_title, job_description, hiring_manager, company_name, company_address, required_skills, company_trait, resume_text)
|
| 65 |
+
pdf_path = save_pdf_cover_letter(cover_letter_text)
|
| 66 |
+
|
| 67 |
+
return pdf_path
|
| 68 |
+
|
| 69 |
+
resume_input = gr.File(label="Upload your resume (text format)")
|
| 70 |
+
job_title_input = gr.Textbox(label="Job Title")
|
| 71 |
+
job_description_input = gr.Textbox(label="Job Description")
|
| 72 |
+
hiring_manager_input = gr.Textbox(label="Hiring Manager")
|
| 73 |
+
company_name_input = gr.Textbox(label="Company Name")
|
| 74 |
+
company_address_input = gr.Textbox(label="Company Address")
|
| 75 |
+
required_skills_input = gr.Textbox(label="Required Skills")
|
| 76 |
+
company_trait_input = gr.Textbox(label="Company Trait")
|
| 77 |
+
|
| 78 |
+
output = gr.File(label="Download Cover Letter")
|
| 79 |
+
|
| 80 |
+
iface = gr.Interface(
|
| 81 |
+
fn=process_resume_and_generate_cover_letter,
|
| 82 |
+
inputs=[
|
| 83 |
+
resume_input,
|
| 84 |
+
job_title_input,
|
| 85 |
+
job_description_input,
|
| 86 |
+
hiring_manager_input,
|
| 87 |
+
company_name_input,
|
| 88 |
+
company_address_input,
|
| 89 |
+
required_skills_input,
|
| 90 |
+
company_trait_input
|
| 91 |
+
],
|
| 92 |
+
outputs=output,
|
| 93 |
+
title="Cover Letter Generator",
|
| 94 |
+
description="Upload your resume and fill in the job qualifications to generate a personalized cover letter."
|
| 95 |
+
)
|
| 96 |
+
|
| 97 |
+
if __name__ == "__main__":
|
| 98 |
+
iface.launch()
|
requirements.txt
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
Flask==2.0.1
|
| 3 |
+
transformers==4.9.2
|
| 4 |
+
fpdf==1.7.2
|
| 5 |
+
torch==1.9.0
|
| 6 |
+
|
static/styles.css
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
body {
|
| 2 |
+
font-family: Arial, sans-serif;
|
| 3 |
+
background-color: #f4f4f9;
|
| 4 |
+
margin: 0;
|
| 5 |
+
padding: 0;
|
| 6 |
+
display: flex;
|
| 7 |
+
justify-content: center;
|
| 8 |
+
align-items: center;
|
| 9 |
+
height: 100vh;
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
.container {
|
| 13 |
+
width: 50%;
|
| 14 |
+
padding: 20px;
|
| 15 |
+
background: #fff;
|
| 16 |
+
box-shadow: 0 0 10px rgba(0,0,0,0.1);
|
| 17 |
+
border-radius: 8px;
|
| 18 |
+
text-align: center;
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
h1 {
|
| 22 |
+
color: #333;
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
form {
|
| 26 |
+
display: flex;
|
| 27 |
+
flex-direction: column;
|
| 28 |
+
align-items: center;
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
label {
|
| 32 |
+
margin: 10px 0 5px;
|
| 33 |
+
color: #555;
|
| 34 |
+
width: 100%;
|
| 35 |
+
text-align: left;
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
input[type="text"],
|
| 39 |
+
input[type="file"],
|
| 40 |
+
textarea {
|
| 41 |
+
padding: 10px;
|
| 42 |
+
border: 1px solid #ccc;
|
| 43 |
+
border-radius: 4px;
|
| 44 |
+
margin-bottom: 20px;
|
| 45 |
+
width: 100%;
|
| 46 |
+
box-sizing: border-box;
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
button {
|
| 50 |
+
padding: 10px 15px;
|
| 51 |
+
border: none;
|
| 52 |
+
background-color: #5cb85c;
|
| 53 |
+
color: #fff;
|
| 54 |
+
border-radius: 4px;
|
| 55 |
+
cursor: pointer;
|
| 56 |
+
font-size: 16px;
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
button:hover {
|
| 60 |
+
background-color: #4cae4c;
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
a {
|
| 64 |
+
display: block;
|
| 65 |
+
margin-top: 20px;
|
| 66 |
+
text-decoration: none;
|
| 67 |
+
color: #337ab7;
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
a:hover {
|
| 71 |
+
text-decoration: underline;
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
ul {
|
| 75 |
+
list-style: none;
|
| 76 |
+
padding: 0;
|
| 77 |
+
margin: 0;
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
li {
|
| 81 |
+
background: #ffdddd;
|
| 82 |
+
padding: 10px;
|
| 83 |
+
margin-bottom: 10px;
|
| 84 |
+
border-left: 5px solid #f44336;
|
| 85 |
+
}
|
templates/index.html
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<title>Upload Resume</title>
|
| 6 |
+
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
|
| 7 |
+
</head>
|
| 8 |
+
<body>
|
| 9 |
+
<div class="container">
|
| 10 |
+
<h1>Upload Your Resume</h1>
|
| 11 |
+
<form action="{{ url_for('upload_resume') }}" method="post" enctype="multipart/form-data">
|
| 12 |
+
<input type="file" name="resume">
|
| 13 |
+
<button type="submit">Upload</button>
|
| 14 |
+
</form>
|
| 15 |
+
{% with messages = get_flashed_messages() %}
|
| 16 |
+
{% if messages %}
|
| 17 |
+
<ul>
|
| 18 |
+
{% for message in messages %}
|
| 19 |
+
<li>{{ message }}</li>
|
| 20 |
+
{% endfor %}
|
| 21 |
+
</ul>
|
| 22 |
+
{% endif %}
|
| 23 |
+
{% endwith %}
|
| 24 |
+
</div>
|
| 25 |
+
</body>
|
| 26 |
+
</html>
|
templates/job_qualifications.html
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<title>Job Qualifications</title>
|
| 6 |
+
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
|
| 7 |
+
</head>
|
| 8 |
+
<body>
|
| 9 |
+
<div class="container">
|
| 10 |
+
<h1>Enter Job Qualifications</h1>
|
| 11 |
+
<form action="{{ url_for('job_qualifications') }}" method="post">
|
| 12 |
+
<label for="job_title">Job Title:</label>
|
| 13 |
+
<input type="text" id="job_title" name="job_title">
|
| 14 |
+
|
| 15 |
+
<label for="job_description">Job Description:</label>
|
| 16 |
+
<textarea id="job_description" name="job_description"></textarea>
|
| 17 |
+
|
| 18 |
+
<label for="hiring_manager">Hiring Manager:</label>
|
| 19 |
+
<input type="text" id="hiring_manager" name="hiring_manager">
|
| 20 |
+
|
| 21 |
+
<label for="company_name">Company Name:</label>
|
| 22 |
+
<input type="text" id="company_name" name="company_name">
|
| 23 |
+
|
| 24 |
+
<label for="company_address">Company Address:</label>
|
| 25 |
+
<input type="text" id="company_address" name="company_address">
|
| 26 |
+
|
| 27 |
+
<label for="required_skills">Required Skills:</label>
|
| 28 |
+
<input type="text" id="required_skills" name="required_skills">
|
| 29 |
+
|
| 30 |
+
<label for="company_trait">Company Trait:</label>
|
| 31 |
+
<input type="text" id="company_trait" name="company_trait">
|
| 32 |
+
|
| 33 |
+
<button type="submit">Submit</button>
|
| 34 |
+
</form>
|
| 35 |
+
<a href="{{ url_for('index') }}">Back</a>
|
| 36 |
+
{% with messages = get_flashed_messages() %}
|
| 37 |
+
{% if messages %}
|
| 38 |
+
<ul>
|
| 39 |
+
{% for message in messages %}
|
| 40 |
+
<li>{{ message }}</li>
|
| 41 |
+
{% endfor %}
|
| 42 |
+
</ul>
|
| 43 |
+
{% endif %}
|
| 44 |
+
{% endwith %}
|
| 45 |
+
</div>
|
| 46 |
+
</body>
|
| 47 |
+
</html>
|
templates/style.css
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
body{
|
| 2 |
+
margin: auto;
|
| 3 |
+
padding: 0;
|
| 4 |
+
font-family: Arial, sans-serif;
|
| 5 |
+
background-color: #f0f0f0;
|
| 6 |
+
}
|
| 7 |
+
h1{
|
| 8 |
+
width: 100%;
|
| 9 |
+
background-color: maroon;
|
| 10 |
+
color: #d82323;
|
| 11 |
+
}
|
templates/success.html
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<title>Success</title>
|
| 6 |
+
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
|
| 7 |
+
</head>
|
| 8 |
+
<body>
|
| 9 |
+
<div class="container">
|
| 10 |
+
<h1>Success</h1>
|
| 11 |
+
<p>Your cover letter has been generated successfully.</p>
|
| 12 |
+
<a href="{{ url_for('download', filename=temp_file_path) }}">Download Cover Letter</a>
|
| 13 |
+
<a href="{{ url_for('index') }}">Back</a>
|
| 14 |
+
</div>
|
| 15 |
+
</body>
|
| 16 |
+
</html>
|
test.py
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import asyncio
|
| 2 |
+
import pyttsx3
|
| 3 |
+
import requests
|
| 4 |
+
from bs4 import BeautifulSoup
|
| 5 |
+
from selenium import webdriver
|
| 6 |
+
from selenium.webdriver.common.keys import Keys
|
| 7 |
+
|
| 8 |
+
# Initialize the TTS engine
|
| 9 |
+
engine = pyttsx3.init()
|
| 10 |
+
|
| 11 |
+
# Define a function to fetch and parse the web page
|
| 12 |
+
async def fetch_page(url):
|
| 13 |
+
loop = asyncio.get_event_loop()
|
| 14 |
+
response = await loop.run_in_executor(None, requests.get, url)
|
| 15 |
+
soup = BeautifulSoup(response.text, 'html.parser')
|
| 16 |
+
return soup
|
| 17 |
+
|
| 18 |
+
# Define a function to extract text from the web page
|
| 19 |
+
def extract_text(soup):
|
| 20 |
+
text = ' '.join([p.get_text() for p in soup.find_all('p')])
|
| 21 |
+
return text
|
| 22 |
+
|
| 23 |
+
# Define a function to speak the text
|
| 24 |
+
def speak_text(text):
|
| 25 |
+
engine.say(text)
|
| 26 |
+
engine.runAndWait()
|
| 27 |
+
|
| 28 |
+
# Define a function to handle keyboard navigation
|
| 29 |
+
def handle_keyboard_navigation(driver, event):
|
| 30 |
+
if event.key == Keys.ARROW_UP:
|
| 31 |
+
# Navigate to the previous element
|
| 32 |
+
pass
|
| 33 |
+
elif event.key == Keys.ARROW_DOWN:
|
| 34 |
+
# Navigate to the next element
|
| 35 |
+
pass
|
| 36 |
+
elif event.key == Keys.ARROW_LEFT:
|
| 37 |
+
# Navigate to the previous sibling element
|
| 38 |
+
pass
|
| 39 |
+
elif event.key == Keys.ARROW_RIGHT:
|
| 40 |
+
# Navigate to the next sibling element
|
| 41 |
+
pass
|
| 42 |
+
elif event.key == Keys.ENTER:
|
| 43 |
+
# Activate the current element (e.g., click a button or link)
|
| 44 |
+
pass
|
| 45 |
+
elif event.key == Keys.TAB:
|
| 46 |
+
# Move to the next form field or interactive element
|
| 47 |
+
pass
|
| 48 |
+
|
| 49 |
+
# Define a function to handle form fields
|
| 50 |
+
def handle_form_fields(driver, event):
|
| 51 |
+
target = event.target
|
| 52 |
+
if target.tag_name.lower() in ['input', 'textarea']:
|
| 53 |
+
# Update the form field value
|
| 54 |
+
pass
|
| 55 |
+
elif event.key == Keys.ENTER and target.tag_name.lower() == 'form':
|
| 56 |
+
# Submit the form
|
| 57 |
+
target.submit()
|
| 58 |
+
|
| 59 |
+
# Define a function to handle other interactive elements
|
| 60 |
+
def handle_interactive_elements(driver, event):
|
| 61 |
+
target = event.target
|
| 62 |
+
if target.tag_name.lower() in ['button', 'a']:
|
| 63 |
+
# Activate the button or link
|
| 64 |
+
target.click()
|
| 65 |
+
|
| 66 |
+
# Create the asyncflow pipeline
|
| 67 |
+
async def navigate_page(url):
|
| 68 |
+
soup = await fetch_page(url)
|
| 69 |
+
text = extract_text(soup)
|
| 70 |
+
speak_text(text)
|
| 71 |
+
|
| 72 |
+
# Setting up Selenium WebDriver
|
| 73 |
+
driver = webdriver.Chrome() # or use another browser driver
|
| 74 |
+
driver.get(url)
|
| 75 |
+
|
| 76 |
+
# Add event listeners for keyboard navigation, form fields, and interactive elements
|
| 77 |
+
driver.execute_script("""
|
| 78 |
+
document.addEventListener('keydown', arguments[0]);
|
| 79 |
+
document.addEventListener('input', arguments[1]);
|
| 80 |
+
document.addEventListener('click', arguments[2]);
|
| 81 |
+
""", handle_keyboard_navigation, handle_form_fields, handle_interactive_elements)
|
| 82 |
+
|
| 83 |
+
# Run the pipeline
|
| 84 |
+
asyncio.run(navigate_page('https://example.com'))
|