105 lines
3.2 KiB
TypeScript
105 lines
3.2 KiB
TypeScript
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.39.3';
|
|
import { requireAuth, checkRateLimit } from '../_shared/auth.ts';
|
|
|
|
const corsHeaders = {
|
|
'Access-Control-Allow-Origin': '*',
|
|
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
|
|
};
|
|
|
|
Deno.serve(async (req) => {
|
|
if (req.method === 'OPTIONS') {
|
|
return new Response(null, { headers: corsHeaders });
|
|
}
|
|
|
|
try {
|
|
// Auth check
|
|
const auth = await requireAuth(req);
|
|
if (auth.error) return auth.error;
|
|
|
|
// Rate limit check (20 AI suggestions per hour)
|
|
const supabaseService = createClient(
|
|
Deno.env.get('SUPABASE_URL')!,
|
|
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
|
|
);
|
|
const rateLimitResponse = await checkRateLimit(auth.userId, 'ai_suggest', supabaseService);
|
|
if (rateLimitResponse) return rateLimitResponse;
|
|
|
|
const apiKey = Deno.env.get('INTEGRATIONS_API_KEY');
|
|
if (!apiKey) {
|
|
throw new Error('INTEGRATIONS_API_KEY not configured');
|
|
}
|
|
|
|
const { query, count = 10, offset = 0, safeSearch = 'Moderate', freshness, mkt, cc } = await req.json();
|
|
|
|
if (!query) {
|
|
return new Response(
|
|
JSON.stringify({ error: 'Query is required' }),
|
|
{ status: 400, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
|
|
);
|
|
}
|
|
|
|
// Build query parameters
|
|
const params = new URLSearchParams({
|
|
q: query,
|
|
count: count.toString(),
|
|
offset: offset.toString(),
|
|
safeSearch,
|
|
});
|
|
|
|
if (freshness) params.append('freshness', freshness);
|
|
if (mkt) params.append('mkt', mkt);
|
|
if (cc) params.append('cc', cc);
|
|
|
|
// Call Smart Search API
|
|
const response = await fetch(
|
|
`https://app-9w9pd00g5j41-api-VaOwP8E7dKEa.gateway.appmedo.com/search/FgEFxazBTfRUumJx/smart?${params.toString()}`,
|
|
{
|
|
method: 'GET',
|
|
headers: {
|
|
'X-Gateway-Authorization': `Bearer ${apiKey}`,
|
|
},
|
|
}
|
|
);
|
|
|
|
if (!response.ok) {
|
|
const errorText = await response.text();
|
|
throw new Error(`Smart Search API error: ${response.status} - ${errorText}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
|
|
// Log search to database
|
|
const authHeader = req.headers.get('Authorization');
|
|
if (authHeader) {
|
|
const supabaseUrl = Deno.env.get('SUPABASE_URL')!;
|
|
const supabaseKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!;
|
|
const supabase = createClient(supabaseUrl, supabaseKey);
|
|
|
|
const token = authHeader.replace('Bearer ', '');
|
|
const { data: { user } } = await supabase.auth.getUser(token);
|
|
|
|
if (user) {
|
|
await supabase.from('admin_search_history').insert({
|
|
admin_id: user.id,
|
|
search_type: 'smart_search',
|
|
query: query,
|
|
results_count: data.webPages?.value?.length || 0,
|
|
metadata: { count, offset, safeSearch, freshness, mkt, cc }
|
|
});
|
|
}
|
|
}
|
|
|
|
return new Response(
|
|
JSON.stringify(data),
|
|
{ headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
|
|
);
|
|
|
|
} catch (error) {
|
|
console.error('Smart Search error:', error);
|
|
return new Response(
|
|
JSON.stringify({ error: error.message }),
|
|
{ status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
|
|
);
|
|
}
|
|
});
|