Files
Spanglish/frontend/src/app/llms.txt/route.ts
2026-02-12 05:17:47 +00:00

197 lines
6.2 KiB
TypeScript

import { NextResponse } from 'next/server';
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://spanglish.com.py';
const apiUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001';
interface LlmsFaq {
question: string;
answer: string;
}
interface LlmsEvent {
id: string;
title: string;
titleEs?: string;
shortDescription?: string;
shortDescriptionEs?: string;
description: string;
descriptionEs?: string;
startDatetime: string;
endDatetime?: string;
location: string;
price: number;
currency: string;
availableSeats?: number;
status: string;
}
async function getNextUpcomingEvent(): Promise<LlmsEvent | null> {
try {
const response = await fetch(`${apiUrl}/api/events/next/upcoming`, {
next: { tags: ['next-event'] },
});
if (!response.ok) return null;
const data = await response.json();
return data.event || null;
} catch {
return null;
}
}
async function getUpcomingEvents(): Promise<LlmsEvent[]> {
try {
const response = await fetch(`${apiUrl}/api/events?status=published&upcoming=true`, {
next: { tags: ['next-event'] },
});
if (!response.ok) return [];
const data = await response.json();
return data.events || [];
} catch {
return [];
}
}
// Event times are always shown in Paraguay time (America/Asuncion) so llms.txt
// matches what users see on the website, regardless of server timezone.
const EVENT_TIMEZONE = 'America/Asuncion';
function formatEventDate(dateStr: string): string {
return new Date(dateStr).toLocaleDateString('en-US', {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric',
timeZone: EVENT_TIMEZONE,
});
}
function formatEventTime(dateStr: string): string {
return new Date(dateStr).toLocaleTimeString('en-US', {
hour: '2-digit',
minute: '2-digit',
hour12: true,
timeZone: EVENT_TIMEZONE,
});
}
function formatPrice(price: number, currency: string): string {
if (price === 0) return 'Free';
return `${price.toLocaleString()} ${currency}`;
}
async function getHomepageFaqs(): Promise<LlmsFaq[]> {
try {
const response = await fetch(`${apiUrl}/api/faq?homepage=true`, {
next: { revalidate: 3600 },
});
if (!response.ok) return [];
const data = await response.json();
return (data.faqs || []).map((f: any) => ({
question: f.question,
answer: f.answer,
}));
} catch {
return [];
}
}
export async function GET() {
const [nextEvent, upcomingEvents, faqs] = await Promise.all([
getNextUpcomingEvent(),
getUpcomingEvents(),
getHomepageFaqs(),
]);
const lines: string[] = [];
// Header
lines.push('# Spanglish Community');
lines.push('');
lines.push('> English-Spanish language exchange community organizing social events and meetups in Asunción, Paraguay.');
lines.push('');
lines.push(`- Website: ${siteUrl}`);
lines.push(`- Events page: ${siteUrl}/events`);
// Social links
const instagram = process.env.NEXT_PUBLIC_INSTAGRAM;
const whatsapp = process.env.NEXT_PUBLIC_WHATSAPP;
const telegram = process.env.NEXT_PUBLIC_TELEGRAM;
const email = process.env.NEXT_PUBLIC_EMAIL;
if (instagram) lines.push(`- Instagram: https://instagram.com/${instagram}`);
if (telegram) lines.push(`- Telegram: https://t.me/${telegram}`);
if (email) lines.push(`- Email: ${email}`);
if (whatsapp) lines.push(`- WhatsApp: ${whatsapp}`);
lines.push('');
// Next Event (most important section for AI)
lines.push('## Next Event');
lines.push('');
if (nextEvent) {
lines.push(`- Event: ${nextEvent.title}`);
lines.push(`- Date: ${formatEventDate(nextEvent.startDatetime)}`);
lines.push(`- Time: ${formatEventTime(nextEvent.startDatetime)}`);
if (nextEvent.endDatetime) {
lines.push(`- End time: ${formatEventTime(nextEvent.endDatetime)}`);
}
lines.push(`- Location: ${nextEvent.location}, Asunción, Paraguay`);
lines.push(`- Price: ${formatPrice(nextEvent.price, nextEvent.currency)}`);
if (nextEvent.availableSeats !== undefined) {
lines.push(`- Available spots: ${nextEvent.availableSeats}`);
}
lines.push(`- Details and tickets: ${siteUrl}/events/${nextEvent.id}`);
if (nextEvent.shortDescription) {
lines.push(`- Description: ${nextEvent.shortDescription}`);
}
} else {
lines.push('No upcoming events currently scheduled. Check back soon or follow us on social media for announcements.');
}
lines.push('');
// All upcoming events
if (upcomingEvents.length > 1) {
lines.push('## All Upcoming Events');
lines.push('');
for (const event of upcomingEvents) {
lines.push(`### ${event.title}`);
lines.push(`- Date: ${formatEventDate(event.startDatetime)}`);
lines.push(`- Time: ${formatEventTime(event.startDatetime)}`);
lines.push(`- Location: ${event.location}, Asunción, Paraguay`);
lines.push(`- Price: ${formatPrice(event.price, event.currency)}`);
lines.push(`- Details: ${siteUrl}/events/${event.id}`);
lines.push('');
}
}
// About section
lines.push('## About Spanglish');
lines.push('');
lines.push('Spanglish is a language exchange community based in Asunción, Paraguay. We organize regular social events where people can practice English and Spanish in a relaxed, friendly environment. Our events bring together locals and internationals for conversation, cultural exchange, and fun.');
lines.push('');
lines.push('## Frequently Asked Questions');
lines.push('');
if (faqs.length > 0) {
for (const faq of faqs) {
lines.push(`- **${faq.question}** ${faq.answer}`);
}
} else {
lines.push('- **What is Spanglish?** A language exchange community that hosts social events to practice English and Spanish.');
lines.push('- **Where are events held?** In Asunción, Paraguay. Specific venues are listed on each event page.');
lines.push('- **How do I attend an event?** Visit the events page to see upcoming events and book tickets.');
}
lines.push(`- More FAQ: ${siteUrl}/faq`);
lines.push('');
const content = lines.join('\n');
return new NextResponse(content, {
headers: {
'Content-Type': 'text/plain; charset=utf-8',
'Cache-Control': 'public, max-age=3600, s-maxage=3600, stale-while-revalidate=86400',
},
});
}