Use Ollama rewrite path for CV generation
This commit is contained in:
@@ -86,6 +86,13 @@ class SummarizeRequest(BaseModel):
|
||||
top_skills: int = Field(default=8, ge=3, le=12)
|
||||
|
||||
|
||||
class RewriteRequest(BaseModel):
|
||||
instruction: str = Field(min_length=1, max_length=6000)
|
||||
text: str = Field(min_length=1, max_length=MAX_INPUT_CHARS)
|
||||
max_length: int = Field(default=220, ge=24, le=256)
|
||||
min_length: int = Field(default=80, ge=8, le=180)
|
||||
|
||||
|
||||
class CvNormalizeRequest(BaseModel):
|
||||
text: str = Field(min_length=1, max_length=50000)
|
||||
|
||||
@@ -424,6 +431,39 @@ def _ollama_generate_json(prompt: str):
|
||||
raise HTTPException(status_code=502, detail="Ollama did not return valid JSON.")
|
||||
|
||||
|
||||
def _ollama_generate_text(prompt: str) -> str:
|
||||
if not OLLAMA_MODEL:
|
||||
raise HTTPException(status_code=503, detail="OLLAMA_MODEL is not configured.")
|
||||
|
||||
payload = json.dumps({
|
||||
"model": OLLAMA_MODEL,
|
||||
"prompt": prompt,
|
||||
"stream": False,
|
||||
"options": {"temperature": 0.2}
|
||||
}).encode("utf-8")
|
||||
|
||||
req = urllib_request.Request(
|
||||
f"{OLLAMA_BASE_URL}/api/generate",
|
||||
data=payload,
|
||||
headers={"Content-Type": "application/json"},
|
||||
method="POST",
|
||||
)
|
||||
|
||||
try:
|
||||
with urllib_request.urlopen(req, timeout=180) as response:
|
||||
body = json.loads(response.read().decode("utf-8"))
|
||||
except HTTPError as ex:
|
||||
raise HTTPException(status_code=502, detail=f"Ollama request failed with {ex.code}.")
|
||||
except URLError as ex:
|
||||
raise HTTPException(status_code=503, detail=f"Ollama is unreachable: {ex.reason}.")
|
||||
|
||||
raw = (body.get("response") or "").strip()
|
||||
if not raw:
|
||||
raise HTTPException(status_code=502, detail="Ollama returned an empty rewrite.")
|
||||
|
||||
return raw
|
||||
|
||||
|
||||
@app.post("/cv/normalize")
|
||||
async def normalize_cv(req: CvNormalizeRequest):
|
||||
prompt = f"""
|
||||
@@ -536,6 +576,49 @@ Block:
|
||||
}
|
||||
|
||||
|
||||
@app.post("/cv/rewrite")
|
||||
async def rewrite_cv(req: RewriteRequest):
|
||||
prompt = f"""
|
||||
You are an expert CV and resume writer.
|
||||
Rewrite the candidate CV into a polished, factual CV tailored to the target role.
|
||||
Return ONLY the final CV text. No analysis. No commentary. No JSON. No markdown code fences. No recruiter notes.
|
||||
|
||||
Non-negotiable rules:
|
||||
- Preserve facts only. Never invent employers, dates, locations, salaries, education, qualifications, technologies, metrics, or achievements.
|
||||
- Never output sections like 'Role summary', 'What the company wants most', 'Keywords to mirror', 'Interview focus', 'Top hard skills', or similar analysis headings.
|
||||
- Do not describe the job ad. Rewrite the candidate CV.
|
||||
- Use crisp CV language, not prose about what the company wants.
|
||||
- Keep the output directly usable as a CV.
|
||||
- If rewriting the whole CV, output a complete CV with sensible headings and bullets.
|
||||
- If rewriting only one section, return only that rewritten section.
|
||||
- Keep bullets concrete and concise.
|
||||
- If a fact is not present in the source CV, omit it.
|
||||
|
||||
Preferred whole-CV structure when the source supports it:
|
||||
# Contact
|
||||
# Professional Summary
|
||||
# Work Experience
|
||||
# Education
|
||||
# Skills
|
||||
# Certifications
|
||||
# Projects
|
||||
# Languages
|
||||
# Interests
|
||||
|
||||
Instruction:
|
||||
{req.instruction.strip()}
|
||||
|
||||
Candidate source CV:
|
||||
{req.text.strip()}
|
||||
""".strip()
|
||||
|
||||
rewritten = _ollama_generate_text(prompt).strip()
|
||||
if not rewritten:
|
||||
raise HTTPException(status_code=502, detail="Ollama returned an empty rewrite.")
|
||||
|
||||
return {"rewritten_text": rewritten}
|
||||
|
||||
|
||||
@app.post("/summarize")
|
||||
async def summarize(req: SummarizeRequest):
|
||||
if req.min_length >= req.max_length:
|
||||
|
||||
Reference in New Issue
Block a user