Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

22 expect the server url and openai keys in the input on the plugin #25

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ Waltzes is a project designed to generate personalized cover letters based on jo
1. Open Firefox and navigate to `about:debugging#/runtime/this-firefox`.
2. Click "Load Temporary Add-on" and select any file in the `addon` directory.

3. Configure the extension:
- Copy the extension ID (e.g., `6546988c-c591-4bce-8e38-357819650252`).
- Go to the following url `moz-extension://{YOUR_TEMPORARY_EXTENSION_ID}/src/configure.html`
- Provide your OpenAI API key and the Flask server URL.
- Click "Save".

### Flask Server Setup

1. Navigate to the `python` directory:
Expand Down
56 changes: 56 additions & 0 deletions addon/src/configure.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Configure - Waltzes</title>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
crossorigin="anonymous"
/>

<style>
.container {
max-width: 700px;
margin: 0 auto;
}
</style>
</head>
<body>
<div class="container">
<h1 class="text-center mt-5">Configure Waltzes for yourself!</h1>

<div class="mb-3">
<label for="host" class="form-label">Host</label>
<small class="form-text text-muted"
>e.g. http://localhost:5000 (default)</small
>
<input
type="text"
class="form-control"
id="host"
name="host"
required
value="http://localhost:5000"
/>
</div>
<div class="mb-3">
<label for="openAiKey" class="form-label">OpenAI Key</label>
<input
type="password"
class="form-control"
id="openAiKey"
name="openAiKey"
required
/>
</div>
<button type="submit" id="save" class="btn btn-primary">
Save
</button>
</div>

<script src="./configure.js"></script>
</body>
</html>
19 changes: 19 additions & 0 deletions addon/src/configure.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const saveButton = document.getElementById("save");

saveButton.addEventListener("click", async function () {
const host = document.getElementById("host").value;
const openAiKey = document.getElementById("openAiKey").value;
localStorage.setItem("host", host);
localStorage.setItem("openAiKey", openAiKey);
location.reload();
});

const host = localStorage.getItem("host");
if (host) {
document.getElementById("host").value = host;
}

const openAiKey = localStorage.getItem("openAiKey");
if (openAiKey) {
document.getElementById("openAiKey").value = openAiKey;
}
8 changes: 5 additions & 3 deletions addon/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,18 @@ function showCoverLetter(coverLetter) {
generateCLButton.addEventListener("click", async function () {
const loader = document.getElementById("loader");
const currentTab = await getCurrentTab();
// TODO: Fetch base url from local storage (dynamic url based on user's input)
const baseUrl = "http:/localhost:5000/job-details";
const savedHost = localStorage.getItem("host") || "http://localhost:5000";
const baseUrl = [savedHost, "job-details"].join("/");
let jobBoard = "";
if (currentTab.url.includes("greenhouse")) jobBoard = "greenhouse";

if (!jobBoard) {
notSupported(currentTab.title, currentTab.url);
return;
}
const url = `${baseUrl}/${jobBoard}?url=${currentTab.url}`;
const openAiKey = localStorage.getItem("openAiKey");
let url = `${baseUrl}/${jobBoard}?url=${currentTab.url}`;
if (openAiKey) url += `&openAiKey=${openAiKey}`;

generateCLButton.disabled = true;
loader.hidden = false;
Expand Down
3 changes: 2 additions & 1 deletion python/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def test():
@app.route("/job-details/<job_board>", methods=["GET"])
def get_job_details(job_board):
job_url = request.args.get("url")
openai_api_key = request.args.get("openAiKey")
job_details = ""

if job_url is None:
Expand All @@ -35,7 +36,7 @@ def get_job_details(job_board):

resume_vectors, resume_segments = vectorize_resume()
best_match_section = get_best_match_from_resume(job_details, resume_vectors, resume_segments)
response = generate_cover_letter(job_details, best_match_section)
response = generate_cover_letter(job_details, best_match_section, openai_api_key)


return {"coverLetter": response, "bestMatchSection": best_match_section}
7 changes: 5 additions & 2 deletions python/services/openai.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import os
from openai import OpenAI

client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))


def generate_cover_letter(raw_job_details, best_match_section):
def generate_cover_letter(raw_job_details, best_match_section,api_key):
if api_key is None:
api_key = os.environ.get("OPENAI_API_KEY")
print("OPEN AI KEY => ", api_key)
client = OpenAI(api_key=api_key)

prompt = f"""
Generate a compelling cover letter based on the provided resume and job details. Analyze the resume to identify relevant work experience, skills, and achievements that align with the job requirements. Use this information to craft a brief, enthusiastic letter that showcases the candidate's qualifications and passion for the role.
Expand Down