Spaces:
Sleeping
Sleeping
| 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(): | |
| 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() | |