Spaces:
Build error
Build error
| """ | |
| CV Review Feature | |
| """ | |
| import json | |
| import concurrent.futures | |
| from httpx import LocalProtocolError | |
| import streamlit as st | |
| from cohere.core.api_error import ApiError | |
| from utils.backend import produce_report | |
| from utils.format import extract_json | |
| def generate_markdown_report(REPORT_OBJ: dict) -> str: | |
| """Format the report object dictionary into a markdown readable report""" | |
| def add_section(section_title: str, table_contents: list) -> str: | |
| """Utility function to add a section containing a table to the markdown report""" | |
| if not table_contents: | |
| return "" | |
| section = f"### {section_title.title()}\n\n" | |
| section += ( | |
| "| Job Posting Requirement | CV Details | Explanation | Impact Score |\n" | |
| "| ----------------------- | ---------- | ----------- | -------------- |\n" | |
| ) | |
| for table_row in table_contents: | |
| section += f"| {table_row.get('jobPostingDetails', 'N/A')} | {table_row.get('cvDetails', 'N/A')} | {table_row.get('explanation', '')} | **{table_row.get('severityScore', 0)}** |\n" | |
| return section + "\n" | |
| report = ( | |
| f"# CV Analysis Report\n\n" | |
| f"**Name:** {REPORT_OBJ.get('personName', 'Unknown')} \n" | |
| f"**Job:** {REPORT_OBJ.get('jobTitle', 'N/A')} at {REPORT_OBJ.get('companyName', 'N/A')} \n" | |
| f"**Job Description:** {REPORT_OBJ.get('jobDesc', 'No description available.')}\n\n" | |
| "---\n\n" | |
| "## Key Findings\n\n" | |
| ) | |
| sections = ["experience", "education", "responsibilities", "languages", "tools"] | |
| for section in sections: | |
| report += add_section(section, REPORT_OBJ.get(section, [])) | |
| report += "---\n" | |
| return report | |
| def CVReviewPage(): | |
| """Source Code for CV Review Page""" | |
| SHARED_STATE = st.session_state.shared_materials | |
| API_KEY = st.session_state.api_key | |
| if not SHARED_STATE["valid_flag"]: | |
| st.error("You need to upload a Job Description & CV to use this feature.") | |
| else: | |
| produce_report_button = st.button("Produce Suitability Report") | |
| if produce_report_button: | |
| try: | |
| results = {} | |
| # We will make 3 calls in parallel, to get various bits of information efficiently | |
| with concurrent.futures.ThreadPoolExecutor() as executor: | |
| futures = { | |
| critique_type: executor.submit( | |
| produce_report, | |
| SHARED_STATE["cv"], | |
| SHARED_STATE["job_posting"], | |
| critique_type, | |
| API_KEY, | |
| ) | |
| for critique_type in ["basic", "general", "specific"] | |
| } | |
| for critique_type, future in futures.items(): | |
| results[critique_type] = future.result() | |
| except LocalProtocolError: | |
| st.error("You need to enter a Cohere API Key.") | |
| except ApiError: | |
| st.error("You need a valid Cohere API Key") | |
| # merge the from our calls, by extracting the json object from the gpt message | |
| resultsDict = {} | |
| for jsonText in results.values(): | |
| _, output_report_json = extract_json(jsonText) | |
| resultsDict.update(output_report_json) | |
| # store this as the report object | |
| SHARED_STATE["report"] = resultsDict | |
| # if the report object exists | |
| if SHARED_STATE["report"]: | |
| REPORT = SHARED_STATE["report"] | |
| # these are used for file naming | |
| name = REPORT.get("personName", "MissingPersonName") | |
| job_title = REPORT.get("jobTitle", "MissingTitle") | |
| company_name = REPORT.get("companyName", "MissingCompany") | |
| # render markdown report | |
| st.markdown(generate_markdown_report(REPORT)) | |
| # Downloadable in json form ! | |
| st.download_button( | |
| label="Download Report JSON", | |
| data=json.dumps(REPORT, indent=4), | |
| file_name=f"{name}_{job_title}_{company_name}.json", | |
| mime="application/json", | |
| use_container_width=True, | |
| ) | |