Spaces:
Build error
Build error
| import gradio as gr | |
| import yaml | |
| import os | |
| from utils import process_ksas, process_analysis, process_core_content, process_summary, _cover_letter | |
| def load_txt_file(txt_file): | |
| with open(txt_file, 'r', encoding='utf-8') as f: | |
| txt_str_contents = f.read() | |
| return txt_str_contents | |
| def load_initial_resume(file_path): | |
| try: | |
| with open(file_path, 'r', encoding='utf-8') as f: | |
| resume_data = yaml.safe_load(f) | |
| if not isinstance(resume_data, dict): | |
| print(f"Warning: Resume data is not a dictionary: {type(resume_data)}") | |
| return None | |
| return resume_data | |
| except Exception as e: | |
| print(f"Error loading initial resume: {e}") | |
| return None | |
| with gr.Blocks() as demo: | |
| gr.Markdown('''# Resume Generator | |
| This tool generates a tailored resume and cover letter for a job description using Anthropic's LLM API. | |
| Instead of doing this in one shot, each step of the process is broken down into separate blocks to allow for manual edits between steps. Edit the outputs as you go to align with historical accuracy and with your writing preferences. | |
| Sample files have been provided for each input to help you get started. You can upload your own files to replace the samples. | |
| ## Instructions | |
| Upload all of the following files: | |
| - Job Description: a .txt file containing the job description. | |
| - Resume YAML: a .yaml file containing your work experience. See the provided template for formatting structure. Work experience bullets are grouped by job and category, where multiple variations of bullets may be stored to provide additional texture to the LLM. | |
| - Additional Resume Context: a .txt file containing additional resume details that you don't want to tailor, but want to share with the LLM as extra context. | |
| - Additional Freeform Context: a .txt file that elaborates on resume details to support the LLM. This information wouldn't normally be included on the resume. It can be unpolished writing and brutally honest background details that prevent the LLM from stretching the truth. | |
| - Resume Summary Writing Sample: a .txt file containing a writing sample of a bullet list summary for the top of your resume. | |
| - Cover Letter Writing Sample: a .txt file containing a writing sample of a cover letter. | |
| ''') | |
| ### File management | |
| job_desc_file = gr.File(label="Job Description", value="job_description.txt") | |
| resume_file = gr.File(label="Resume YAML", value="full_cv.yaml") | |
| extra_resume_context_file = gr.File(label="Additional Resume Context", value="additional_resume_context.txt") | |
| freeform_context_file = gr.File(label="Additional Freeform Context", value="freeform_context.txt") | |
| summary_sample_file = gr.File(label="Resume Summary Writing Sample", value="summary_sample.txt") | |
| cover_letter_sample_file = gr.File(label="Cover Letter Writing Sample", value="cover_letter_sample.txt") | |
| # Create States that store ontent as variables | |
| job_desc_content = gr.State(load_txt_file("job_description.txt")) | |
| resume_content = gr.State(load_initial_resume("full_cv.yaml")) | |
| extra_resume_context_content = gr.State(load_txt_file("additional_resume_context.txt")) | |
| freeform_context_content = gr.State(load_txt_file("freeform_context.txt")) | |
| summary_sample_content = gr.State(load_txt_file("summary_sample.txt")) | |
| cover_letter_sample_content = gr.State(load_txt_file("cover_letter_sample.txt")) | |
| # If a file is uploaded, automatically update the respective variable storing its contents | |
| job_desc_file.upload(fn=load_txt_file, inputs=[job_desc_file], outputs=[job_desc_content]) | |
| resume_file.upload(fn=load_initial_resume, inputs=[resume_file], outputs=[resume_content]) | |
| extra_resume_context_file.upload(fn=load_txt_file, inputs=[extra_resume_context_file], outputs=[extra_resume_context_content]) | |
| freeform_context_file.upload(fn=load_txt_file, inputs=[freeform_context_file], outputs=[freeform_context_content]) | |
| summary_sample_file.upload(fn=load_txt_file, inputs=[summary_sample_file], outputs=[summary_sample_content]) | |
| cover_letter_sample_file.upload(fn=load_txt_file, inputs=[cover_letter_sample_file], outputs=[cover_letter_sample_content]) | |
| # Extract KSAs | |
| ksas_content = gr.State(None) | |
| ksas_btn = gr.Button("1. Extract KSAs") | |
| ksas_output = gr.Textbox(label="Extracted KSAs", lines=10, interactive=True) | |
| ksas_btn.click(process_ksas, inputs=[job_desc_content], outputs=[ksas_output]) | |
| ksas_output.change(lambda x: x, ksas_output, ksas_content) | |
| # Analyze first to determine whether or not to proceed | |
| analyze_btn = gr.Button("2. Analyze Fit") | |
| analysis_output = gr.Textbox(label="Analysis & Recommendation", lines=10, interactive=True) | |
| analyze_btn.click(process_analysis, inputs=[resume_content, job_desc_content, ksas_content, freeform_context_content], outputs=analysis_output) | |
| # Generate core resume content (experience bullets and technical skills) | |
| core_content_btn = gr.Button("3. Generate Core Content") | |
| exp_content = gr.State(None) | |
| exp_output = gr.Textbox(label="Experience Bullets", lines=10, interactive=True) | |
| exp_output.change(lambda x: x, exp_output, exp_content) | |
| skills_content = gr.State(None) | |
| skills_output = gr.Textbox(label="Technical Skills", lines=5, interactive=True) | |
| skills_output.change(lambda x: x, skills_output, skills_content) | |
| core_content_btn.click(process_core_content, inputs=[resume_content, job_desc_content, ksas_content, freeform_context_content], outputs=[exp_output, skills_output]) | |
| # Generate summary | |
| summary_content = gr.State(None) | |
| summary_btn = gr.Button("4. Generate Summary") | |
| summary_output = gr.Textbox(label="Summary", lines=8, interactive=True) | |
| summary_btn.click(process_summary, inputs=[job_desc_content, ksas_content, exp_content, skills_content, extra_resume_context_content, summary_sample_content], outputs=[summary_output]) | |
| summary_output.change(lambda x: x, summary_output, summary_content) | |
| # Generate cover letter | |
| cover_letter_content = gr.State(None) | |
| cover_letter_btn = gr.Button("5. Generate Cover Letter") | |
| cover_letter_output = gr.Textbox(label="Cover Letter", lines=10, interactive=True) | |
| cover_letter_btn.click(_cover_letter, inputs=[job_desc_content, ksas_content, exp_content, skills_content, extra_resume_context_content, summary_content, cover_letter_sample_content], outputs=[cover_letter_output]) | |
| cover_letter_output.change(lambda x: x, cover_letter_output, cover_letter_content) | |
| if __name__ == "__main__": | |
| demo.launch(share=True) | |