first iteration - buggy

This commit is contained in:
overcuriousity
2025-08-16 18:15:20 +02:00
parent 1d98dd3257
commit 0c7c502b03
12 changed files with 1939 additions and 2437 deletions

View File

@@ -1,17 +1,19 @@
// src/pages/api/ai/embeddings-status.ts
// src/pages/api/ai/embeddings-status.ts - Updated
import type { APIRoute } from 'astro';
import { embeddingsService } from '../../../utils/embeddings.js';
export const prerender = false;
export const GET: APIRoute = async () => {
try {
const { embeddingsService } = await import('../../../utils/embeddings.js');
await embeddingsService.waitForInitialization();
const stats = embeddingsService.getStats();
const status = stats.enabled && stats.initialized ? 'ready' :
stats.enabled && !stats.initialized ? 'initializing' : 'disabled';
console.log(`[EMBEDDINGS-STATUS-API] Service status: ${status}, stats:`, stats);
return new Response(JSON.stringify({
success: true,
embeddings: stats,
@@ -23,6 +25,8 @@ export const GET: APIRoute = async () => {
});
} catch (error) {
console.error('[EMBEDDINGS-STATUS-API] Error checking embeddings status:', error);
return new Response(JSON.stringify({
success: false,
embeddings: { enabled: false, initialized: false, count: 0 },

View File

@@ -1,23 +1,13 @@
// src/pages/api/ai/enhance-input.ts - Enhanced AI service compatibility
// src/pages/api/ai/enhance-input.ts - Updated to use refactored services
import type { APIRoute } from 'astro';
import { withAPIAuth } from '../../../utils/auth.js';
import { apiError, apiServerError, createAuthErrorResponse } from '../../../utils/api.js';
import { enqueueApiCall } from '../../../utils/rateLimitedQueue.js';
import { aiService } from '../../../utils/aiService.js';
import { JSONParser } from '../../../utils/jsonUtils.js';
export const prerender = false;
function getEnv(key: string): string {
const value = process.env[key];
if (!value) {
throw new Error(`Missing environment variable: ${key}`);
}
return value;
}
const AI_ENDPOINT = getEnv('AI_ANALYZER_ENDPOINT');
const AI_ANALYZER_API_KEY = getEnv('AI_ANALYZER_API_KEY');
const AI_ANALYZER_MODEL = getEnv('AI_ANALYZER_MODEL');
const rateLimitStore = new Map<string, { count: number; resetTime: number }>();
const RATE_LIMIT_WINDOW = 60 * 1000;
const RATE_LIMIT_MAX = 5;
@@ -49,7 +39,7 @@ function checkRateLimit(userId: string): boolean {
return true;
}
function cleanupExpiredRateLimits() {
function cleanupExpiredRateLimits(): void {
const now = Date.now();
for (const [userId, limit] of rateLimitStore.entries()) {
if (now > limit.resetTime) {
@@ -94,39 +84,6 @@ ${input}
`.trim();
}
async function callAIService(prompt: string): Promise<Response> {
const endpoint = AI_ENDPOINT;
const apiKey = AI_ANALYZER_API_KEY;
const model = AI_ANALYZER_MODEL;
let headers: Record<string, string> = {
'Content-Type': 'application/json'
};
if (apiKey) {
headers['Authorization'] = `Bearer ${apiKey}`;
console.log('[ENHANCE API] Using API key authentication');
} else {
console.log('[ENHANCE API] No API key - making request without authentication');
}
const requestBody = {
model,
messages: [{ role: 'user', content: prompt }],
max_tokens: 300,
temperature: 0.7,
top_p: 0.9,
frequency_penalty: 0.2,
presence_penalty: 0.1
};
return fetch(`${endpoint}/v1/chat/completions`, {
method: 'POST',
headers,
body: JSON.stringify(requestBody)
});
}
export const POST: APIRoute = async ({ request }) => {
try {
const authResult = await withAPIAuth(request, 'ai');
@@ -155,28 +112,26 @@ export const POST: APIRoute = async ({ request }) => {
const systemPrompt = createEnhancementPrompt(sanitizedInput);
const taskId = `enhance_${userId}_${Date.now()}_${Math.random().toString(36).substr(2, 4)}`;
const aiResponse = await enqueueApiCall(() => callAIService(systemPrompt), taskId);
console.log(`[ENHANCE-API] Processing enhancement request for user: ${userId}`);
const aiResponse = await enqueueApiCall(() =>
aiService.callAI(systemPrompt, {
maxTokens: 300,
temperature: 0.7
}), taskId);
if (!aiResponse.ok) {
const errorText = await aiResponse.text();
console.error('[ENHANCE API] AI enhancement error:', errorText, 'Status:', aiResponse.status);
return apiServerError.unavailable('Enhancement service unavailable');
}
const aiData = await aiResponse.json();
const aiContent = aiData.choices?.[0]?.message?.content;
if (!aiContent) {
if (!aiResponse.content) {
return apiServerError.unavailable('No enhancement response');
}
let questions;
try {
const cleanedContent = aiContent
const cleanedContent = aiResponse.content
.replace(/^```json\s*/i, '')
.replace(/\s*```\s*$/, '')
.trim();
questions = JSON.parse(cleanedContent);
questions = JSONParser.safeParseJSON(cleanedContent, []);
if (!Array.isArray(questions)) {
throw new Error('Response is not an array');
@@ -198,11 +153,11 @@ export const POST: APIRoute = async ({ request }) => {
}
} catch (error) {
console.error('Failed to parse enhancement response:', aiContent);
console.error('[ENHANCE-API] Failed to parse enhancement response:', aiResponse.content);
questions = [];
}
console.log(`[ENHANCE API] User: ${userId}, Forensics Questions: ${questions.length}, Input length: ${sanitizedInput.length}`);
console.log(`[ENHANCE-API] User: ${userId}, Questions generated: ${questions.length}, Input length: ${sanitizedInput.length}`);
return new Response(JSON.stringify({
success: true,
@@ -215,7 +170,7 @@ export const POST: APIRoute = async ({ request }) => {
});
} catch (error) {
console.error('Enhancement error:', error);
console.error('[ENHANCE-API] Enhancement error:', error);
return apiServerError.internal('Enhancement processing failed');
}
};

View File

@@ -1,4 +1,4 @@
// src/pages/api/ai/query.ts
// src/pages/api/ai/query.ts - Updated to use refactored services
import type { APIRoute } from 'astro';
import { withAPIAuth } from '../../../utils/auth.js';
import { apiError, apiServerError, createAuthErrorResponse } from '../../../utils/api.js';
@@ -20,15 +20,14 @@ const MAIN_RATE_LIMIT_MAX = parseInt(process.env.AI_RATE_LIMIT_MAX_REQUESTS || '
const MICRO_TASK_TOTAL_LIMIT = parseInt(process.env.AI_MICRO_TASK_TOTAL_LIMIT || '50', 10);
function sanitizeInput(input: string): string {
let sanitized = input
return input
.replace(/```[\s\S]*?```/g, '[CODE_BLOCK_REMOVED]')
.replace(/\<\/?[^>]+(>|$)/g, '')
.replace(/\b(system|assistant|user)\s*[:]/gi, '[ROLE_REMOVED]')
.replace(/\b(ignore|forget|disregard)\s+(previous|all|your)\s+(instructions?|context|rules?)/gi, '[INSTRUCTION_REMOVED]')
.trim();
sanitized = sanitized.slice(0, 2000).replace(/\s+/g, ' ');
return sanitized;
.trim()
.slice(0, 2000)
.replace(/\s+/g, ' ');
}
function checkRateLimit(userId: string): { allowed: boolean; reason?: string; microTasksRemaining?: number } {
@@ -77,7 +76,7 @@ function incrementMicroTaskCount(userId: string, aiCallsMade: number): void {
}
}
function cleanupExpiredRateLimits() {
function cleanupExpiredRateLimits(): void {
const now = Date.now();
const maxStoreSize = 1000;
@@ -117,51 +116,52 @@ export const POST: APIRoute = async ({ request }) => {
const body = await request.json();
const { query, mode = 'workflow', taskId: clientTaskId } = body;
console.log(`[MICRO-TASK API] Received request - TaskId: ${clientTaskId}, Mode: ${mode}, Query length: ${query?.length || 0}`);
console.log(`[MICRO-TASK API] Micro-task calls remaining: ${rateLimitResult.microTasksRemaining}`);
console.log(`[AI-API] Received request - TaskId: ${clientTaskId}, Mode: ${mode}, Query length: ${query?.length || 0}`);
console.log(`[AI-API] Micro-task calls remaining: ${rateLimitResult.microTasksRemaining}`);
if (!query || typeof query !== 'string') {
console.log(`[MICRO-TASK API] Invalid query for task ${clientTaskId}`);
console.log(`[AI-API] Invalid query for task ${clientTaskId}`);
return apiError.badRequest('Query required');
}
if (!['workflow', 'tool'].includes(mode)) {
console.log(`[MICRO-TASK API] Invalid mode for task ${clientTaskId}: ${mode}`);
console.log(`[AI-API] Invalid mode for task ${clientTaskId}: ${mode}`);
return apiError.badRequest('Invalid mode. Must be "workflow" or "tool"');
}
const sanitizedQuery = sanitizeInput(query);
if (sanitizedQuery.includes('[FILTERED]')) {
console.log(`[MICRO-TASK API] Filtered input detected for task ${clientTaskId}`);
console.log(`[AI-API] Filtered input detected for task ${clientTaskId}`);
return apiError.badRequest('Invalid input detected');
}
const taskId = clientTaskId || `ai_${userId}_${Date.now()}_${Math.random().toString(36).substr(2, 6)}`;
console.log(`[MICRO-TASK API] About to enqueue micro-task pipeline ${taskId}`);
console.log(`[AI-API] Enqueueing pipeline task ${taskId}`);
const result = await enqueueApiCall(() =>
aiPipeline.processQuery(sanitizedQuery, mode)
, taskId);
if (!result || !result.recommendation) {
return apiServerError.unavailable('No response from micro-task AI pipeline');
return apiServerError.unavailable('No response from AI pipeline');
}
const stats = result.processingStats;
const estimatedAICallsMade = stats.microTasksCompleted + stats.microTasksFailed;
incrementMicroTaskCount(userId, estimatedAICallsMade);
console.log(`[MICRO-TASK API] Pipeline completed for ${taskId}:`);
console.log(` - Mode: ${mode}`);
console.log(` - User: ${userId}`);
console.log(` - Query length: ${sanitizedQuery.length}`);
console.log(` - Processing time: ${stats.processingTimeMs}ms`);
console.log(` - Micro-tasks completed: ${stats.microTasksCompleted}`);
console.log(` - Micro-tasks failed: ${stats.microTasksFailed}`);
console.log(` - Estimated AI calls: ${estimatedAICallsMade}`);
console.log(` - Embeddings used: ${stats.embeddingsUsed}`);
console.log(` - Final items: ${stats.finalSelectedItems}`);
console.log(`[AI-API] Pipeline completed for ${taskId}:`, {
mode,
user: userId,
queryLength: sanitizedQuery.length,
processingTime: stats.processingTimeMs,
microTasksCompleted: stats.microTasksCompleted,
microTasksFailed: stats.microTasksFailed,
estimatedAICalls: estimatedAICallsMade,
embeddingsUsed: stats.embeddingsUsed,
finalItems: stats.finalSelectedItems
});
const currentLimit = rateLimitStore.get(userId);
const remainingMicroTasks = currentLimit ?
@@ -175,7 +175,7 @@ export const POST: APIRoute = async ({ request }) => {
query: sanitizedQuery,
processingStats: {
...result.processingStats,
pipelineType: 'micro-task',
pipelineType: 'refactored',
microTasksSuccessRate: stats.microTasksCompleted / (stats.microTasksCompleted + stats.microTasksFailed),
averageTaskTime: stats.processingTimeMs / (stats.microTasksCompleted + stats.microTasksFailed),
estimatedAICallsMade
@@ -191,18 +191,16 @@ export const POST: APIRoute = async ({ request }) => {
});
} catch (error) {
console.error('[MICRO-TASK API] Pipeline error:', error);
console.error('[AI-API] Pipeline error:', error);
if (error.message.includes('embeddings')) {
return apiServerError.unavailable('Embeddings service error - using AI fallback');
} else if (error.message.includes('micro-task')) {
return apiServerError.unavailable('Micro-task pipeline error - some analysis steps failed');
} else if (error.message.includes('selector')) {
return apiServerError.unavailable('AI selector service error');
return apiServerError.unavailable('Embeddings service error');
} else if (error.message.includes('AI')) {
return apiServerError.unavailable('AI service error');
} else if (error.message.includes('rate limit')) {
return apiError.rateLimit('AI service rate limits exceeded during micro-task processing');
return apiError.rateLimit('AI service rate limits exceeded');
} else {
return apiServerError.internal('Micro-task AI pipeline error');
return apiServerError.internal('AI pipeline error');
}
}
};