story-generator/supabase/functions/generate-word-audio/index.ts
Lucas Santana 0c2a63dcd3
Some checks are pending
Docker Build and Push / build (push) Waiting to run
fix: corrigindo CORS
2025-01-18 17:42:58 -03:00

110 lines
3.1 KiB
TypeScript

import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
import { createClient } from "https://esm.sh/@supabase/supabase-js@2";
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
'Cross-Origin-Resource-Policy': 'cross-origin'
};
serve(async (req) => {
if (req.method === 'OPTIONS') {
return new Response('ok', { headers: corsHeaders });
}
try {
const { word } = await req.json();
if (!word || typeof word !== 'string') {
throw new Error('Palavra inválida');
}
// Criar cliente Supabase
const supabaseClient = createClient(
Deno.env.get('SUPABASE_URL') ?? '',
Deno.env.get('SUPABASE_ANON_KEY') ?? ''
);
// Verificar se já existe áudio para esta palavra
const { data: existingAudio } = await supabaseClient
.from('phonics_word_audio')
.select('audio_url')
.eq('word', word.toLowerCase())
.single();
if (existingAudio?.audio_url) {
return new Response(
JSON.stringify({ audioUrl: existingAudio.audio_url }),
{ headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
);
}
// Gerar novo áudio usando Text-to-Speech
const response = await fetch('https://api.elevenlabs.io/v1/text-to-speech/21m00Tcm4TlvDq8ikWAM', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'xi-api-key': Deno.env.get('ELEVEN_LABS_API_KEY') ?? '',
},
body: JSON.stringify({
text: word,
model_id: "eleven_multilingual_v2",
voice_settings: {
stability: 0.75,
similarity_boost: 0.75,
style: 0.5,
use_speaker_boost: true
}
}),
});
if (!response.ok) {
throw new Error('Erro ao gerar áudio');
}
const audioBuffer = await response.arrayBuffer();
const audioBase64 = btoa(String.fromCharCode(...new Uint8Array(audioBuffer)));
// Salvar áudio no storage
const fileName = `${word.toLowerCase()}_${Date.now()}.mp3`;
const { error: uploadError } = await supabaseClient.storage
.from('phonics-audio')
.upload(fileName, audioBuffer, {
contentType: 'audio/mpeg',
cacheControl: '31536000', // 1 ano
});
if (uploadError) {
throw uploadError;
}
// Obter URL pública
const { data: { publicUrl } } = supabaseClient.storage
.from('phonics-audio')
.getPublicUrl(fileName);
// Salvar referência no banco
await supabaseClient
.from('phonics_word_audio')
.insert({
word: word.toLowerCase(),
audio_url: publicUrl,
audio_path: fileName,
});
return new Response(
JSON.stringify({ audioUrl: publicUrl }),
{ headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
);
} catch (error) {
console.error('Error:', error);
return new Response(
JSON.stringify({ error: error.message }),
{
status: 400,
headers: { ...corsHeaders, 'Content-Type': 'application/json' }
}
);
}
});