214 lines
7.8 KiB
TypeScript
214 lines
7.8 KiB
TypeScript
import { Router, Request, Response } from "express";
|
|
import { insertGraphNodeSchema, insertGraphEdgeSchema, insertKnowledgeBaseSchema } from "@shared/schema";
|
|
import * as graphService from "./service";
|
|
|
|
const router = Router();
|
|
|
|
// Middleware de autenticação
|
|
router.use((req: Request, res: Response, next) => {
|
|
if (!req.isAuthenticated()) {
|
|
return res.status(401).json({ error: "Não autenticado" });
|
|
}
|
|
next();
|
|
});
|
|
|
|
const tenantId = (req: Request): number | undefined =>
|
|
(req.user as any)?.tenantId ?? undefined;
|
|
|
|
// ─── Nodes ────────────────────────────────────────────────────────────────────
|
|
|
|
router.get("/nodes", async (req: Request, res: Response) => {
|
|
try {
|
|
const type = req.query.type as string | undefined;
|
|
const limit = req.query.limit ? parseInt(req.query.limit as string) : 100;
|
|
const nodes = await graphService.getNodes(tenantId(req), type, limit);
|
|
res.json(nodes);
|
|
} catch (error: any) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
router.get("/nodes/:id", async (req: Request, res: Response) => {
|
|
try {
|
|
const node = await graphService.getNodeById(parseInt(req.params.id));
|
|
if (!node) return res.status(404).json({ error: "Nó não encontrado" });
|
|
res.json(node);
|
|
} catch (error: any) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
router.post("/nodes", async (req: Request, res: Response) => {
|
|
try {
|
|
const parsed = insertGraphNodeSchema.safeParse({
|
|
...req.body,
|
|
tenantId: tenantId(req),
|
|
});
|
|
if (!parsed.success) {
|
|
return res.status(400).json({ error: parsed.error.flatten() });
|
|
}
|
|
const node = await graphService.createNode(parsed.data);
|
|
res.status(201).json(node);
|
|
} catch (error: any) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
router.put("/nodes/:id", async (req: Request, res: Response) => {
|
|
try {
|
|
const node = await graphService.updateNode(parseInt(req.params.id), req.body);
|
|
if (!node) return res.status(404).json({ error: "Nó não encontrado" });
|
|
res.json(node);
|
|
} catch (error: any) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
router.delete("/nodes/:id", async (req: Request, res: Response) => {
|
|
try {
|
|
const deleted = await graphService.deleteNode(parseInt(req.params.id));
|
|
if (!deleted) return res.status(404).json({ error: "Nó não encontrado" });
|
|
res.json({ success: true });
|
|
} catch (error: any) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
// ─── Batch de Nodes ───────────────────────────────────────────────────────────
|
|
|
|
router.post("/nodes/batch", async (req: Request, res: Response) => {
|
|
try {
|
|
const { nodes } = req.body as { nodes: any[] };
|
|
if (!Array.isArray(nodes)) {
|
|
return res.status(400).json({ error: "Campo 'nodes' deve ser um array" });
|
|
}
|
|
const created = await Promise.all(
|
|
nodes.map((n) =>
|
|
graphService.createNode({ ...n, tenantId: tenantId(req) })
|
|
)
|
|
);
|
|
res.status(201).json(created);
|
|
} catch (error: any) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
// ─── Edges ────────────────────────────────────────────────────────────────────
|
|
|
|
router.get("/edges", async (req: Request, res: Response) => {
|
|
try {
|
|
const sourceId = req.query.sourceId ? parseInt(req.query.sourceId as string) : undefined;
|
|
const targetId = req.query.targetId ? parseInt(req.query.targetId as string) : undefined;
|
|
const edges = await graphService.getEdges(sourceId, targetId);
|
|
res.json(edges);
|
|
} catch (error: any) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
router.post("/edges", async (req: Request, res: Response) => {
|
|
try {
|
|
const parsed = insertGraphEdgeSchema.safeParse(req.body);
|
|
if (!parsed.success) {
|
|
return res.status(400).json({ error: parsed.error.flatten() });
|
|
}
|
|
const edge = await graphService.createEdge(parsed.data);
|
|
res.status(201).json(edge);
|
|
} catch (error: any) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
router.delete("/edges/:id", async (req: Request, res: Response) => {
|
|
try {
|
|
const deleted = await graphService.deleteEdge(parseInt(req.params.id));
|
|
if (!deleted) return res.status(404).json({ error: "Aresta não encontrada" });
|
|
res.json({ success: true });
|
|
} catch (error: any) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
// ─── Knowledge Base ───────────────────────────────────────────────────────────
|
|
|
|
router.get("/knowledge", async (req: Request, res: Response) => {
|
|
try {
|
|
const category = req.query.category as string | undefined;
|
|
const search = req.query.search as string | undefined;
|
|
const entries = await graphService.getKnowledgeEntries(category, search);
|
|
res.json(entries);
|
|
} catch (error: any) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
router.get("/knowledge/:id", async (req: Request, res: Response) => {
|
|
try {
|
|
const entry = await graphService.getKnowledgeEntry(parseInt(req.params.id));
|
|
if (!entry) return res.status(404).json({ error: "Entrada não encontrada" });
|
|
res.json(entry);
|
|
} catch (error: any) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
router.post("/knowledge", async (req: Request, res: Response) => {
|
|
try {
|
|
const parsed = insertKnowledgeBaseSchema.safeParse(req.body);
|
|
if (!parsed.success) {
|
|
return res.status(400).json({ error: parsed.error.flatten() });
|
|
}
|
|
const entry = await graphService.createKnowledgeEntry(parsed.data);
|
|
res.status(201).json(entry);
|
|
} catch (error: any) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
router.put("/knowledge/:id", async (req: Request, res: Response) => {
|
|
try {
|
|
const entry = await graphService.updateKnowledgeEntry(parseInt(req.params.id), req.body);
|
|
if (!entry) return res.status(404).json({ error: "Entrada não encontrada" });
|
|
res.json(entry);
|
|
} catch (error: any) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
router.delete("/knowledge/:id", async (req: Request, res: Response) => {
|
|
try {
|
|
const deleted = await graphService.deleteKnowledgeEntry(parseInt(req.params.id));
|
|
if (!deleted) return res.status(404).json({ error: "Entrada não encontrada" });
|
|
res.json({ success: true });
|
|
} catch (error: any) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
// ─── Busca Semântica ──────────────────────────────────────────────────────────
|
|
|
|
router.post("/search", async (req: Request, res: Response) => {
|
|
try {
|
|
const { query, n_results = 5 } = req.body as { query: string; n_results?: number };
|
|
if (!query) return res.status(400).json({ error: "Campo 'query' é obrigatório" });
|
|
|
|
const result = await graphService.semanticSearch(query, n_results);
|
|
res.json(result);
|
|
} catch (error: any) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
// ─── Grafo completo para visualização ────────────────────────────────────────
|
|
|
|
router.get("/visualization", async (req: Request, res: Response) => {
|
|
try {
|
|
const data = await graphService.getGraphData(tenantId(req));
|
|
res.json(data);
|
|
} catch (error: any) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
export default router;
|