mirror of
https://github.com/mblanke/Dashboard.git
synced 2026-03-01 04:00:22 -05:00
fix: add POST handler to /api/rag for semantic search + agent proxy
- Added POST handler that proxies retrieve/agent/tags actions to RAG API - Maps RAG API response shape (chunks[].rerank_score) to frontend expected format - Normalizes rerank_score (0-10 range) to 0-1 score for display - Disabled tags fetch on mount (blocks RAG API - scrolls all 49k Qdrant points)
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
const RAG_API = process.env.RAG_API_URL || "http://localhost:8099";
|
||||
|
||||
/* ─── GET /api/rag → status + ingest-progress ─── */
|
||||
export async function GET() {
|
||||
try {
|
||||
const [statusRes, progressRes] = await Promise.all([
|
||||
@@ -32,3 +33,95 @@ export async function GET() {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/* ─── POST /api/rag → proxy retrieve / agent / tags ─── */
|
||||
export async function POST(req: NextRequest) {
|
||||
try {
|
||||
const body = await req.json();
|
||||
const { action, ...params } = body;
|
||||
|
||||
/* --- tags --------------------------------------------------------- */
|
||||
if (action === "tags") {
|
||||
const res = await fetch(`${RAG_API}/tags`, {
|
||||
next: { revalidate: 0 },
|
||||
});
|
||||
const data = await res.json();
|
||||
// normalise → always return { tags: string[] }
|
||||
const tags: string[] = Array.isArray(data)
|
||||
? data
|
||||
: Array.isArray(data.tags)
|
||||
? data.tags
|
||||
: [];
|
||||
return NextResponse.json({ tags });
|
||||
}
|
||||
|
||||
/* --- retrieve (semantic search) ----------------------------------- */
|
||||
if (action === "retrieve") {
|
||||
const res = await fetch(`${RAG_API}/retrieve`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
question: params.question,
|
||||
top_k: params.top_k ?? 8,
|
||||
tags: params.tags,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
const err = await res.text();
|
||||
return NextResponse.json(
|
||||
{ error: err || "RAG retrieve failed" },
|
||||
{ status: res.status }
|
||||
);
|
||||
}
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
// RAG API returns { chunks: [...] } — map to frontend's expected shape
|
||||
const chunks = data.chunks ?? data.results ?? (Array.isArray(data) ? data : []);
|
||||
const results = chunks.map((c: Record<string, unknown>) => ({
|
||||
title: c.title ?? "",
|
||||
text: c.text ?? "",
|
||||
source: c.source_path ?? c.source ?? "",
|
||||
page: c.page ?? null,
|
||||
score: c.rerank_score != null
|
||||
? Math.min((c.rerank_score as number) / 10, 1) // normalise rerank_score ≈0-10 → 0-1
|
||||
: c.score ?? null,
|
||||
tags: c.tags ?? [],
|
||||
}));
|
||||
|
||||
return NextResponse.json(results);
|
||||
}
|
||||
|
||||
/* --- agent --------------------------------------------------------- */
|
||||
if (action === "agent") {
|
||||
const res = await fetch(`${RAG_API}/agent`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
question: params.question,
|
||||
max_steps: params.max_steps ?? 5,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
const err = await res.text();
|
||||
return NextResponse.json(
|
||||
{ error: err || "RAG agent failed" },
|
||||
{ status: res.status }
|
||||
);
|
||||
}
|
||||
|
||||
const data = await res.json();
|
||||
return NextResponse.json(data);
|
||||
}
|
||||
|
||||
return NextResponse.json(
|
||||
{ error: `Unknown action: ${action}` },
|
||||
{ status: 400 }
|
||||
);
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : "Unexpected error";
|
||||
return NextResponse.json({ error: message }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,20 +232,20 @@ export default function SemanticSearch() {
|
||||
const [agentResult, setAgentResult] = useState<AgentResponse | null>(null);
|
||||
|
||||
// fetch tags on mount
|
||||
useEffect(() => {
|
||||
ragFetch({ action: "tags" })
|
||||
.then((data) => {
|
||||
const tags: string[] = Array.isArray(data)
|
||||
? data
|
||||
: Array.isArray(data.tags)
|
||||
? data.tags
|
||||
: [];
|
||||
setAvailableTags(tags);
|
||||
})
|
||||
.catch(() => {
|
||||
/* silently ignore – tags are optional */
|
||||
});
|
||||
}, []);
|
||||
// useEffect(() => {
|
||||
// ragFetch({ action: "tags" })
|
||||
// .then((data) => {
|
||||
// const tags: string[] = Array.isArray(data)
|
||||
// ? data
|
||||
// : Array.isArray(data.tags)
|
||||
// ? data.tags
|
||||
// : [];
|
||||
// setAvailableTags(tags);
|
||||
// })
|
||||
// .catch(() => {
|
||||
// /* silently ignore – tags are optional */
|
||||
// });
|
||||
// }, []);
|
||||
|
||||
const toggleTag = useCallback((tag: string) => {
|
||||
setSelectedTags((prev) =>
|
||||
|
||||
Reference in New Issue
Block a user