- Primary model
- Secondary model
- Tertiary model
gemini-2.5-flashThe default model for generating readings. Provides the best balance of quality and speed.
Learn how Luz de Arcanos uses Google Gemini to generate personalized tarot interpretations with the Seraphina persona.
@google/genai SDK:
import { GoogleGenAI } from '@google/genai';
const ai = new GoogleGenAI({ apiKey });
const response = await ai.models.generateContent({
model: 'gemini-2.5-flash',
contents: prompt
});
GEMINI_API_KEY.const models = ['gemini-2.5-flash', 'gemini-2.0-flash', 'gemini-2.0-flash-lite'];
let reading: string | undefined;
for (const model of models) {
try {
const response = await ai.models.generateContent({ model, contents: prompt });
if (response.text) {
reading = response.text;
break;
}
} catch (err: any) {
if (err?.status === 429) continue;
break;
}
}
Seraphina's characteristics
const prompt = `Actúa como Seraphina, una tarotista profesional y empática.
Tu estilo es cálido pero directo y práctico. No usas palabras complicadas
ni eres excesivamente mística. Tu objetivo es ayudar a la persona con
consejos que pueda aplicar mañana mismo.
DATOS:
- Nombre: ${name}
- Pregunta: "${question}"
- Cartas: ${cardsText}
REGLAS DE ESCRITURA:
1. Sé breve: La lectura completa NO debe superar las 250 palabras.
2. Lenguaje claro: Habla como una amiga sabia, no como un libro antiguo.
3. Estructura directa:
- APERTURA: Hola ${name}, vamos a ver qué dicen las cartas.
- PASADO: Lo que te trajo aquí.
- PRESENTE: Lo que pasa ahora.
- FUTURO: Lo que viene.
- CONSEJO: Un paso práctico a seguir.
4. Tono: Positivo y constructivo, pero realista.
`;
const positions = ['Pasado', 'Presente', 'Futuro'] as const;
const cardsText = cards
.map((card, i) => {
const orientation = card.reversed ? 'invertida' : 'al derecho';
const keywords = card.reversed ? card.reversedKeywords : card.uprightKeywords;
return `• ${positions[i]}: ${card.name} (${orientation}) — ${card.description}. Energías: ${keywords.join(', ')}.`;
})
.join('\n');
• Pasado: El Loco (al derecho) — El inicio de un viaje, potencial ilimitado.
Energías: nuevos comienzos, aventura, inocencia, libertad.
• Presente: La Torre (invertida) — Derrumbe de estructuras falsas.
Energías: catástrofe evitada, resistencia, miedo al cambio, crisis interna.
• Futuro: El Sol (al derecho) — Radiante éxito, claridad de propósito.
Energías: alegría, éxito, vitalidad, claridad.
function getFallbackReading(name: string, cards: Array<{ name: string; reversed?: boolean }>) {
const [past, present, future] = cards;
return `Hola ${name}, vamos a ver qué dicen las cartas.
En el pasado, ${past.name} ${past.reversed ? 'invertida' : 'al derecho'} marca el punto
de partida de lo que estás viviendo.
En el presente, ${present.name} ${present.reversed ? 'invertida' : 'al derecho'} refleja
lo que está pasando ahora mismo.
Para el futuro, ${future.name} ${future.reversed ? 'invertida' : 'al derecho'} muestra
hacia dónde se dirigen las cosas si seguís el camino actual.
Mi consejo: revisá qué de tu pasado todavía estás cargando sin necesidad,
y enfocate en lo que sí podés cambiar hoy.`;
}
reading ??= getFallbackReading(name, cards);
??=) ensures the fallback is only used if no AI model succeeded.export const server = {
tarot: {
consult: defineAction({
input: z.object({
name: z.string().min(1).max(60),
question: z.string().min(1).max(500),
cards: z.array(CardSchema).length(3),
}),
handler: async ({ name, question, cards }) => {
const apiKey = import.meta.env.GEMINI_API_KEY;
if (!apiKey) {
throw new Error('GEMINI_API_KEY no configurada');
}
const ai = new GoogleGenAI({ apiKey });
const models = ['gemini-2.5-flash', 'gemini-2.0-flash', 'gemini-2.0-flash-lite'];
let reading: string | undefined;
for (const model of models) {
try {
const response = await ai.models.generateContent({ model, contents: prompt });
if (response.text) {
reading = response.text;
break;
}
} catch (err: any) {
if (err?.status === 429) continue;
break;
}
}
reading ??= getFallbackReading(name, cards);
return { reading };
},
}),
},
};
input: z.object({
name: z.string().min(1).max(60),
question: z.string().min(1).max(500),
cards: z.array(CardSchema).length(3),
})