Files
mini/src/pages/api/intelligence/spintax/validate.ts

220 lines
6.6 KiB
TypeScript

import type { APIRoute } from 'astro';
/**
* Spintax Pattern Validator
* Check syntax before running 10k generations
*/
function validateGodToken(request: Request): boolean {
const token = request.headers.get('X-God-Token') ||
request.headers.get('Authorization')?.replace('Bearer ', '') ||
new URL(request.url).searchParams.get('token');
const godToken = process.env.GOD_MODE_TOKEN || import.meta.env.GOD_MODE_TOKEN;
if (!godToken) return true;
return token === godToken;
}
interface ValidationError {
type: string;
position: number;
message: string;
}
/**
* Validate spintax pattern syntax
*/
function validateSpintax(pattern: string): { valid: boolean; errors: ValidationError[] } {
const errors: ValidationError[] = [];
let braceStack: number[] = [];
let inBraces = false;
let currentDepth = 0;
const maxDepth = 3;
for (let i = 0; i < pattern.length; i++) {
const char = pattern[i];
const prevChar = i > 0 ? pattern[i - 1] : '';
// Check for opening brace
if (char === '{' && prevChar !== '\\') {
braceStack.push(i);
currentDepth++;
inBraces = true;
if (currentDepth > maxDepth) {
errors.push({
type: 'max_depth',
position: i,
message: `Nested too deep (max ${maxDepth} levels)`
});
}
}
// Check for closing brace
if (char === '}' && prevChar !== '\\') {
if (braceStack.length === 0) {
errors.push({
type: 'unmatched_closing',
position: i,
message: 'Closing brace without opening brace'
});
} else {
const openPos = braceStack.pop();
const content = pattern.substring(openPos! + 1, i);
// Check for empty braces
if (content.trim() === '') {
errors.push({
type: 'empty_braces',
position: openPos!,
message: 'Empty option set {}'
});
}
// Check for missing pipes
if (!content.includes('|')) {
errors.push({
type: 'no_alternatives',
position: openPos!,
message: 'Option set must contain at least one pipe |'
});
}
// Check for empty options
const options = content.split('|');
for (let j = 0; j < options.length; j++) {
if (options[j].trim() === '') {
errors.push({
type: 'empty_option',
position: openPos! + content.indexOf('||'),
message: 'Empty option between pipes'
});
}
}
currentDepth--;
}
inBraces = braceStack.length > 0;
}
}
// Check for unclosed braces
if (braceStack.length > 0) {
for (const pos of braceStack) {
errors.push({
type: 'unclosed_brace',
position: pos,
message: 'Opening brace not closed'
});
}
}
return {
valid: errors.length === 0,
errors
};
}
/**
* Generate a few sample variations
*/
function generateSamples(pattern: string, count: number = 3): string[] {
const samples: string[] = [];
for (let i = 0; i < count; i++) {
let result = pattern;
const regex = /\{([^{}]+)\}/g;
result = result.replace(regex, (match, content) => {
const options = content.split('|').map((s: string) => s.trim());
return options[Math.floor(Math.random() * options.length)];
});
samples.push(result);
}
return samples;
}
export const POST: APIRoute = async ({ request }) => {
if (!validateGodToken(request)) {
return new Response(JSON.stringify({ error: 'Unauthorized' }), {
status: 401,
headers: { 'Content-Type': 'application/json' }
});
}
try {
const { pattern, max_depth = 3 } = await request.json();
if (!pattern) {
return new Response(JSON.stringify({
error: 'Missing pattern'
}), {
status: 400,
headers: { 'Content-Type': 'application/json' }
});
}
const validation = validateSpintax(pattern);
const samples = validation.valid ? generateSamples(pattern, 5) : [];
return new Response(JSON.stringify({
pattern,
valid: validation.valid,
errors: validation.errors,
samples: validation.valid ? samples : null,
stats: {
length: pattern.length,
braces: (pattern.match(/\{/g) || []).length,
pipes: (pattern.match(/\|/g) || []).length
},
recommendation: validation.valid
? '✅ Pattern is valid - safe to use in batch generation'
: '❌ Fix errors before using in production',
timestamp: new Date().toISOString()
}), {
status: 200,
headers: { 'Content-Type': 'application/json' }
});
} catch (error: any) {
return new Response(JSON.stringify({
error: 'Validation failed',
details: error.message
}), {
status: 500,
headers: { 'Content-Type': 'application/json' }
});
}
};
export const GET: APIRoute = async ({ request }) => {
if (!validateGodToken(request)) {
return new Response(JSON.stringify({ error: 'Unauthorized' }), {
status: 401,
headers: { 'Content-Type': 'application/json' }
});
}
return new Response(JSON.stringify({
endpoint: 'POST /api/intelligence/spintax/validate',
description: 'Validate spintax patterns before batch generation',
examples: {
valid: '{Hello|Hi|Hey} {world|there|friend}!',
invalid: '{Hello|Hi} {world',
nested: '{The {best|top} {solution|answer}}',
empty: '{|option} // Error: empty option'
},
errors_detected: [
'unmatched_braces',
'empty_option_sets',
'no_alternatives',
'max_depth_exceeded'
]
}, null, 2), {
status: 200,
headers: { 'Content-Type': 'application/json' }
});
};