CoverPilot / app.py
cxumol's picture
preprocess ok
b22f922
raw
history blame
5.55 kB
from config import DEMO_TITLE, IS_SHARE, CV_EXT, EXT_TXT
from config import CHEAP_API_BASE, CHEAP_API_KEY, CHEAP_MODEL
from config import STRONG_API_BASE, STRONG_API_KEY, STRONG_MODEL
from util import is_valid_url
from util import mylogger
from taskNonAI import extract_url, file_to_html
from taskAI import TaskAI
## load data
from data_test import mock_jd, mock_cv
## ui
import gradio as gr
## dependency
from pypandoc.pandoc_download import download_pandoc
## std
import os
logger = mylogger(__name__,'%(asctime)s:%(levelname)s:%(message)s')
info = logger.info
def init():
os.system("shot-scraper install -b firefox")
download_pandoc()
def run_refine(api_base, api_key, api_model, jd_info, cv_file: str, cv_text):
if jd_info:
if is_valid_url(jd_info):
jd = extract_url(jd_info)
else:
jd = jd_info
else:
jd = mock_jd
if cv_text:
cv = cv_text
elif cv_file:
if any([cv_file.endswith(ext) for ext in EXT_TXT]):
with open(cv_file, "r", encoding="utf8") as f:
cv = f.read()
else:
cv = file_to_html(cv_file)
else:
cv = mock_cv
cheapAPI = {"base": api_base, "key": api_key, "model": api_model}
taskAI = TaskAI(cheapAPI, temperature=0.2, max_tokens=2048) # max_tokens=2048
info("API initialized")
gen = (
taskAI.jd_preprocess(topic="job description", input=jd),
taskAI.cv_preprocess(input=cv),
)
info("tasks initialized")
result = [""] * 2
while 1:
stop: bool = True
for i in range(len(gen)):
try:
result[i] += next(gen[i]).delta
stop = False
except StopIteration:
# info(f"gen[{i}] exhausted")
pass
yield result
if stop:
info("tasks done")
break
def run_compose(api_base, api_key, api_model, min_jd, min_cv):
strongAPI = {"base": api_base, "key": api_key, "model": api_model}
taskAI = TaskAI(strongAPI, temperature=0.5, max_tokens=2048)
info("API initialized")
with gr.Blocks(
title=DEMO_TITLE,
theme=gr.themes.Base(primary_hue="blue", secondary_hue="sky", neutral_hue="slate"),
) as demo:
intro = f"""# {DEMO_TITLE}
> You provide job description and résumé. I write Cover letter for you!
Before you use, please setup OpenAI-like API for 2 AI agents': Cheap AI and Strong AI.
"""
gr.Markdown(intro)
with gr.Row():
with gr.Column(scale=1):
with gr.Accordion("AI setup (OpenAI-like API)", open=False):
gr.Markdown(
"**Cheap AI**, an honest format converter and refinery machine, extracts essential info from job description and résumé, to reduce subsequent cost on Strong AI."
)
with gr.Group():
weak_base = gr.Textbox(
value=CHEAP_API_BASE, label="API BASE"
)
weak_key = gr.Textbox(value=CHEAP_API_KEY, label="API key")
weak_model = gr.Textbox(value=CHEAP_MODEL, label="Model ID")
gr.Markdown(
"---\n**Strong AI**, a thoughtful wordsmith, generates perfect cover letters to make both you and recruiters happy."
)
with gr.Group():
strong_base = gr.Textbox(
value=STRONG_API_BASE, label="API BASE"
)
strong_key = gr.Textbox(
value=STRONG_API_KEY, label="API key", type="password"
)
strong_model = gr.Textbox(value=STRONG_MODEL, label="Model ID")
with gr.Group():
gr.Markdown("## Employer - Job Description")
jd_info = gr.Textbox(
label="Job Description",
placeholder="Paste as Full Text (recommmend) or URL (may fail)",
lines=5,
)
with gr.Group():
gr.Markdown("## Applicant - CV / Résumé")
with gr.Row():
cv_file = gr.File(
label="Allowed formats: " + " ".join(CV_EXT),
file_count="single",
file_types=CV_EXT,
type="filepath",
)
cv_text = gr.TextArea(
label="Or enter text",
placeholder="If attempting to both upload a file and enter text, only this text will be used.",
)
with gr.Column(scale=2):
gr.Markdown("## Result")
with gr.Row():
min_jd = gr.TextArea(label="Minimized Job Description")
min_cv = gr.TextArea(label="Minimized CV / Résumé")
cover_letter_text = gr.TextArea(label="Cover Letter")
cover_letter_pdf = gr.File(
label="Cover Letter PDF",
file_count="single",
file_types=[".pdf"],
type="filepath",
)
infer_btn = gr.Button("Go!", variant="primary")
infer_btn.click(
fn=run_refine,
inputs=[weak_base, weak_key, weak_model, jd_info, cv_file, cv_text],
outputs=[min_jd, min_cv],
concurrency_limit=5,
)
if __name__ == "__main__":
init()
demo.queue(max_size=10).launch(
show_error=True, debug=True, share=IS_SHARE
)