mirror of
https://github.com/prdlk/cv.git
synced 2026-08-02 17:31:41 +00:00
init(app): Setup client package for web api specific logic
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
import { Hono } from "hono";
|
||||
import type { ChatMessage, JobExtract, MatchResult, ResumePlan } from "../shared/types";
|
||||
import { buildPlan, chatReply } from "./ai";
|
||||
import { loadCorpus } from "./db";
|
||||
import { extractJob } from "./extract";
|
||||
import { renderLatex } from "./latex";
|
||||
import { matchCorpus } from "./match";
|
||||
|
||||
const app = new Hono<{ Bindings: Env }>();
|
||||
|
||||
app.onError((err, c) => {
|
||||
console.error(JSON.stringify({ level: "error", path: c.req.path, message: err.message }));
|
||||
return c.json({ error: err.message }, 500);
|
||||
});
|
||||
|
||||
app.post("/api/extract", async (c) => {
|
||||
const { url } = await c.req.json<{ url?: string }>();
|
||||
const trimmed = url?.trim() ?? "";
|
||||
if (!/^https?:\/\//i.test(trimmed)) {
|
||||
return c.json({ error: "Enter a full http(s) URL to a job posting." }, 400);
|
||||
}
|
||||
let jd: JobExtract;
|
||||
try {
|
||||
jd = await extractJob(trimmed);
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
return c.json({ error: `Could not fetch the posting: ${message}` }, 502);
|
||||
}
|
||||
if (jd.text.length < 120) {
|
||||
return c.json(
|
||||
{ error: "The page yielded almost no text (likely rendered by JavaScript). Try the direct job-board URL (Greenhouse/Lever/Workable)." },
|
||||
422,
|
||||
);
|
||||
}
|
||||
return c.json(jd);
|
||||
});
|
||||
|
||||
app.post("/api/match", async (c) => {
|
||||
const { text } = await c.req.json<{ text?: string }>();
|
||||
if (!text) return c.json({ error: "Missing job text." }, 400);
|
||||
const corpus = await loadCorpus(c.env.DB);
|
||||
return c.json(matchCorpus(corpus, text));
|
||||
});
|
||||
|
||||
app.post("/api/chat", async (c) => {
|
||||
const body = await c.req.json<{ jd: JobExtract; match: MatchResult; messages: ChatMessage[] }>();
|
||||
const corpus = await loadCorpus(c.env.DB);
|
||||
try {
|
||||
const reply = await chatReply(c.env, corpus, body.jd, body.match, body.messages ?? []);
|
||||
return c.json({ reply });
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
return c.json({ error: `Workers AI is unavailable (${message}). Check \`wrangler login\` / network.` }, 502);
|
||||
}
|
||||
});
|
||||
|
||||
app.post("/api/plan", async (c) => {
|
||||
const body = await c.req.json<{ jd: JobExtract; match?: MatchResult; chat?: ChatMessage[] }>();
|
||||
if (!body.jd?.text) return c.json({ error: "Missing job extract." }, 400);
|
||||
const corpus = await loadCorpus(c.env.DB);
|
||||
const match = body.match ?? matchCorpus(corpus, body.jd.text);
|
||||
return c.json(await buildPlan(c.env, corpus, body.jd, match, body.chat ?? []));
|
||||
});
|
||||
|
||||
app.post("/api/latex", async (c) => {
|
||||
const { plan } = await c.req.json<{ plan?: ResumePlan }>();
|
||||
if (!plan) return c.json({ error: "Missing plan." }, 400);
|
||||
const corpus = await loadCorpus(c.env.DB);
|
||||
return c.json({ latex: renderLatex(corpus, plan) });
|
||||
});
|
||||
|
||||
/** Production fallback compiler; local dev uses the Vite /local/compile middleware (real pdflatex). */
|
||||
app.post("/api/pdf", async (c) => {
|
||||
const { latex } = await c.req.json<{ latex?: string }>();
|
||||
if (!latex) return c.json({ error: "Missing latex source." }, 400);
|
||||
const res = await fetch("https://latex.ytotech.com/builds/sync", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ compiler: "pdflatex", resources: [{ main: true, content: latex }] }),
|
||||
});
|
||||
if (res.ok && res.body) {
|
||||
return new Response(res.body, { headers: { "Content-Type": "application/pdf" } });
|
||||
}
|
||||
const log = (await res.text()).slice(0, 4000);
|
||||
return c.json({ error: `Remote LaTeX service responded ${res.status}`, log }, 502);
|
||||
});
|
||||
|
||||
export default app;
|
||||
Reference in New Issue
Block a user