CV_Parser / app.py
jonathanjordan21's picture
Update app.py
2d51595 verified
import gradio as gr
from parser import parse_resume
# import json
from langchain_docling.loader import ExportType
from langchain_docling import DoclingLoader
def process_file(file_path, resumes):
loader = DoclingLoader(file_path=file_path, export_type=ExportType.MARKDOWN)
job_description = loader.load()[0].page_content
if not job_description.strip() or not resumes:
return "Please provide both job description and at least one resume."
print("[RESUME]", job_description)
print("[CATEGORIES]", resumes)
thinking, results = parse_resume(job_description, resumes)
print("[THINKING]", thinking)
print("[RESULTS]", results)
# results = json.loads(results)
# print("[SUCCESS JSON PARSING]")
return thinking, results
def process_input(job_description, file_upload, resumes):
# resumes = [r for r in resumes if r and r.strip() != ""] # Remove empty
print("[FILE UPLOAD]", file_upload)
if file_upload:
return process_file(file_upload, resumes)
if not job_description.strip() or not resumes:
return "Please provide both job description and at least one resume."
print("[CATEGORIES]", resumes)
thinking, results = parse_resume(job_description, resumes)
print("[THINKING]", thinking)
print("[RESULTS]", results)
# results = json.loads(results)
# print("[SUCCESS JSON PARSING]")
return thinking, results
# results = zip(*parse_resume(job_description, resumes))
# formatted_output = ""
# for i, (resume, score) in enumerate(results, 1):
# formatted_output += f"Resume #{i}:\nScore: {score:.2f}\nResume Snippet: {resume[:200]}...\n\n-------\n\n"
# return formatted_output
initial_parsing = [
{"name":"education", "type":"List[str]","description":"attended school, university, and other education programs"},
{"name":"experience", "type":"int", "description":"years of experience"},
{"name":"skills", "type":"List[str]", "description":"list of skills"},
{"name":"name", "type":"str", "description":"name of the person"},
{"name":"location", "type":"str", "description":"location of the person"},
{"name":"email", "type":"str", "description":"email of the person"},
{"name":"websites", "type":"List[str]", "description":"urls related of the person"},
{"name":"certifications", "type":"List[str]", "description":"list of certifications"},
{"name":"languages", "type":"List[str]", "description":"list of languages"},
{"name":"projects", "type":"List[str]", "description":"list of projects"},
{"name":"note", "type":"str", "description":"additional note which highlight the best or uniqueness of the person"}
]
def toggle_textbox(file):
print("[FILE TOOGLE]", file)
# return gr.Textbox.update(interactive=False if file else True)
is_file = bool(file)
return gr.update(visible=not is_file), gr.update(visible=not is_file), gr.update(visible=is_file)
def update_json(data, name, data_type, desc):
if name:
idx = -1
for i,x in enumerate(data):
if name == x["name"]:
idx = i
break
if idx != -1:
if desc:
data[idx]["description"] = desc
if data_type:
data[idx]["type"] = data_type
elif desc:
data.append(
{"name":name, "type":data_type if data_type else "str", "description":desc}
)
# if name and desc:
# data.append(
# {"name":name, "type":data_type if data_type else "str", "description":desc}
# )
return data
def delete_json(data, name):
for i,x in enumerate(data):
if x["name"] == name:
data.pop(i)
return data
# UI definition
with gr.Blocks() as demo:
gr.Markdown("## πŸ“ CV / Resume Parsing")
resumes_list = []
with gr.Row():
resume_count = gr.State(2)
with gr.Column():
@gr.render(inputs=resume_count)
def render_count(count):
name = gr.Textbox(
lines=1,
placeholder="Category name",
label="Name"
)
data_type = gr.Textbox(
lines=1,
placeholder="Category data type",
label="Data Type"
)
desc = gr.Textbox(
lines=1,
placeholder="Category description",
label="Description"
)
update_json_button.click(update_json, inputs=[json_display, name, data_type, desc], outputs=json_display)
# resumes_list.append(
# {"name":name, "type":data_type, "description":desc}
# )
# resumes_list.append(name)
# resumes_list.append(data_type)
# resumes_list.append(desc)
# @gr.render(inputs=input_text)
# def add_resume():
# new_input = gr.Textbox(
# lines=6,
# placeholder=f"Paste resume #{len(resumes_list)+1} here...",
# label=f"Resume #{len(resumes_list)+1}"
# )
# resumes_list.append(new_input)
# return resumes_group.update(visible=True)
# add_resume_btn = gr.Button("βž• Add Another Category")
# add_resume_btn.click(lambda x: x + 1, resume_count, resume_count)
update_json_button = gr.Button("Add / Edit Category")
category_delete = gr.Textbox(
lines=1,
placeholder="Category Name",
label="Remove Category By Name"
)
delete_json_button = gr.Button("Delete Category")
json_display = gr.JSON(value=initial_parsing, label="Parsing Categories", show_label=True)
delete_json_button.click(delete_json, inputs=[json_display, category_delete], outputs=json_display)
with gr.Column():
job_description = gr.Textbox(
lines=16,
placeholder="Paste Resume here...",
label="CV / Resume"
)
file_upload = gr.File(
label="Input Resume File"
)
output = gr.Textbox(
lines=6,
label="Parsing Result",
interactive=False
)
# output = gr.JSON(show_indices=True, label="Parsing Result", show_label=True)
thinking_output = gr.Textbox(
lines=6,
label="Thinking Result",
interactive=False
)
submit_btn_2 = gr.Button("πŸš€ Parse Resume / CV", visible=False)
submit_btn_2.click(
fn=process_input,
inputs=[job_description, file_upload, json_display],
outputs=[thinking_output, output]
)
submit_btn = gr.Button("πŸš€ Parse Resume / CV")
submit_btn.click(
fn=process_input,
inputs=[job_description, file_upload, json_display],
outputs=[thinking_output, output]
)
file_upload.change(fn=toggle_textbox, inputs=file_upload, outputs=[job_description, submit_btn, submit_btn_2])
# add_resume_btn.click(add_resume, outputs=resumes_group)
# add_resume_btn.click(lambda x: x + 1, resume_count, resume_count)
demo.launch()