Skip to content

Commit

Permalink
Added auth functionalities for smooth operation
Browse files Browse the repository at this point in the history
  • Loading branch information
bhargavyagnik committed Nov 17, 2024
1 parent b1c42eb commit 384c3c3
Show file tree
Hide file tree
Showing 11 changed files with 409 additions and 247 deletions.
50 changes: 43 additions & 7 deletions src/backend/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ class SignInRequest(BaseModel):
email: str
password: str

class RefreshTokenRequest(BaseModel):
refresh_token: str

# Auth dependency
async def verify_token(authorization: Annotated[str | None, Header()] = None):
if not authorization or not authorization.startswith("Bearer "):
Expand All @@ -93,6 +96,7 @@ async def signup(request: SignUpRequest):
})
return response.dict()
except Exception as e:
print(e)
raise HTTPException(status_code=400, detail=str(e))

@app.post("/auth/login")
Expand All @@ -114,8 +118,9 @@ async def logout(user = Depends(verify_token)):
except Exception as e:
raise HTTPException(status_code=400, detail=str(e))


@app.post("/upload-resume")
async def upload_resume(file: UploadFile, user = Depends(verify_token)):
async def upload_resume(file: UploadFile,user = Depends(verify_token)):
try:
content = await file.read()

Expand All @@ -140,6 +145,7 @@ async def store_generation_request(
job_details: JobDetails,
model: str,
resume_preview: str,
userid: str,
status: str = 'started',
error: str = None,
):
Expand All @@ -148,8 +154,10 @@ async def store_generation_request(
'id': request_id,
'job_title': job_details.title,
'company': job_details.company,
'job_descr': job_details.description,
'model': model,
'resume_preview': resume_preview,
'userid': userid,
'response_status': status,
'error': error,
'created_at': datetime.utcnow().isoformat(),
Expand All @@ -169,16 +177,17 @@ async def update_generation_status(request_id: str, status: str, error: str = No
except Exception as e:
logger.error(f"Failed to update request status in Supabase: {str(e)}")

async def generate_cover_letter_stream(job_details: JobDetails, resume_text: str, model: str, system_prompt: str):
async def generate_cover_letter_stream(job_details: JobDetails, resume_text: str, model: str, system_prompt: str,userid:str):
request_id = str(uuid.uuid4())

# Store initial request
await store_generation_request(request_id, job_details, model,resume_text[:500])
await store_generation_request(request_id, job_details, model,resume_text[:500],userid)

logger.info(
f"Starting generation for request {request_id} | "
f"Model: {model} | "
f"Resume Preview: {resume_text[:10]}"
f"Resume Preview: {resume_text[:10]} | "
f"User ID: {userid}"
)

async with httpx.AsyncClient() as client:
Expand Down Expand Up @@ -261,14 +270,15 @@ async def generate_cover_letter_stream(job_details: JobDetails, resume_text: str


@app.post("/generate-cover-letter")
async def generate_cover_letter(request: CoverLetterRequest):
async def generate_cover_letter(request: CoverLetterRequest,user = Depends(verify_token)):
logger.info(f"Received cover letter request for {request.job_details.company}")
return StreamingResponse(
generate_cover_letter_stream(
request.job_details,
request.resume_text,
request.model,
request.system_prompt
request.system_prompt,
user.user.id
),
media_type="text/event-stream"
)
Expand All @@ -278,4 +288,30 @@ async def health_check():
return {
"status": "alive",
"service": "cover-letter-generator"
}
}

@app.get("/auth/verify")
async def verify_access_token(user = Depends(verify_token)):
try:
return {
"valid": True,
"user": {
"id": user.user.id,
"email": user.user.email
}
}
except Exception as e:
logger.error(f"Token verification failed: {str(e)}")
raise HTTPException(status_code=401, detail="Invalid token")

@app.post("/auth/refresh")
async def refresh_token(request: RefreshTokenRequest):
try:
response = supabase.auth.refresh_session(request.refresh_token)
return {
"access_token": response.session.access_token,
"refresh_token": response.session.refresh_token
}
except Exception as e:
logger.error(f"Token refresh failed: {str(e)}")
raise HTTPException(status_code=401, detail="Invalid refresh token")
9 changes: 7 additions & 2 deletions src/extension/background.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { AuthService } from './services/auth.js';

const DEFAULT_SYSTEM_PROMPT = `Start with 'Dear Hiring Manager,' and end with 'Sincerely,' followed by just name.
Paragraph 1: Introduction. Who you are, what you do, and what position you're applying for.
Paragraph 2: Summarize your experience.
Expand Down Expand Up @@ -36,14 +38,14 @@ chrome.runtime.onInstalled.addListener(() => {

async function handleLLMRequest(data, port) {
try {
const token = await AuthService.getToken();
const token = await AuthService.getValidToken();
const settings = await chrome.storage.sync.get({
defaultModel: 'llama-3.1-8b-instruct',
resumeText: data.resumeData,
systemPrompt: DEFAULT_SYSTEM_PROMPT
});

const response = await fetch('https://cvwriter-bhargavyagniks-projects.vercel.app/generate-cover-letter', {
const response = await fetch('https://cvwriter-git-dev-bhargavyagniks-projects.vercel.app/generate-cover-letter', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Expand All @@ -59,6 +61,9 @@ chrome.runtime.onInstalled.addListener(() => {
});

if (!response.ok) {
if (response.status === 401) {
throw new Error('Please logout and try logging in again');
}
throw new Error(`API request failed: ${response.statusText}`);
}

Expand Down
2 changes: 1 addition & 1 deletion src/extension/login.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ <h2>Login to Coverquai</h2>
<button type="button" id="signupBtn">Create Account</button>
</form>
</div>
<script src="login.js"></script>
<script type="module" src="login.js"></script>
</body>
</html>
13 changes: 13 additions & 0 deletions src/extension/login.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import AuthService from './services/auth.js';

document.addEventListener('DOMContentLoaded', async function() {
const isAuthenticated = await AuthService.getValidToken();
if (isAuthenticated) {
window.location.href = 'popup.html';
return;
}
});
document.getElementById('loginForm').addEventListener('submit', async (e) => {
e.preventDefault();
const email = document.getElementById('email').value;
Expand All @@ -8,6 +15,9 @@ document.getElementById('loginForm').addEventListener('submit', async (e) => {

try {
await AuthService.login(email, password);
await new Promise((resolve) => {
chrome.action.setPopup({ popup: 'popup.html' }, resolve);
});
window.location.href = 'popup.html';
} catch (error) {
errorMessage.textContent = error.message;
Expand All @@ -22,6 +32,9 @@ document.getElementById('signupBtn').addEventListener('click', async () => {
try {
await AuthService.signup(email, password);
await AuthService.login(email, password);
await new Promise((resolve) => {
chrome.action.setPopup({ popup: 'popup.html' }, resolve);
});
window.location.href = 'popup.html';
} catch (error) {
errorMessage.textContent = error.message;
Expand Down
8 changes: 5 additions & 3 deletions src/extension/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,17 @@
"scripting"
],
"action": {
"default_popup": "login.html"
"default_popup": "popup.html"
},
"options_page": "options.html",
"background": {
"service_worker": "background.js"
"service_worker": "background.js",
"type": "module"
},
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["content.js"]
"js": ["content.js"],
"type": "module"
}]
}

Expand Down
4 changes: 3 additions & 1 deletion src/extension/options.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
font-family: 'Segoe UI', 'Arial', sans-serif;
background-color: #f5f7fa;
color: #2c3e50;
min-width: 400px;
}

.container {
Expand Down Expand Up @@ -159,13 +160,14 @@ <h1>Settings</h1>

<div class="button-group">
<button id="save">Save Settings</button>
<button id="home" style="margin-left: 10px; background-color: #64748b;">Home</button>
<span id="status"></span>
</div>

<div class="coffee-link">
<a href="https://buymeacoffee.com/bhargavyagnik" target="_blank"> This is an opensource Project, Please support the work, Buy me a coffee</a>
</div>
</div>
<script src="options.js"></script>
<script type="module" src="options.js"></script>
</body>
</html>
18 changes: 16 additions & 2 deletions src/extension/options.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { AuthService } from './services/auth.js';
const DEFAULT_SYSTEM_PROMPT = `Start with 'Dear Hiring Manager,' and end with 'Sincerely,' followed by just name.
Paragraph 1: Introduction. Who you are, what you do, and what position you're applying for.
Paragraph 2: Summarize your experience.
Expand All @@ -20,13 +21,22 @@ function saveOptions() {
try {
const formData = new FormData();
formData.append('file', file);

const response = await fetch('https://cvwriter-bhargavyagniks-projects.vercel.app/upload-resume', {
const token = await AuthService.getValidToken();
const response = await fetch('https://cvwriter-git-dev-bhargavyagniks-projects.vercel.app/upload-resume', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`
},
body: formData
});

if (!response.ok) {
if (response.status === 401) {
throw new Error('Please logout and try logging in again');
}
else if (response.status === 400) {
throw new Error('Unsupported file type');
}
throw new Error('Failed to upload resume');
}

Expand Down Expand Up @@ -96,4 +106,8 @@ document.getElementById('coverLetterName').addEventListener('input', function(e)
document.getElementById('resetPrompt').addEventListener('click', function() {
document.getElementById('systemPrompt').value = DEFAULT_SYSTEM_PROMPT;
saveOptions();
});

document.getElementById('home').addEventListener('click', () => {
window.location.href = 'popup.html';
});
Loading

0 comments on commit 384c3c3

Please sign in to comment.