feat: implement AI chat with vector search and random loading messages

Major Features:
-  AI chat with Azure OpenAI GPT-4o integration
-  Vector search across Bible versions (ASV English, RVA 1909 Spanish)
-  Multi-language support with automatic English fallback
-  Bible version citations in responses [ASV] [RVA 1909]
-  Random Bible-themed loading messages (5 variants)
-  Safe build script with memory guardrails
-  8GB swap memory for build safety
-  Stripe donation integration (multiple payment methods)

AI Chat Improvements:
- Implement vector search with 1536-dim embeddings (Azure text-embedding-ada-002)
- Search all Bible versions in user's language, fallback to English
- Cite Bible versions properly in AI responses
- Add 5 random loading messages: "Searching the Scriptures...", etc.
- Fix Ollama conflict (disabled to use Azure OpenAI exclusively)
- Optimize hybrid search queries for actual table schema

Build & Infrastructure:
- Create safe-build.sh script with memory monitoring (prevents server crashes)
- Add 8GB swap memory for emergency relief
- Document build process in BUILD_GUIDE.md
- Set Node.js memory limits (4GB max during builds)

Database:
- Clean up 115 old vector tables with wrong dimensions
- Keep only 2 tables with correct 1536-dim embeddings
- Add Stripe schema for donations and subscriptions

Documentation:
- AI_CHAT_FINAL_STATUS.md - Complete implementation status
- AI_CHAT_IMPLEMENTATION_COMPLETE.md - Technical details
- BUILD_GUIDE.md - Safe building guide with guardrails
- CHAT_LOADING_MESSAGES.md - Loading messages implementation
- STRIPE_IMPLEMENTATION_COMPLETE.md - Stripe integration docs
- STRIPE_SETUP_GUIDE.md - Stripe configuration guide

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-12 19:37:24 +00:00
parent b3ec31a265
commit a01377b21a
20 changed files with 3022 additions and 130 deletions

View File

@@ -0,0 +1,220 @@
'use client'
import { useEffect, useState, Suspense } from 'react'
import {
Container,
Typography,
Box,
Button,
Paper,
CircularProgress,
Alert,
} from '@mui/material'
import { CheckCircle, Favorite } from '@mui/icons-material'
import { useRouter, useSearchParams } from 'next/navigation'
import { useLocale } from 'next-intl'
function SuccessContent() {
const router = useRouter()
const locale = useLocale()
const searchParams = useSearchParams()
const sessionId = searchParams.get('session_id')
const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
useEffect(() => {
if (!sessionId) {
setError('No session ID found')
setLoading(false)
return
}
// Verify the session was successful
const verifySession = async () => {
try {
// In a real implementation, you might want to verify the session
// with a backend API call here
setLoading(false)
} catch (err) {
setError('Failed to verify donation')
setLoading(false)
}
}
verifySession()
}, [sessionId])
if (loading) {
return (
<Box
sx={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
minHeight: '100vh',
}}
>
<CircularProgress />
</Box>
)
}
if (error) {
return (
<Container maxWidth="sm" sx={{ py: 8 }}>
<Alert severity="error">{error}</Alert>
<Button
variant="contained"
onClick={() => router.push(`/${locale}/donate`)}
sx={{ mt: 3 }}
>
Go Back
</Button>
</Container>
)
}
return (
<Box sx={{ bgcolor: 'grey.50', minHeight: '100vh', py: 8 }}>
<Container maxWidth="md">
<Paper
elevation={2}
sx={{
p: 6,
textAlign: 'center',
borderTop: '4px solid',
borderColor: 'primary.main',
}}
>
<CheckCircle
sx={{
fontSize: 80,
color: 'success.main',
mb: 3,
}}
/>
<Typography
variant="h3"
sx={{
fontSize: { xs: '2rem', md: '2.5rem' },
fontWeight: 700,
mb: 2,
color: 'primary.main',
}}
>
Thank You for Your Donation!
</Typography>
<Typography
variant="h6"
sx={{
fontSize: { xs: '1.1rem', md: '1.3rem' },
color: 'text.secondary',
mb: 4,
lineHeight: 1.8,
}}
>
Your generous gift helps keep God&apos;s Word free and accessible to believers around
the world.
</Typography>
<Box
sx={{
bgcolor: 'primary.light',
color: 'white',
p: 4,
borderRadius: 2,
mb: 4,
}}
>
<Favorite sx={{ fontSize: 48, mb: 2 }} />
<Typography variant="h6" sx={{ fontWeight: 600, mb: 2 }}>
Your Impact
</Typography>
<Typography variant="body1" sx={{ lineHeight: 1.8 }}>
Every contribution big or small directly supports the servers, translations, and
technology that make Biblical Guide possible. You&apos;re not just giving to a
platform; you&apos;re opening doors to Scripture for millions who cannot afford to
pay.
</Typography>
</Box>
<Box
sx={{
bgcolor: 'grey.100',
p: 3,
borderRadius: 2,
mb: 4,
}}
>
<Typography variant="body1" sx={{ fontStyle: 'italic', mb: 2 }}>
Freely you have received; freely give.
</Typography>
<Typography variant="body2" sx={{ fontWeight: 600 }}>
Matthew 10:8
</Typography>
</Box>
<Typography variant="body2" color="text.secondary" sx={{ mb: 4 }}>
You will receive a confirmation email shortly with your donation receipt.
</Typography>
<Box sx={{ display: 'flex', gap: 2, justifyContent: 'center', flexWrap: 'wrap' }}>
<Button
variant="contained"
size="large"
onClick={() => router.push(`/${locale}`)}
sx={{
px: 4,
py: 1.5,
}}
>
Return to Home
</Button>
<Button
variant="outlined"
size="large"
onClick={() => router.push(`/${locale}/bible`)}
sx={{
px: 4,
py: 1.5,
}}
>
Read the Bible
</Button>
</Box>
<Typography
variant="body2"
color="text.secondary"
sx={{ mt: 4, fontStyle: 'italic' }}
>
Biblical Guide is a ministry supported by believers like you. Thank you for partnering
with us to keep the Gospel free forever.
</Typography>
</Paper>
</Container>
</Box>
)
}
export default function DonationSuccessPage() {
return (
<Suspense
fallback={
<Box
sx={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
minHeight: '100vh',
}}
>
<CircularProgress />
</Box>
}
>
<SuccessContent />
</Suspense>
)
}