Spaces:
Running
Running
format
Browse files- app.py +45 -11
- taskAI.py +1 -1
- taskNonAI.py +3 -1
app.py
CHANGED
@@ -36,7 +36,15 @@ def init():
|
|
36 |
## Config Functions
|
37 |
|
38 |
|
39 |
-
def set_same_cheap_strong(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
# setup_zone = gr.Accordion("AI setup (OpenAI-compatible LLM API)", open=True)
|
41 |
if set_same:
|
42 |
return (
|
@@ -114,10 +122,11 @@ def finalize_letter_txt(api_base, api_key, api_model, debug_CoT):
|
|
114 |
for response in taskAI.purify_letter(full_text=debug_CoT):
|
115 |
result += response.delta
|
116 |
yield result
|
117 |
-
|
118 |
|
119 |
|
120 |
-
def finalize_letter_pdf(
|
|
|
|
|
121 |
cheapAPI = {"base": api_base, "key": api_key, "model": api_model}
|
122 |
taskAI = TaskAI(cheapAPI, temperature=0.1, max_tokens=100)
|
123 |
meta_data = next(taskAI.get_jobapp_meta(JD=jd, CV=cv))
|
@@ -135,14 +144,23 @@ def finalize_letter_pdf(api_base, api_key, api_model, jd, cv, cover_letter_text,
|
|
135 |
|
136 |
with gr.Blocks(
|
137 |
title=DEMO_TITLE,
|
138 |
-
theme=gr.themes.Soft(
|
|
|
|
|
139 |
) as app:
|
140 |
intro = f"""# {DEMO_TITLE}
|
141 |
-
> You provide job description and résum
|
142 |
-
Before you use, please fisrt setup API for 2 AI agents':
|
143 |
"""
|
144 |
gr.Markdown(intro)
|
145 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
146 |
with gr.Row():
|
147 |
with gr.Column(scale=1):
|
148 |
with gr.Accordion(
|
@@ -151,7 +169,7 @@ with gr.Blocks(
|
|
151 |
is_debug = gr.Checkbox(label="Debug Mode", value=IS_DEBUG)
|
152 |
|
153 |
gr.Markdown(
|
154 |
-
"**
|
155 |
)
|
156 |
with gr.Group():
|
157 |
cheap_base = gr.Textbox(value=CHEAP_API_BASE, label="API Base")
|
@@ -160,7 +178,7 @@ with gr.Blocks(
|
|
160 |
)
|
161 |
cheap_model = gr.Textbox(value=CHEAP_MODEL, label="Model ID")
|
162 |
gr.Markdown(
|
163 |
-
"---\n**
|
164 |
)
|
165 |
is_same_cheap_strong = gr.Checkbox(
|
166 |
label="the same as Cheap AI", value=False, container=False
|
@@ -211,13 +229,29 @@ with gr.Blocks(
|
|
211 |
|
212 |
is_same_cheap_strong.change(
|
213 |
fn=set_same_cheap_strong,
|
214 |
-
inputs=[
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
215 |
outputs=[strong_base, strong_key, strong_model],
|
216 |
)
|
217 |
|
218 |
infer_btn.click(
|
219 |
fn=set_same_cheap_strong,
|
220 |
-
inputs=[
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
221 |
outputs=[strong_base, strong_key, strong_model],
|
222 |
).success(
|
223 |
fn=prepare_input, inputs=[jd_info, cv_file, cv_text], outputs=[jd_info, cv_text]
|
|
|
36 |
## Config Functions
|
37 |
|
38 |
|
39 |
+
def set_same_cheap_strong(
|
40 |
+
set_same: bool,
|
41 |
+
cheap_base,
|
42 |
+
cheap_key,
|
43 |
+
cheap_model,
|
44 |
+
strong_base,
|
45 |
+
strong_key,
|
46 |
+
strong_model,
|
47 |
+
):
|
48 |
# setup_zone = gr.Accordion("AI setup (OpenAI-compatible LLM API)", open=True)
|
49 |
if set_same:
|
50 |
return (
|
|
|
122 |
for response in taskAI.purify_letter(full_text=debug_CoT):
|
123 |
result += response.delta
|
124 |
yield result
|
|
|
125 |
|
126 |
|
127 |
+
def finalize_letter_pdf(
|
128 |
+
api_base, api_key, api_model, jd, cv, cover_letter_text, is_debug
|
129 |
+
):
|
130 |
cheapAPI = {"base": api_base, "key": api_key, "model": api_model}
|
131 |
taskAI = TaskAI(cheapAPI, temperature=0.1, max_tokens=100)
|
132 |
meta_data = next(taskAI.get_jobapp_meta(JD=jd, CV=cv))
|
|
|
144 |
|
145 |
with gr.Blocks(
|
146 |
title=DEMO_TITLE,
|
147 |
+
theme=gr.themes.Soft(
|
148 |
+
primary_hue="sky", secondary_hue="emerald", neutral_hue="stone"
|
149 |
+
),
|
150 |
) as app:
|
151 |
intro = f"""# {DEMO_TITLE}
|
152 |
+
> You provide job description and résumé, and I write Cover letter for you!
|
153 |
+
Before you use, please fisrt setup API for 2 AI agents': **CheapAI** and StrongAI.
|
154 |
"""
|
155 |
gr.Markdown(intro)
|
156 |
+
with gr.Accordion("User Guide", open=False):
|
157 |
+
guide = gr.Markdown("""## Setup
|
158 |
+
`API Key`: If you have no idea, go to https://beta.openai.com/account/api-keys
|
159 |
+
|
160 |
+
`Model ID` to choose:
|
161 |
+
- **CheapAI**: `gpt-3.5-turbo-*` should be fine if OpenAI won't make them lazier and dumber. `Mistral-7B-Instruct-v0.1` works well, but `gemma-7b-it` doesn't, because gemma can't understand instructions properly in this case.
|
162 |
+
- **StrongAI**: Models with small context window size like won't work, such as `gpt-3.5-turbo-0613` or perhaps `gpt-4-0613`. `Mistral-7B-Instruct-v0.1` can do the job.
|
163 |
+
""")
|
164 |
with gr.Row():
|
165 |
with gr.Column(scale=1):
|
166 |
with gr.Accordion(
|
|
|
169 |
is_debug = gr.Checkbox(label="Debug Mode", value=IS_DEBUG)
|
170 |
|
171 |
gr.Markdown(
|
172 |
+
"**CheapAI**, an honest format converter and refiner, extracts essential info from job description and résumé, to reduce subsequent cost on Strong AI."
|
173 |
)
|
174 |
with gr.Group():
|
175 |
cheap_base = gr.Textbox(value=CHEAP_API_BASE, label="API Base")
|
|
|
178 |
)
|
179 |
cheap_model = gr.Textbox(value=CHEAP_MODEL, label="Model ID")
|
180 |
gr.Markdown(
|
181 |
+
"---\n**StrongAI**, a thoughtful wordsmith, generates perfect cover letters to make both you and recruiters happy."
|
182 |
)
|
183 |
is_same_cheap_strong = gr.Checkbox(
|
184 |
label="the same as Cheap AI", value=False, container=False
|
|
|
229 |
|
230 |
is_same_cheap_strong.change(
|
231 |
fn=set_same_cheap_strong,
|
232 |
+
inputs=[
|
233 |
+
is_same_cheap_strong,
|
234 |
+
cheap_base,
|
235 |
+
cheap_key,
|
236 |
+
cheap_model,
|
237 |
+
strong_base,
|
238 |
+
strong_key,
|
239 |
+
strong_model,
|
240 |
+
],
|
241 |
outputs=[strong_base, strong_key, strong_model],
|
242 |
)
|
243 |
|
244 |
infer_btn.click(
|
245 |
fn=set_same_cheap_strong,
|
246 |
+
inputs=[
|
247 |
+
is_same_cheap_strong,
|
248 |
+
cheap_base,
|
249 |
+
cheap_key,
|
250 |
+
cheap_model,
|
251 |
+
strong_base,
|
252 |
+
strong_key,
|
253 |
+
strong_model,
|
254 |
+
],
|
255 |
outputs=[strong_base, strong_key, strong_model],
|
256 |
).success(
|
257 |
fn=prepare_input, inputs=[jd_info, cv_file, cv_text], outputs=[jd_info, cv_text]
|
taskAI.py
CHANGED
@@ -68,6 +68,7 @@ Before officially write the letter, think step by step. First, list what makes a
|
|
68 |
## tasks
|
69 |
class TaskAI(OpenAILike):
|
70 |
is_debug = False
|
|
|
71 |
def __init__(self, api: dict[str, str], is_debug=False, **kwargs):
|
72 |
log = logger.info
|
73 |
|
@@ -86,7 +87,6 @@ class TaskAI(OpenAILike):
|
|
86 |
return window_size
|
87 |
|
88 |
checkAPI(api_base=api["base"], api_key=api["key"])
|
89 |
-
|
90 |
|
91 |
super().__init__(
|
92 |
api_base=api["base"],
|
|
|
68 |
## tasks
|
69 |
class TaskAI(OpenAILike):
|
70 |
is_debug = False
|
71 |
+
|
72 |
def __init__(self, api: dict[str, str], is_debug=False, **kwargs):
|
73 |
log = logger.info
|
74 |
|
|
|
87 |
return window_size
|
88 |
|
89 |
checkAPI(api_base=api["base"], api_key=api["key"])
|
|
|
90 |
|
91 |
super().__init__(
|
92 |
api_base=api["base"],
|
taskNonAI.py
CHANGED
@@ -54,12 +54,14 @@ def _date() -> str:
|
|
54 |
def _typst_escape(s) -> str:
|
55 |
return str(s).replace("@", "\@").replace("#", "\#")
|
56 |
|
|
|
57 |
def _ensure_no_signature_in_body(cover_letter_body: str) -> str:
|
58 |
if not cover_letter_body.strip().endswith(","):
|
59 |
# remove last line
|
60 |
cover_letter_body = "\n".join(cover_letter_body.split("\n")[:-1])
|
61 |
return cover_letter_body
|
62 |
|
|
|
63 |
def compile_pdf(
|
64 |
context: dict, tmpl_path: str, output_path="/tmp/cover_letter.pdf", is_debug=False
|
65 |
) -> list[str]:
|
@@ -69,7 +71,7 @@ def compile_pdf(
|
|
69 |
tmpl = Template(f.read())
|
70 |
context = {k: _typst_escape(v) for k, v in context.items()}
|
71 |
context.update({"date_string": _date()})
|
72 |
-
context["letter_body"]=_ensure_no_signature_in_body(context["letter_body"])
|
73 |
|
74 |
letter_typ = tmpl.safe_substitute(context)
|
75 |
with open(letter_src_filepath, "w", encoding="utf8") as f:
|
|
|
54 |
def _typst_escape(s) -> str:
|
55 |
return str(s).replace("@", "\@").replace("#", "\#")
|
56 |
|
57 |
+
|
58 |
def _ensure_no_signature_in_body(cover_letter_body: str) -> str:
|
59 |
if not cover_letter_body.strip().endswith(","):
|
60 |
# remove last line
|
61 |
cover_letter_body = "\n".join(cover_letter_body.split("\n")[:-1])
|
62 |
return cover_letter_body
|
63 |
|
64 |
+
|
65 |
def compile_pdf(
|
66 |
context: dict, tmpl_path: str, output_path="/tmp/cover_letter.pdf", is_debug=False
|
67 |
) -> list[str]:
|
|
|
71 |
tmpl = Template(f.read())
|
72 |
context = {k: _typst_escape(v) for k, v in context.items()}
|
73 |
context.update({"date_string": _date()})
|
74 |
+
context["letter_body"] = _ensure_no_signature_in_body(context["letter_body"])
|
75 |
|
76 |
letter_typ = tmpl.safe_substitute(context)
|
77 |
with open(letter_src_filepath, "w", encoding="utf8") as f:
|