File size: 3,345 Bytes
63458bf | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | import "@std/dotenv/load";
import { Application, Router } from "@oak/oak";
import { DocsExtractorAgent } from "./main.ts";
const jobs = new Map<string, { status: string; result?: unknown; error?: string }>();
const router = new Router();
router
.post("/api/extract", async (ctx) => {
try {
const body = await ctx.request.body.json();
const { docsUrl, extractionType } = body;
if (!docsUrl || !extractionType) {
ctx.response.status = 400;
ctx.response.body = { error: "Missing required fields: docsUrl, extractionType" };
return;
}
const jobId = crypto.randomUUID();
jobs.set(jobId, { status: "processing" });
// Process extraction in background
(async () => {
try {
const agent = await DocsExtractorAgent.create();
const result = await agent.extract(docsUrl, extractionType, "claude-sonnet-4-20250514");
jobs.set(jobId, { status: "completed", result });
await agent.cleanup();
} catch (error) {
console.error("Extraction error:", error);
jobs.set(jobId, {
status: "failed",
error: error instanceof Error ? error.message : String(error)
});
}
})();
ctx.response.body = { jobId, status: "processing" };
} catch (error) {
console.error("API error:", error);
ctx.response.status = 500;
ctx.response.body = {
error: error instanceof Error ? error.message : "Internal server error"
};
}
})
.get("/api/job/:jobId", (ctx) => {
const jobId = ctx.params.jobId;
const job = jobs.get(jobId);
if (!job) {
ctx.response.status = 404;
ctx.response.body = { error: "Job not found" };
return;
}
ctx.response.body = job;
})
.get("/api/docs", async (ctx) => {
try {
const docs: Array<{ name: string; path: string }> = [];
for await (const entry of Deno.readDir("./generated-docs")) {
if (entry.isFile && entry.name.endsWith(".md")) {
docs.push({ name: entry.name, path: `./generated-docs/${entry.name}` });
}
}
ctx.response.body = { docs };
} catch (error) {
console.error("Error reading docs:", error);
ctx.response.body = { docs: [] };
}
})
.get("/api/docs/:filename", async (ctx) => {
try {
const filename = ctx.params.filename;
const content = await Deno.readTextFile(`./generated-docs/${filename}`);
ctx.response.headers.set("Content-Type", "text/markdown");
ctx.response.body = content;
} catch (error) {
ctx.response.status = 404;
ctx.response.body = { error: "Document not found" };
}
});
const app = new Application();
// CORS middleware
app.use(async (ctx, next) => {
ctx.response.headers.set("Access-Control-Allow-Origin", "*");
ctx.response.headers.set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
ctx.response.headers.set("Access-Control-Allow-Headers", "Content-Type, Authorization");
if (ctx.request.method === "OPTIONS") {
ctx.response.status = 200;
return;
}
await next();
});
app.use(router.routes());
app.use(router.allowedMethods());
const PORT = 8000;
console.log(`🚀 Docs Extractor API running on http://localhost:${PORT}`);
await app.listen({ port: PORT });
|