83 lines
2.5 KiB
TypeScript
83 lines
2.5 KiB
TypeScript
// src/pages/api/search/semantic.ts
|
|
import type { APIRoute } from 'astro';
|
|
import { getToolsData } from '../../../utils/dataService.js';
|
|
import { configDotenv } from 'dotenv';
|
|
|
|
configDotenv();
|
|
|
|
const DEFAULT_MAX_RESULTS = (() => {
|
|
const raw = process.env.AI_EMBEDDING_CANDIDATES;
|
|
const n = Number.parseInt(raw ?? '', 10);
|
|
return Number.isFinite(n) && n > 0 ? n : 50;
|
|
})();
|
|
|
|
const DEFAULT_THRESHOLD = (() => {
|
|
const raw = process.env.AI_SIMILARITY_THRESHOLD;
|
|
const n = Number.parseFloat(raw ?? '');
|
|
return Number.isFinite(n) && n >= 0 && n <= 1 ? n : 0.45;
|
|
})();
|
|
|
|
export const prerender = false;
|
|
|
|
|
|
export const POST: APIRoute = async ({ request }) => {
|
|
try {
|
|
const {
|
|
query,
|
|
maxResults = DEFAULT_MAX_RESULTS,
|
|
threshold = DEFAULT_THRESHOLD
|
|
} = await request.json();
|
|
|
|
if (!query || typeof query !== 'string') {
|
|
return new Response(
|
|
JSON.stringify({ success: false, error: 'Query is required' }),
|
|
{ status: 400, headers: { 'Content-Type': 'application/json' } }
|
|
);
|
|
}
|
|
|
|
/* --- (rest of the handler unchanged) -------------------------- */
|
|
const { embeddingsService } = await import('../../../utils/embeddings.js');
|
|
|
|
if (!embeddingsService.isEnabled()) {
|
|
return new Response(
|
|
JSON.stringify({ success: false, error: 'Semantic search not available' }),
|
|
{ status: 400, headers: { 'Content-Type': 'application/json' } }
|
|
);
|
|
}
|
|
|
|
await embeddingsService.waitForInitialization();
|
|
|
|
const similarItems = await embeddingsService.findSimilar(
|
|
query.trim(),
|
|
maxResults,
|
|
threshold
|
|
);
|
|
|
|
const toolsData = await getToolsData();
|
|
const rankedTools = similarItems
|
|
.map((s, i) => {
|
|
const tool = toolsData.tools.find(t => t.name === s.name);
|
|
return tool ? { ...tool, _semanticSimilarity: s.similarity, _semanticRank: i + 1 } : null;
|
|
})
|
|
.filter(Boolean);
|
|
|
|
return new Response(
|
|
JSON.stringify({
|
|
success: true,
|
|
query: query.trim(),
|
|
results: rankedTools,
|
|
totalFound: rankedTools.length,
|
|
semanticSearch: true,
|
|
threshold,
|
|
maxSimilarity: rankedTools[0]?._semanticSimilarity ?? 0
|
|
}),
|
|
{ status: 200, headers: { 'Content-Type': 'application/json' } }
|
|
);
|
|
} catch (error) {
|
|
console.error('Semantic search error:', error);
|
|
return new Response(
|
|
JSON.stringify({ success: false, error: 'Semantic search failed' }),
|
|
{ status: 500, headers: { 'Content-Type': 'application/json' } }
|
|
);
|
|
}
|
|
}; |