Aramente commited on
Commit
11bedd8
·
0 Parent(s):

feat: backend scaffold — FastAPI, models, Dockerfile, health endpoint

Browse files
Files changed (6) hide show
  1. Dockerfile +12 -0
  2. app/main.py +20 -0
  3. app/models.py +99 -0
  4. requirements.txt +14 -0
  5. tests/__init__.py +0 -0
  6. tests/test_api.py +11 -0
Dockerfile ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11-slim
2
+
3
+ WORKDIR /app
4
+
5
+ COPY requirements.txt .
6
+ RUN pip install --no-cache-dir -r requirements.txt
7
+
8
+ COPY app/ ./app/
9
+
10
+ EXPOSE 7860
11
+
12
+ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "7860"]
app/main.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+
4
+ app = FastAPI(title="Bored CV API", version="0.1.0")
5
+
6
+ app.add_middleware(
7
+ CORSMiddleware,
8
+ allow_origins=[
9
+ "http://localhost:5173",
10
+ "https://*.github.io",
11
+ ],
12
+ allow_credentials=True,
13
+ allow_methods=["*"],
14
+ allow_headers=["*"],
15
+ )
16
+
17
+
18
+ @app.get("/api/health")
19
+ async def health():
20
+ return {"status": "ok"}
app/models.py ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel, Field
2
+
3
+
4
+ class Experience(BaseModel):
5
+ title: str
6
+ company: str
7
+ dates: str
8
+ description: str
9
+ bullets: list[str] = []
10
+
11
+
12
+ class Education(BaseModel):
13
+ degree: str
14
+ school: str
15
+ year: str
16
+
17
+
18
+ class Profile(BaseModel):
19
+ name: str
20
+ title: str
21
+ location: str = ""
22
+ email: str = ""
23
+ summary: str = ""
24
+ experiences: list[Experience] = []
25
+ education: list[Education] = []
26
+ skills: list[str] = []
27
+
28
+
29
+ class OfferRequirement(BaseModel):
30
+ text: str
31
+ category: str = ""
32
+
33
+
34
+ class Offer(BaseModel):
35
+ title: str
36
+ company: str
37
+ location: str = ""
38
+ description: str
39
+ requirements: list[OfferRequirement] = []
40
+ nice_to_have: list[OfferRequirement] = []
41
+
42
+
43
+ class GapAnalysis(BaseModel):
44
+ matched_skills: list[str] = []
45
+ gaps: list[str] = []
46
+ questions: list[str] = []
47
+
48
+
49
+ class ChatMessage(BaseModel):
50
+ role: str
51
+ content: str
52
+
53
+
54
+ class ChatRequest(BaseModel):
55
+ profile: Profile
56
+ offer: Offer
57
+ gap_analysis: GapAnalysis
58
+ messages: list[ChatMessage] = []
59
+
60
+
61
+ class ChatResponse(BaseModel):
62
+ message: str
63
+ is_complete: bool = False
64
+
65
+
66
+ class RewrittenExperience(BaseModel):
67
+ title: str
68
+ company: str
69
+ dates: str
70
+ bullets: list[str]
71
+
72
+
73
+ class CVData(BaseModel):
74
+ name: str
75
+ title: str
76
+ email: str = ""
77
+ location: str = ""
78
+ summary: str
79
+ experiences: list[RewrittenExperience]
80
+ education: list[Education]
81
+ skills: list[str]
82
+ language: str = "en"
83
+
84
+
85
+ class GenerateRequest(BaseModel):
86
+ profile: Profile
87
+ offer: Offer
88
+ gap_analysis: GapAnalysis
89
+ messages: list[ChatMessage]
90
+
91
+
92
+ class OfferScrapeRequest(BaseModel):
93
+ url: str = ""
94
+ raw_text: str = ""
95
+
96
+
97
+ class AnalyzeRequest(BaseModel):
98
+ profile: Profile
99
+ offer: Offer
requirements.txt ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ fastapi==0.115.6
2
+ uvicorn[standard]==0.34.0
3
+ python-multipart==0.0.19
4
+ pdfplumber==0.11.4
5
+ beautifulsoup4==4.12.3
6
+ httpx==0.28.1
7
+ google-generativeai==0.8.4
8
+ slowapi==0.1.9
9
+ authlib==1.4.1
10
+ itsdangerous==2.2.0
11
+ pytest==8.3.4
12
+ pytest-asyncio==0.24.0
13
+ httpx[http2]==0.28.1
14
+ reportlab==4.2.5
tests/__init__.py ADDED
File without changes
tests/test_api.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pytest
2
+ from fastapi.testclient import TestClient
3
+ from app.main import app
4
+
5
+ client = TestClient(app)
6
+
7
+
8
+ def test_health():
9
+ response = client.get("/api/health")
10
+ assert response.status_code == 200
11
+ assert response.json() == {"status": "ok"}