Fix hero card aspect ratio and add horoscope generation functionality
Introduce horoscope generation via OpenAI API, including new API endpoints and database schema. Adjust card components in `home.tsx` to use `aspect-[16/9]` for consistent image sizing, resolving previous height stretching issues. Update dependencies in `package.json`. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 413891e8-d784-4bea-b9f5-91a5a68316b4 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: ca1aa952-242c-43c1-9e28-47aed39cee1b Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/f209e72a-0939-48fa-84fc-57854de71967/413891e8-d784-4bea-b9f5-91a5a68316b4/nTLKCC5 Replit-Helium-Checkpoint-Created: true
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
import OpenAI from "openai";
|
||||
import { db } from "./db";
|
||||
import { dailyHoroscopes } from "@shared/schema";
|
||||
import { eq, and } from "drizzle-orm";
|
||||
|
||||
const openai = new OpenAI({
|
||||
apiKey: process.env.AI_INTEGRATIONS_OPENAI_API_KEY,
|
||||
baseURL: process.env.AI_INTEGRATIONS_OPENAI_BASE_URL,
|
||||
});
|
||||
|
||||
const SIGN_NAMES = [
|
||||
"Widder", "Stier", "Zwillinge", "Krebs", "Löwe", "Jungfrau",
|
||||
"Waage", "Skorpion", "Schütze", "Steinbock", "Wassermann", "Fische"
|
||||
];
|
||||
|
||||
function getTodayStr(): string {
|
||||
const d = new Date();
|
||||
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
|
||||
}
|
||||
|
||||
export async function getHoroscopesForToday(): Promise<any[]> {
|
||||
const today = getTodayStr();
|
||||
const existing = await db.select().from(dailyHoroscopes).where(eq(dailyHoroscopes.dateStr, today));
|
||||
if (existing.length === 12) return existing;
|
||||
return [];
|
||||
}
|
||||
|
||||
export async function generateDailyHoroscopes(): Promise<void> {
|
||||
const today = getTodayStr();
|
||||
|
||||
const existing = await db.select().from(dailyHoroscopes).where(eq(dailyHoroscopes.dateStr, today));
|
||||
if (existing.length >= 12) {
|
||||
console.log(`Horoscopes for ${today} already exist.`);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`Generating horoscopes for ${today}...`);
|
||||
|
||||
for (let i = 0; i < SIGN_NAMES.length; i++) {
|
||||
const signName = SIGN_NAMES[i];
|
||||
|
||||
const alreadyExists = existing.find(h => h.signIndex === i);
|
||||
if (alreadyExists) continue;
|
||||
|
||||
try {
|
||||
const response = await openai.chat.completions.create({
|
||||
model: "gpt-5-mini",
|
||||
messages: [
|
||||
{
|
||||
role: "system",
|
||||
content: `Du bist ein erfahrener Astrologe, der tägliche Horoskope für eine deutschsprachige Volksmusik- und Schlager-Nachrichtenwebsite schreibt. Dein Stil ist warm, ermutigend und poetisch. Du beziehst manchmal Musik, Natur und alpine Kultur in deine Texte ein. Schreibe immer auf Deutsch. Das heutige Datum ist ${today}.`
|
||||
},
|
||||
{
|
||||
role: "user",
|
||||
content: `Erstelle ein ausführliches Tageshoroskop für das Sternzeichen ${signName} für heute (${today}).
|
||||
|
||||
Antworte NUR mit einem JSON-Objekt in diesem exakten Format (kein Markdown, keine Erklärung):
|
||||
{
|
||||
"general": "Ausführlicher allgemeiner Tagestext, mindestens 4-5 Sätze über die allgemeine Energie, Stimmung und Möglichkeiten des Tages.",
|
||||
"love": "Ausführlicher Text über Liebe und Partnerschaft, mindestens 3-4 Sätze mit konkreten Ratschlägen für Singles und Paare.",
|
||||
"career": "Ausführlicher Text über Beruf und Finanzen, mindestens 3-4 Sätze mit konkreten Tipps.",
|
||||
"health": "Ausführlicher Text über Gesundheit und Wohlbefinden, mindestens 3-4 Sätze.",
|
||||
"tip": "Ein konkreter, umsetzbarer Tipp des Tages in 1-2 Sätzen.",
|
||||
"weekly": "Ausführliche Wochenvorschau, mindestens 4-5 Sätze mit Hinweisen für jeden Wochentag.",
|
||||
"monthly": "Ausführliche Monatsvorschau, mindestens 4-5 Sätze über die wichtigsten Themen des Monats."
|
||||
}`
|
||||
}
|
||||
],
|
||||
temperature: 0.9,
|
||||
max_tokens: 2000,
|
||||
});
|
||||
|
||||
const content = response.choices[0]?.message?.content || "";
|
||||
const jsonMatch = content.match(/\{[\s\S]*\}/);
|
||||
if (!jsonMatch) {
|
||||
console.error(`Failed to parse horoscope for ${signName}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const parsed = JSON.parse(jsonMatch[0]);
|
||||
|
||||
await db.insert(dailyHoroscopes).values({
|
||||
signIndex: i,
|
||||
signName,
|
||||
dateStr: today,
|
||||
general: parsed.general || "",
|
||||
love: parsed.love || "",
|
||||
career: parsed.career || "",
|
||||
health: parsed.health || "",
|
||||
tip: parsed.tip || "",
|
||||
weekly: parsed.weekly || "",
|
||||
monthly: parsed.monthly || "",
|
||||
});
|
||||
|
||||
console.log(`Generated horoscope for ${signName}`);
|
||||
} catch (err: any) {
|
||||
console.error(`Error generating horoscope for ${signName}:`, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`Horoscope generation complete for ${today}.`);
|
||||
}
|
||||
|
||||
export async function getOrGenerateHoroscope(signIndex: number): Promise<any | null> {
|
||||
const today = getTodayStr();
|
||||
|
||||
const [existing] = await db.select().from(dailyHoroscopes)
|
||||
.where(and(eq(dailyHoroscopes.dateStr, today), eq(dailyHoroscopes.signIndex, signIndex)));
|
||||
|
||||
if (existing) return existing;
|
||||
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user