From 79f1512f3ab39bb74f394ee239e2724247e8bec2 Mon Sep 17 00:00:00 2001 From: Andrei Date: Fri, 10 Oct 2025 22:38:19 +0000 Subject: [PATCH] feat: Apple-style donation-focused landing page + Azure OpenAI fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Major updates: - Replace homepage with clean, minimalist Apple-style landing page - Focus on donation messaging and mission statement - Add comprehensive AI chat analysis documentation - Fix Azure OpenAI configuration with correct endpoints - Update embedding API to use text-embedding-ada-002 (1536 dims) Landing Page Features: - Hero section with tagline "Every Scripture. Every Language. Forever Free" - Mission statement emphasizing free access - Matthew 10:8 verse highlight - 6 feature cards (Global Library, Multilingual, Prayer Wall, AI Chat, Privacy, Offline) - Donation CTA sections with PayPal and card options - "Why It Matters" section with dark background - Clean footer with navigation links Technical Changes: - Updated .env.local with new Azure credentials - Fixed vector-search.ts to support separate embed API version - Integrated AuthModal into Bible reader and prayers page - Made prayer filters collapsible and mobile-responsive - Changed language picker to single-select Documentation Created: - AI_CHAT_FIX_PLAN.md - Comprehensive implementation plan - AI_CHAT_VERIFICATION_FINDINGS.md - Database analysis - AI_CHAT_ANALYSIS_SUMMARY.md - Executive summary - AI_CHAT_STATUS_UPDATE.md - Current status and next steps - logo.svg - App logo (MenuBook icon) Build: โœ… Successful (Next.js 15.5.3) ๐Ÿค– Generated with Claude Code Co-Authored-By: Claude --- .duckversions/-20251010181141.618.env | 29 + .env.local | 13 +- AI_CHAT_ANALYSIS_SUMMARY.md | 402 ++++++ AI_CHAT_FIX_PLAN.md | 1877 +++++++++++++++++++++++++ AI_CHAT_STATUS_UPDATE.md | 287 ++++ AI_CHAT_VERIFICATION_FINDINGS.md | 334 +++++ app/[locale]/bible/reader.tsx | 63 +- app/[locale]/page.tsx | 1132 +++++++-------- app/[locale]/prayers/page.tsx | 210 +-- components/auth/auth-modal.tsx | 334 +++++ components/chat/floating-chat.tsx | 28 + lib/vector-search.ts | 3 +- logo.svg | 4 + messages/en.json | 4 +- messages/es.json | 4 +- messages/it.json | 4 +- messages/ro.json | 4 +- 17 files changed, 4066 insertions(+), 666 deletions(-) create mode 100644 .duckversions/-20251010181141.618.env create mode 100644 AI_CHAT_ANALYSIS_SUMMARY.md create mode 100644 AI_CHAT_FIX_PLAN.md create mode 100644 AI_CHAT_STATUS_UPDATE.md create mode 100644 AI_CHAT_VERIFICATION_FINDINGS.md create mode 100644 components/auth/auth-modal.tsx create mode 100644 logo.svg diff --git a/.duckversions/-20251010181141.618.env b/.duckversions/-20251010181141.618.env new file mode 100644 index 0000000..a5f1fc1 --- /dev/null +++ b/.duckversions/-20251010181141.618.env @@ -0,0 +1,29 @@ +# Database +DATABASE_URL=postgresql://postgres:a3ppq@10.0.0.207:5432/biblical-guide +DB_PASSWORD=a3ppq + +# Build optimizations +NEXT_TELEMETRY_DISABLED=1 +DISABLE_ESLINT_PLUGIN=true + +# Authentication +NEXTAUTH_URL=https://biblical-guide.com +NEXTAUTH_SECRET=development-secret-change-in-production +JWT_SECRET=development-jwt-secret-change-in-production + +# Azure OpenAI +AZURE_OPENAI_KEY=4sVcRlDOB7WnRK8oE6ATnokpKmc02JgY4GH2ng9y1vr1CyFT7ORLJQQJ99BDAC5RqLJXJ3w3AAAAACOGW8Kh +AZURE_OPENAI_ENDPOINT=https://footprints-open-ai.openai.azure.com +AZURE_OPENAI_DEPLOYMENT=gpt-4o +AZURE_OPENAI_API_VERSION=2025-01-01-preview + +# API Bible +API_BIBLE_KEY=7b42606f8f809e155c9b0742c4f1849b + +# Ollama for embeddings +OLLAMA_API_URL=http://localhost:11434 +OLLAMA_EMBED_MODEL=llama3.1:latest +BIBLE_JSON_DIR=/root/biblical-guide/bibles/json + +# WebSocket port +WEBSOCKET_PORT=3015 \ No newline at end of file diff --git a/.env.local b/.env.local index 9a2ee1b..b371f77 100644 --- a/.env.local +++ b/.env.local @@ -12,13 +12,14 @@ NEXTAUTH_URL=https://biblical-guide.com NEXTAUTH_SECRET=development-secret-change-in-production JWT_SECRET=development-jwt-secret-change-in-production -# Azure OpenAI -AZURE_OPENAI_KEY=4DhkkXVdDOXZ7xX1eOLHTHQQnbCy0jFYdA6RPJtyAdOMtO16nZmFJQQJ99BCACYeBjFXJ3w3AAABACOGHgNC -AZURE_OPENAI_ENDPOINT=https://azureopenaiinstant.openai.azure.com +# Azure OpenAI (Updated 2025-10-10) +AZURE_OPENAI_KEY=42702a67a41547919877a2ab8e4837f9 +AZURE_OPENAI_ENDPOINT=https://footprints-ai.openai.azure.com AZURE_OPENAI_DEPLOYMENT=gpt-4o -AZURE_OPENAI_API_VERSION=2024-05-01-preview -AZURE_OPENAI_EMBED_DEPLOYMENT=embed-3 -EMBED_DIMS=3072 +AZURE_OPENAI_API_VERSION=2025-01-01-preview +AZURE_OPENAI_EMBED_DEPLOYMENT=Text-Embedding-ada-002-V2 +AZURE_OPENAI_EMBED_API_VERSION=2023-05-15 +EMBED_DIMS=1536 BIBLE_MD_PATH=./bibles/Biblia-Fidela-limba-romana.md LANG_CODE=ro TRANSLATION_CODE=FIDELA diff --git a/AI_CHAT_ANALYSIS_SUMMARY.md b/AI_CHAT_ANALYSIS_SUMMARY.md new file mode 100644 index 0000000..c2e3a61 --- /dev/null +++ b/AI_CHAT_ANALYSIS_SUMMARY.md @@ -0,0 +1,402 @@ +# AI Chat System Analysis - Executive Summary + +**Date:** 2025-10-10 +**Analyst:** Claude Code +**Status:** ๐Ÿ”ด Critical Issues Found - Requires User Action + +--- + +## ๐ŸŽฏ Bottom Line + +The AI chat system has **excellent infrastructure** (vector database, search algorithms) but is blocked by **two critical issues**: + +1. **โŒ Azure OpenAI Not Configured** - No deployments exist or are accessible +2. **โŒ Wrong Bible Versions** - Priority languages (Romanian, Spanish, Italian) are NOT in database + +**Good News:** +- โœ… Ollama embedding model is being installed now (alternative to Azure) +- โœ… Vector search code is production-ready +- โœ… Database has 116 fully-embedded Bible versions + +--- + +## ๐Ÿ“Š System Status Report + +### Vector Database: โœ… EXCELLENT (100%) + +| Component | Status | Details | +|-----------|--------|---------| +| PostgreSQL Connection | โœ… Working | v17.5 | +| pgvector Extension | โœ… Installed | v0.8.0 | +| Schema `ai_bible` | โœ… Exists | Ready | +| Total Vector Tables | โœ… 116 tables | 100% embedded | +| Languages Supported | โš ๏ธ 47 languages | BUT missing priority ones | + +### AI API Status: โŒ BLOCKED + +| Service | Status | Issue | +|---------|--------|-------| +| Azure OpenAI Chat | โŒ Not Working | Deployment `gpt-4o` not found (404) | +| Azure OpenAI Embeddings | โŒ Not Working | Deployment `embed-3` not found (404) | +| Ollama (Local AI) | ๐Ÿ”„ Installing | `nomic-embed-text` downloading now | + +### Vector Search Code: โœ… READY + +| Feature | Status | Location | +|---------|--------|----------| +| Multi-table search | โœ… Implemented | `/lib/vector-search.ts:109` | +| Hybrid search (vector + text) | โœ… Implemented | `/lib/vector-search.ts:163` | +| Language filtering | โœ… Implemented | Table pattern: `bv_{lang}_{version}` | +| Chat integration | โœ… Implemented | `/app/api/chat/route.ts:190` | + +--- + +## ๐Ÿšจ Critical Issue #1: Wrong Bible Versions + +### User Requirements vs. Reality + +**What You Need:** +- โœ… English +- โŒ Romanian (ro) +- โŒ Spanish (es) +- โŒ Italian (it) + +**What's in Database:** +- โœ… English: 9 versions (KJV, ASV, etc.) +- โŒ Romanian: **NOT FOUND** +- โŒ Spanish: **NOT FOUND** +- โŒ Italian: **NOT FOUND** + +### What IS in the Database (47 Languages) + +The 116 tables contain mostly obscure languages: +- `ab` (Abkhazian), `ac` (Acholi), `ad` (Adangme), `ag` (Aguacateca), etc. +- German (de), Dutch (nl), French (fr) โœ“ +- But **NO Romanian, Spanish, or Italian** + +### Where These Tables Came From + +Looking at your environment variable: +```bash +BIBLE_MD_PATH=./bibles/Biblia-Fidela-limba-romana.md +LANG_CODE=ro +TRANSLATION_CODE=FIDELA +``` + +You have Romanian Bible data (`Fidela`) but it's **NOT in the vector database yet**. + +--- + +## ๐Ÿšจ Critical Issue #2: Azure OpenAI Not Configured + +### The Problem + +Your `.env.local` has: +```bash +AZURE_OPENAI_DEPLOYMENT=gpt-4o +AZURE_OPENAI_EMBED_DEPLOYMENT=embed-3 +``` + +But when we try to access these deployments: +``` +โŒ Error 404: DeploymentNotFound +"The API deployment for this resource does not exist" +``` + +### Tested All Common Names - None Work + +We automatically tested these deployment names: +- Chat: `gpt-4`, `gpt-4o`, `gpt-35-turbo`, `gpt-4-32k`, `chat`, `gpt4`, `gpt4o` +- Embeddings: `text-embedding-ada-002`, `text-embedding-3-small`, `embed`, `embed-3`, `ada-002` + +**Result:** All returned 404 + +### What This Means + +Either: +1. **No deployments have been created yet** in your Azure OpenAI resource +2. **Deployments have custom names** that we can't guess +3. **API key doesn't have access** to the deployments + +### How to Check + +1. Go to Azure Portal: https://portal.azure.com +2. Find your resource: `azureopenaiinstant.openai.azure.com` +3. Click "Deployments" or "Model deployments" +4. **Screenshot what you see** and share deployment names + +--- + +## โœ… The Good News: Ollama Alternative + +### Ollama is Available Locally + +We found Ollama running on your server: +- URL: `http://localhost:11434` +- Chat model installed: `llama3.1:latest` โœ… +- Embedding model: `nomic-embed-text` (downloading now... ~260MB) + +### What Ollama Can Do + +| Capability | Status | +|------------|--------| +| Generate embeddings | โœ… Yes (once download completes) | +| Vector search queries | โœ… Yes | +| Generate chat responses | โœ… Yes (using llama3.1) | +| **Cost** | โœ… **FREE** (runs locally) | + +### Ollama vs. Azure OpenAI + +| Feature | Ollama | Azure OpenAI | +|---------|--------|--------------| +| Cost | Free | Pay per token | +| Speed | Fast (local) | Moderate (network) | +| Quality | Good | Excellent | +| Multilingual | Good | Excellent | +| Configuration | โœ… Working now | โŒ Broken | + +--- + +## ๐ŸŽฌ What Happens Next + +### Option A: Use Ollama (Can Start Now) + +**Pros:** +- โœ… Already working on your server +- โœ… Free (no API costs) +- โœ… Fast (local processing) +- โœ… Can generate embeddings for Romanian/Spanish/Italian Bibles + +**Cons:** +- โš ๏ธ Slightly lower quality than GPT-4 +- โš ๏ธ Requires local compute resources + +**Implementation:** +1. Wait for `nomic-embed-text` download to complete (~2 minutes) +2. Update `.env.local` to prefer Ollama: + ```bash + OLLAMA_API_URL=http://localhost:11434 + OLLAMA_EMBED_MODEL=nomic-embed-text + ``` +3. Create embeddings for Romanian/Spanish/Italian Bibles +4. Chat will use `llama3.1` for responses + +### Option B: Fix Azure OpenAI (Requires Azure Access) + +**Pros:** +- โœ… Higher quality responses (GPT-4) +- โœ… Better multilingual support +- โœ… Scalable for many users + +**Cons:** +- โŒ Costs money per API call +- โŒ Requires Azure Portal access +- โŒ Blocked until deployments are created + +**Implementation:** +1. Log into Azure Portal +2. Go to Azure OpenAI resource +3. Create two deployments: + - Chat: Deploy `gpt-4` or `gpt-35-turbo` (name it anything) + - Embeddings: Deploy `text-embedding-ada-002` or `text-embedding-3-small` +4. Update `.env.local` with actual deployment names +5. Test with our verification script + +### Option C: Hybrid (Best of Both) + +Use Ollama for embeddings (free) + Azure for chat (quality): + +```bash +# Use Ollama for embeddings +OLLAMA_API_URL=http://localhost:11434 +OLLAMA_EMBED_MODEL=nomic-embed-text + +# Use Azure for chat (once fixed) +AZURE_OPENAI_DEPLOYMENT= +``` + +--- + +## ๐Ÿ“‹ Required Actions (In Order) + +### Immediate (Today) + +1. **Decision:** Choose Option A (Ollama), B (Azure), or C (Hybrid) + +2. **If Ollama (Option A or C):** + - โœ… Download is in progress + - Wait 2-5 minutes for completion + - Test with: `curl -X POST http://localhost:11434/api/embeddings -d '{"model":"nomic-embed-text","prompt":"test"}'` + +3. **If Azure (Option B or C):** + - Log into Azure Portal + - Navigate to Azure OpenAI resource + - Check/create deployments + - Share deployment names + +### Short-term (This Week) + +4. **Get Romanian Bible Data:** + - Source: `/bibles/Biblia-Fidela-limba-romana.md` (already exists!) + - Need: Cornilescu version (if available) + - Action: Create embeddings and import + +5. **Get Spanish Bible Data:** + - Source needed: RVR1960 (Reina-Valera 1960) + - Optional: NVI (Nueva Versiรณn Internacional) + - Action: Find source, create embeddings, import + +6. **Get Italian Bible Data:** + - Source needed: Nuova Diodati + - Optional: Nuova Riveduta + - Action: Find source, create embeddings, import + +### Medium-term (Next 2 Weeks) + +7. **Implement English Fallback:** + - When Romanian/Spanish/Italian searches return poor results + - Automatically search English versions + - Add language indicator in citations: `[KJV - English] John 3:16` + +8. **Create Version Config Table:** + - Track which versions are complete + - Map versions to languages + - Enable smart fallback logic + +9. **Testing:** + - Test Romanian queries โ†’ Romanian results + - Test Spanish queries โ†’ Spanish results + - Test Italian queries โ†’ Italian results + - Test fallback when needed + +--- + +## ๐Ÿ”ง Technical Details + +### Current Database Schema + +Table naming pattern: +``` +ai_bible.bv_{language_code}_{version_abbreviation} + +Examples: +- ai_bible.bv_en_eng_kjv โœ… Exists (English KJV) +- ai_bible.bv_ro_cornilescu โŒ Needed (Romanian Cornilescu) +- ai_bible.bv_es_rvr1960 โŒ Needed (Spanish RVR1960) +- ai_bible.bv_it_nuovadiodati โŒ Needed (Italian Nuova Diodati) +``` + +### Table Structure (All 116 tables have this) + +| Column | Type | Description | +|--------|------|-------------| +| `id` | uuid | Primary key | +| `testament` | text | OT/NT | +| `book` | text | Book name | +| `chapter` | integer | Chapter number | +| `verse` | integer | Verse number | +| `language` | text | Language code | +| `translation` | text | Version abbreviation | +| `ref` | text | "Genesis 1:1" format | +| `text_raw` | text | Verse text | +| `text_norm` | text | Normalized text | +| `tsv` | tsvector | Full-text search index | +| **`embedding`** | vector | **Vector embedding (3072 dims)** | +| `created_at` | timestamp | Creation time | +| `updated_at` | timestamp | Update time | + +### Embedding Dimensions + +Current `.env.local` says: +```bash +EMBED_DIMS=3072 +``` + +This matches: +- โœ… Azure `text-embedding-3-small` (3072 dims) +- โœ… Azure `text-embedding-3-large` (3072 dims) +- โŒ Azure `text-embedding-ada-002` (1536 dims) - **INCOMPATIBLE** +- โœ… Ollama `nomic-embed-text` (768 dims default, but can use 3072) + +**Important:** If using Ollama, we may need to adjust embedding dimensions or re-create tables. + +--- + +## ๐Ÿ’ก Recommendations + +### My Recommendation: Start with Ollama + +**Why:** +1. โœ… It's already working (or will be in 5 minutes) +2. โœ… Free (no API costs while developing) +3. โœ… Can immediately create Romanian embeddings from your `Fidela` Bible +4. โœ… Unblocks development + +**Then:** +- Add Azure OpenAI later for higher quality (when deployments are fixed) +- Use hybrid: Ollama for embeddings, Azure for chat + +### Workflow I Suggest + +``` +Today: +โ†’ Finish installing Ollama embedding model +โ†’ Test embedding generation +โ†’ Create embeddings for Fidela Romanian Bible +โ†’ Import into ai_bible.bv_ro_fidela +โ†’ Test Romanian chat + +This Week: +โ†’ Fix Azure deployments (for better chat quality) +โ†’ Find Spanish RVR1960 data +โ†’ Find Italian Nuova Diodati data +โ†’ Create embeddings for both +โ†’ Import into database + +Next Week: +โ†’ Implement English fallback +โ†’ Add version metadata table +โ†’ Create test suite +โ†’ Optimize performance +``` + +--- + +## ๐Ÿ“ž Questions for You + +1. **AI Provider:** Do you want to use Ollama (free, local) or fix Azure OpenAI (better quality, costs money)? + +2. **Azure Access:** Do you have access to the Azure Portal to check/create deployments? + +3. **Bible Data:** Do you have Spanish (RVR1960) and Italian (Nuova Diodati) Bible data, or do we need to source it? + +4. **Fidela Bible:** The file `./bibles/Biblia-Fidela-limba-romana.md` exists - should we create embeddings for this now? + +5. **Embedding Dimensions:** Are you okay with potentially re-creating embedding tables with different dimensions if we switch from Azure (3072) to Ollama (768)? + +--- + +## ๐Ÿ“„ Reference Documents + +| Document | Purpose | Location | +|----------|---------|----------| +| Implementation Plan | Detailed technical plan | `/AI_CHAT_FIX_PLAN.md` | +| Verification Findings | Database analysis | `/AI_CHAT_VERIFICATION_FINDINGS.md` | +| This Summary | Executive overview | `/AI_CHAT_ANALYSIS_SUMMARY.md` | +| Verification Script | System health check | `/scripts/verify-ai-system.ts` | +| Deployment Discovery | Find Azure deployments | `/scripts/discover-azure-deployments.ts` | + +--- + +## โœ… Next Action + +**Waiting for your decision:** +- Option A: Use Ollama โ† **Recommended to start** +- Option B: Fix Azure OpenAI +- Option C: Hybrid approach + +Once you decide, I can immediately proceed with implementation. + +--- + +**Status:** Analysis complete. Ready to implement based on your choice. ๐Ÿš€ diff --git a/AI_CHAT_FIX_PLAN.md b/AI_CHAT_FIX_PLAN.md new file mode 100644 index 0000000..9602059 --- /dev/null +++ b/AI_CHAT_FIX_PLAN.md @@ -0,0 +1,1877 @@ +# AI Chat Vector Search Implementation Plan +## Biblical Guide - Vector Database Integration & Multi-Language Search + +**Document Version:** 1.0 +**Date:** January 2025 +**Status:** Implementation Plan + +--- + +## Table of Contents + +1. [Executive Summary](#1-executive-summary) +2. [Current State Analysis](#2-current-state-analysis) +3. [Requirements & Specifications](#3-requirements--specifications) +4. [Architecture Overview](#4-architecture-overview) +5. [Database Schema Analysis](#5-database-schema-analysis) +6. [Implementation Plan](#6-implementation-plan) +7. [Vector Search Logic](#7-vector-search-logic) +8. [API Integration](#8-api-integration) +9. [Testing Strategy](#9-testing-strategy) +10. [Deployment & Monitoring](#10-deployment--monitoring) + +--- + +## 1. Executive Summary + +### 1.1 Objective + +Implement a robust vector search system for the AI chat that: +- โœ… Searches through all Bible versions in the user's language +- โœ… Returns comprehensive answers with Bible version citations +- โœ… Falls back to English versions when language-specific content is unavailable +- โœ… Maintains conversation context and accuracy +- โœ… Provides multilingual responses (English, Romanian, Spanish, Italian) + +### 1.2 Current Status + +- **Completed:** Vector embeddings for ALL Bible versions in dedicated vector database +- **Pending:** Integration of vector search into AI chat system +- **Pending:** Multi-language search logic implementation +- **Pending:** Fallback mechanism for incomplete translations + +### 1.3 Success Criteria + +1. **Accuracy:** AI chat returns biblically accurate answers with verse citations +2. **Language Support:** Searches user's language first, falls back to English when needed +3. **Performance:** Vector search completes in < 2 seconds +4. **Coverage:** All 4 languages supported (en, ro, es, it) +5. **Citations:** Always provides Bible version and verse references + +--- + +## 2. Current State Analysis + +### 2.1 Codebase Investigation Tasks + +**TASK 1: Identify Current AI Chat Implementation** +- [ ] Locate AI chat API routes (`/app/api/chat/`) +- [ ] Find chat component files (`/components/chat/`) +- [ ] Identify current AI provider (OpenAI, Anthropic, etc.) +- [ ] Review conversation storage mechanism +- [ ] Check current embedding/vector search usage (if any) + +**TASK 2: Database Schema Review** +- [ ] Analyze vector database structure +- [ ] Document all Bible version tables +- [ ] Verify embedding dimensions and metadata +- [ ] Check indexing configuration +- [ ] Review language-to-version mapping + +**TASK 3: API Connection Audit** +- [ ] Verify AI API credentials (OpenAI, Anthropic, etc.) +- [ ] Check vector database connection (Supabase, Pinecone, pgvector, etc.) +- [ ] Test API rate limits and quotas +- [ ] Validate environment variables +- [ ] Test connection stability + +**TASK 4: Current Search Flow Analysis** +- [ ] Document existing question โ†’ answer flow +- [ ] Identify where vector search should be integrated +- [ ] Review prompt engineering approach +- [ ] Check context window management +- [ ] Analyze response formatting + +--- + +## 3. Requirements & Specifications + +### 3.1 Functional Requirements + +#### FR-1: Multi-Language Vector Search +**Description:** System must search Bible versions in user's language first + +**User Languages โ†’ Bible Versions Mapping:** +``` +English (en) โ†’ Bible versions: + - KJV (King James Version) + - NIV (New International Version) + - ESV (English Standard Version) + - NASB (New American Standard Bible) + - [other English versions] + +Romanian (ro) โ†’ Bible versions: + - Cornilescu 1924 + - Cornilescu 2024 + - Dumitru Cornilescu + - [other Romanian versions] + +Spanish (es) โ†’ Bible versions: + - Reina-Valera 1960 + - Nueva Versiรณn Internacional (NVI) + - Biblia de las Amรฉricas + - [other Spanish versions] + +Italian (it) โ†’ Bible versions: + - Nuova Riveduta 2006 + - La Sacra Bibbia (Diodati) + - Conferenza Episcopale Italiana + - [other Italian versions] +``` + +**Acceptance Criteria:** +- System identifies user language from chat context +- Searches all versions available in that language +- Returns results from multiple versions when applicable +- Cites version name with each reference + +#### FR-2: Fallback to English +**Description:** When no language-specific content found, search English versions + +**Fallback Conditions:** +1. No Bible versions available in user's language +2. Bible incomplete in user's language (missing books/verses) +3. Vector search returns no results in user's language +4. Confidence score below threshold + +**Acceptance Criteria:** +- Automatic fallback when conditions met +- User informed about language switch (transparent) +- Response translated to user's language +- English version citations included + +#### FR-3: Citation Requirements +**Description:** All answers must include proper Bible citations + +**Citation Format:** +``` +[Version Abbreviation] [Book] [Chapter]:[Verse] + +Examples: +- "According to KJV John 3:16..." +- "Cornilescu Genesis 1:1 states..." +- "As written in NIV Romans 8:28..." +``` + +**Acceptance Criteria:** +- Every Bible reference includes version name +- Book, chapter, verse always specified +- Multiple versions cited when providing comprehensive answer +- Citations are clickable links to Bible reader + +#### FR-4: Comprehensive Answers +**Description:** Search multiple versions and synthesize comprehensive response + +**Answer Structure:** +1. Direct answer to user's question +2. Supporting verses from multiple versions +3. Cross-references when relevant +4. Contextual explanation +5. Links to full passages in Bible reader + +**Acceptance Criteria:** +- Uses 2-4 Bible versions in typical response +- Provides context around cited verses +- Highlights version differences when significant +- Offers to show full passage + +### 3.2 Technical Requirements + +#### TR-1: Vector Database Structure +**Database Type:** PostgreSQL with pgvector extension (or Supabase Vector) + +**Table Schema (per Bible version):** +```sql +-- Example: bible_vectors_kjv (King James Version) +CREATE TABLE bible_vectors_kjv ( + id SERIAL PRIMARY KEY, + book VARCHAR(50) NOT NULL, -- e.g., "Genesis" + chapter INTEGER NOT NULL, + verse INTEGER NOT NULL, + text TEXT NOT NULL, -- The verse text + embedding vector(1536), -- OpenAI ada-002 embeddings + metadata JSONB, -- Additional data + version VARCHAR(20) DEFAULT 'KJV', + language VARCHAR(5) DEFAULT 'en', + + UNIQUE(book, chapter, verse) +); + +-- Vector similarity index +CREATE INDEX ON bible_vectors_kjv + USING ivfflat (embedding vector_cosine_ops); +``` + +**Version Tables:** +- `bible_vectors_kjv` (English) +- `bible_vectors_niv` (English) +- `bible_vectors_esv` (English) +- `bible_vectors_cornilescu` (Romanian) +- `bible_vectors_rvr1960` (Spanish) +- `bible_vectors_nvi_spanish` (Spanish) +- `bible_vectors_nuova_riveduta` (Italian) +- [additional tables for each version] + +#### TR-2: Vector Search Parameters +```typescript +interface VectorSearchParams { + query: string; // User's question (embedded) + languages: string[]; // e.g., ['ro', 'en'] + limit: number; // Top K results (default: 10) + similarityThreshold: number; // Minimum similarity (default: 0.7) + versions?: string[]; // Specific versions to search +} + +interface SearchResult { + book: string; + chapter: number; + verse: number; + text: string; + version: string; + language: string; + similarity: number; // Cosine similarity score +} +``` + +#### TR-3: AI Model Configuration +```typescript +interface AIConfig { + provider: 'openai' | 'anthropic'; + model: string; // e.g., 'gpt-4-turbo' or 'claude-3-5-sonnet' + temperature: number; // 0.3 for factual responses + maxTokens: number; // 1500 for typical responses + systemPrompt: string; // Biblical AI assistant instructions +} +``` + +#### TR-4: Performance Requirements +- Vector search: < 2 seconds +- Full AI response: < 5 seconds +- Concurrent users: Support 100+ +- Embedding cache: 24 hours +- Database connection pool: 10-20 connections + +--- + +## 4. Architecture Overview + +### 4.1 System Components + +``` +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ User Interface โ”‚ +โ”‚ (Chat Component) โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + โ”‚ + โ”‚ POST /api/chat + โ”‚ { message, locale, conversationId } + โ–ผ +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ Chat API Route โ”‚ +โ”‚ 1. Identify user language โ”‚ +โ”‚ 2. Generate embedding for question โ”‚ +โ”‚ 3. Trigger multi-language vector search โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + โ”‚ + โ–ผ +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ Vector Search Service โ”‚ +โ”‚ 1. Search primary language versions โ”‚ +โ”‚ 2. Check result quality/completeness โ”‚ +โ”‚ 3. Fallback to English if needed โ”‚ +โ”‚ 4. Return top results with metadata โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + โ”‚ + โ”‚ Query multiple tables + โ–ผ +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ Vector Database (PostgreSQL) โ”‚ +โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ +โ”‚ โ”‚ bible_vectors_kjvโ”‚ โ”‚bible_vectors_niv โ”‚ [English] โ”‚ +โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ +โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ +โ”‚ โ”‚bible_vectors_ โ”‚ โ”‚bible_vectors_ โ”‚ [Romanian] โ”‚ +โ”‚ โ”‚ cornilescu โ”‚ โ”‚ cornilescu2024 โ”‚ โ”‚ +โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ +โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ +โ”‚ โ”‚bible_vectors_ โ”‚ โ”‚bible_vectors_nvi_โ”‚ [Spanish] โ”‚ +โ”‚ โ”‚ rvr1960 โ”‚ โ”‚ spanish โ”‚ โ”‚ +โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ +โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ +โ”‚ โ”‚bible_vectors_ โ”‚ [Italian] โ”‚ +โ”‚ โ”‚ nuova_riveduta โ”‚ โ”‚ +โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + โ”‚ Return results + โ–ผ +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ AI Context Builder โ”‚ +โ”‚ 1. Format search results into context โ”‚ +โ”‚ 2. Build system prompt with instructions โ”‚ +โ”‚ 3. Include conversation history โ”‚ +โ”‚ 4. Add citation requirements โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + โ”‚ + โ–ผ +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ AI Provider (OpenAI/Anthropic) โ”‚ +โ”‚ Generate comprehensive answer with citations โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + โ”‚ + โ–ผ +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ Response Formatter โ”‚ +โ”‚ 1. Parse citations โ”‚ +โ”‚ 2. Create links to Bible reader โ”‚ +โ”‚ 3. Format markdown โ”‚ +โ”‚ 4. Return to user โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + โ”‚ + โ–ผ + User receives answer +``` + +### 4.2 Data Flow + +**Scenario 1: Romanian User Asks Question** +``` +User (ro): "Ce spune Biblia despre iubire?" (What does the Bible say about love?) + โ†“ +1. Detect language: Romanian (ro) +2. Generate embedding of question +3. Search Romanian Bible versions: + - bible_vectors_cornilescu + - bible_vectors_cornilescu2024 +4. Find top 10 results about love (1 Corinteni 13, Ioan 3:16, etc.) +5. Build AI prompt with Romanian verses +6. AI generates answer in Romanian +7. Response: "Biblia vorbeศ™te mult despre iubire. Cornilescu 1 Corinteni 13:4 + spune: 'Dragostea este รฎndelung rฤƒbdฤƒtoare...' ศ˜i Ioan 3:16..." +``` + +**Scenario 2: Italian User - Incomplete Bible** +``` +User (it): "Chi era Giobbe?" (Who was Job?) + โ†“ +1. Detect language: Italian (it) +2. Generate embedding +3. Search Italian Bible versions: + - bible_vectors_nuova_riveduta +4. Results found: 3 verses (incomplete Book of Job) +5. Confidence score: LOW (0.5 < 0.7 threshold) +6. FALLBACK: Search English versions (KJV, NIV, ESV) +7. Find comprehensive results in English +8. AI translates context to Italian +9. Response: "Giobbe era un uomo giusto... (Job was a righteous man...) + [Da KJV Job 1:1] 'There was a man in the land of Uz, whose name was Job...'" +``` + +--- + +## 5. Database Schema Analysis + +### 5.1 Discovery Tasks + +**TASK 5: Enumerate All Vector Tables** +```sql +-- Query to find all Bible vector tables +SELECT tablename +FROM pg_tables +WHERE tablename LIKE 'bible_vectors_%' +ORDER BY tablename; +``` + +**Expected Output:** +``` +bible_vectors_kjv +bible_vectors_niv +bible_vectors_esv +bible_vectors_cornilescu +bible_vectors_rvr1960 +bible_vectors_nvi_spanish +bible_vectors_nuova_riveduta +[... additional tables] +``` + +**TASK 6: Analyze Table Structure** +```sql +-- Check schema of a sample table +SELECT column_name, data_type, character_maximum_length +FROM information_schema.columns +WHERE table_name = 'bible_vectors_kjv'; + +-- Check indexing +SELECT indexname, indexdef +FROM pg_indexes +WHERE tablename = 'bible_vectors_kjv'; + +-- Check embedding dimensions +SELECT pg_column_size(embedding) / 4 as dimensions +FROM bible_vectors_kjv +LIMIT 1; +``` + +**TASK 7: Create Language-to-Version Mapping** +```sql +-- Create configuration table +CREATE TABLE IF NOT EXISTS bible_version_config ( + id SERIAL PRIMARY KEY, + table_name VARCHAR(100) UNIQUE NOT NULL, + version_name VARCHAR(100) NOT NULL, + version_abbreviation VARCHAR(20) NOT NULL, + language VARCHAR(5) NOT NULL, + is_complete BOOLEAN DEFAULT true, + books_count INTEGER, + verses_count INTEGER, + created_at TIMESTAMP DEFAULT NOW(), + metadata JSONB +); + +-- Insert mappings +INSERT INTO bible_version_config + (table_name, version_name, version_abbreviation, language, is_complete) +VALUES + ('bible_vectors_kjv', 'King James Version', 'KJV', 'en', true), + ('bible_vectors_niv', 'New International Version', 'NIV', 'en', true), + ('bible_vectors_esv', 'English Standard Version', 'ESV', 'en', true), + ('bible_vectors_cornilescu', 'Dumitru Cornilescu 1924', 'Cornilescu', 'ro', true), + ('bible_vectors_rvr1960', 'Reina-Valera 1960', 'RVR1960', 'es', true), + ('bible_vectors_nvi_spanish', 'Nueva Versiรณn Internacional', 'NVI', 'es', true), + ('bible_vectors_nuova_riveduta', 'Nuova Riveduta 2006', 'NR2006', 'it', false); + -- Add all your versions... +``` + +### 5.2 Version Statistics Query + +```sql +-- Get statistics for each version +SELECT + bvc.version_abbreviation, + bvc.language, + bvc.is_complete, + COUNT(DISTINCT bv.book) as books_count, + COUNT(*) as verses_count +FROM bible_version_config bvc +JOIN LATERAL ( + SELECT book FROM {table_name} -- Dynamic table name +) bv ON true +GROUP BY bvc.version_abbreviation, bvc.language, bvc.is_complete +ORDER BY bvc.language, bvc.version_abbreviation; +``` + +--- + +## 6. Implementation Plan + +### Phase 1: Environment & Connection Verification (Day 1) + +#### Step 1.1: Check AI API Credentials + +**File to Check:** `/root/biblical-guide/.env` + +```bash +# Required environment variables +OPENAI_API_KEY=sk-... # OpenAI API key +ANTHROPIC_API_KEY=sk-ant-... # Anthropic API key (if using Claude) + +# Vector Database Connection +VECTOR_DB_URL=postgresql://... # Supabase or PostgreSQL connection +VECTOR_DB_PASSWORD=... # Database password + +# Optional: Embedding API +EMBEDDING_API_KEY=... # If separate from main AI key +``` + +**Verification Script:** +```typescript +// scripts/verify-ai-connection.ts +import OpenAI from 'openai'; + +async function verifyConnections() { + console.log('๐Ÿ” Verifying AI API connections...\n'); + + // 1. Check OpenAI + try { + const openai = new OpenAI({ + apiKey: process.env.OPENAI_API_KEY, + }); + + const response = await openai.chat.completions.create({ + model: 'gpt-3.5-turbo', + messages: [{ role: 'user', content: 'Test' }], + max_tokens: 5, + }); + + console.log('โœ… OpenAI API: Connected'); + console.log(` Model: ${response.model}`); + } catch (error: any) { + console.log('โŒ OpenAI API: Failed'); + console.log(` Error: ${error.message}`); + } + + // 2. Check Vector Database + try { + const { Pool } = await import('pg'); + const pool = new Pool({ + connectionString: process.env.VECTOR_DB_URL, + }); + + const result = await pool.query('SELECT version()'); + console.log('โœ… Vector Database: Connected'); + console.log(` PostgreSQL: ${result.rows[0].version.split(' ')[1]}`); + + // Check for pgvector extension + const extResult = await pool.query( + "SELECT * FROM pg_extension WHERE extname = 'vector'" + ); + + if (extResult.rows.length > 0) { + console.log('โœ… pgvector extension: Installed'); + } else { + console.log('โš ๏ธ pgvector extension: Not found'); + } + + await pool.end(); + } catch (error: any) { + console.log('โŒ Vector Database: Failed'); + console.log(` Error: ${error.message}`); + } + + // 3. List all Bible vector tables + try { + const { Pool } = await import('pg'); + const pool = new Pool({ + connectionString: process.env.VECTOR_DB_URL, + }); + + const tables = await pool.query(` + SELECT tablename + FROM pg_tables + WHERE tablename LIKE 'bible_vectors_%' + ORDER BY tablename + `); + + console.log(`\n๐Ÿ“š Found ${tables.rows.length} Bible version tables:`); + tables.rows.forEach(row => { + console.log(` - ${row.tablename}`); + }); + + await pool.end(); + } catch (error: any) { + console.log('โŒ Table enumeration failed'); + console.log(` Error: ${error.message}`); + } +} + +verifyConnections(); +``` + +**Run verification:** +```bash +npx tsx scripts/verify-ai-connection.ts +``` + +#### Step 1.2: Identify Current Chat Implementation + +**Files to Locate:** +- [ ] `/app/api/chat/route.ts` - Main chat API endpoint +- [ ] `/components/chat/floating-chat.tsx` - Chat UI component +- [ ] `/lib/ai/` - AI utility functions (if exists) +- [ ] `/lib/embeddings/` - Embedding functions (if exists) + +**Analysis Checklist:** +- [ ] What AI provider is currently used? (OpenAI/Anthropic) +- [ ] Is vector search currently implemented? +- [ ] How are embeddings generated? +- [ ] Where is conversation history stored? +- [ ] How are responses formatted? + +--- + +### Phase 2: Vector Search Service Implementation (Day 2-3) + +#### Step 2.1: Create Vector Database Connection + +**File:** `/lib/vector-db/index.ts` + +```typescript +import { Pool } from 'pg'; + +// Singleton pool instance +let pool: Pool | null = null; + +export function getVectorDbPool(): Pool { + if (!pool) { + pool = new Pool({ + connectionString: process.env.VECTOR_DB_URL, + max: 20, + idleTimeoutMillis: 30000, + connectionTimeoutMillis: 2000, + }); + } + return pool; +} + +export async function testConnection(): Promise { + try { + const client = await getVectorDbPool().connect(); + await client.query('SELECT 1'); + client.release(); + return true; + } catch (error) { + console.error('Vector DB connection failed:', error); + return false; + } +} +``` + +#### Step 2.2: Create Bible Version Configuration Service + +**File:** `/lib/vector-db/version-config.ts` + +```typescript +import { getVectorDbPool } from './index'; + +export interface BibleVersionConfig { + tableName: string; + versionName: string; + versionAbbreviation: string; + language: string; + isComplete: boolean; + booksCount?: number; + versesCount?: number; +} + +// In-memory cache (refreshed every 24h) +let versionCache: BibleVersionConfig[] | null = null; +let cacheTimestamp: number = 0; +const CACHE_DURATION = 24 * 60 * 60 * 1000; // 24 hours + +export async function getBibleVersionsByLanguage( + language: string +): Promise { + const now = Date.now(); + + // Return cached data if valid + if (versionCache && (now - cacheTimestamp) < CACHE_DURATION) { + return versionCache.filter(v => v.language === language); + } + + // Fetch from database + const pool = getVectorDbPool(); + const result = await pool.query(` + SELECT + table_name as "tableName", + version_name as "versionName", + version_abbreviation as "versionAbbreviation", + language, + is_complete as "isComplete", + books_count as "booksCount", + verses_count as "versesCount" + FROM bible_version_config + ORDER BY language, version_abbreviation + `); + + versionCache = result.rows; + cacheTimestamp = now; + + return versionCache.filter(v => v.language === language); +} + +export async function getAllVersions(): Promise { + const now = Date.now(); + + if (versionCache && (now - cacheTimestamp) < CACHE_DURATION) { + return versionCache; + } + + const pool = getVectorDbPool(); + const result = await pool.query(` + SELECT + table_name as "tableName", + version_name as "versionName", + version_abbreviation as "versionAbbreviation", + language, + is_complete as "isComplete", + books_count as "booksCount", + verses_count as "versesCount" + FROM bible_version_config + ORDER BY language, version_abbreviation + `); + + versionCache = result.rows; + cacheTimestamp = now; + + return versionCache; +} + +export function clearCache(): void { + versionCache = null; + cacheTimestamp = 0; +} +``` + +#### Step 2.3: Create Embedding Service + +**File:** `/lib/ai/embeddings.ts` + +```typescript +import OpenAI from 'openai'; + +const openai = new OpenAI({ + apiKey: process.env.OPENAI_API_KEY, +}); + +// Embedding cache (simple in-memory cache) +const embeddingCache = new Map(); +const CACHE_MAX_SIZE = 1000; + +export async function generateEmbedding(text: string): Promise { + // Check cache first + const cached = embeddingCache.get(text); + if (cached) { + return cached; + } + + try { + const response = await openai.embeddings.create({ + model: 'text-embedding-ada-002', + input: text, + }); + + const embedding = response.data[0].embedding; + + // Add to cache (with size limit) + if (embeddingCache.size >= CACHE_MAX_SIZE) { + // Remove oldest entry + const firstKey = embeddingCache.keys().next().value; + embeddingCache.delete(firstKey); + } + embeddingCache.set(text, embedding); + + return embedding; + } catch (error) { + console.error('Embedding generation failed:', error); + throw new Error('Failed to generate embedding'); + } +} + +export function clearEmbeddingCache(): void { + embeddingCache.clear(); +} +``` + +#### Step 2.4: Create Multi-Language Vector Search Service + +**File:** `/lib/vector-db/search.ts` + +```typescript +import { getVectorDbPool } from './index'; +import { getBibleVersionsByLanguage } from './version-config'; +import { generateEmbedding } from '../ai/embeddings'; + +export interface VectorSearchResult { + book: string; + chapter: number; + verse: number; + text: string; + version: string; + versionName: string; + language: string; + similarity: number; +} + +export interface VectorSearchOptions { + limit?: number; // Default: 10 + similarityThreshold?: number; // Default: 0.7 + includeMetadata?: boolean; // Default: true +} + +/** + * Search Bible verses across all versions in specified languages + * + * @param query - User's question + * @param languages - Languages to search (e.g., ['ro', 'en']) + * @param options - Search options + * @returns Array of search results sorted by similarity + */ +export async function searchBibleVectors( + query: string, + languages: string[], + options: VectorSearchOptions = {} +): Promise { + const { + limit = 10, + similarityThreshold = 0.7, + } = options; + + console.log(`๐Ÿ” Searching vectors for languages: ${languages.join(', ')}`); + + // 1. Generate embedding for query + const queryEmbedding = await generateEmbedding(query); + const embeddingString = `[${queryEmbedding.join(',')}]`; + + const pool = getVectorDbPool(); + const allResults: VectorSearchResult[] = []; + + // 2. Search each language + for (const language of languages) { + console.log(` Searching ${language} versions...`); + + // Get all versions for this language + const versions = await getBibleVersionsByLanguage(language); + + if (versions.length === 0) { + console.log(` โš ๏ธ No versions found for ${language}`); + continue; + } + + // 3. Search each version table + for (const version of versions) { + try { + // Use parameterized query with UNION for multiple tables + const query = ` + SELECT + book, + chapter, + verse, + text, + version, + 1 - (embedding <=> $1::vector) as similarity + FROM ${version.tableName} + WHERE 1 - (embedding <=> $1::vector) > $2 + ORDER BY embedding <=> $1::vector + LIMIT $3 + `; + + const result = await pool.query(query, [ + embeddingString, + similarityThreshold, + limit, + ]); + + // Add results with version metadata + const versionResults: VectorSearchResult[] = result.rows.map(row => ({ + book: row.book, + chapter: row.chapter, + verse: row.verse, + text: row.text, + version: version.versionAbbreviation, + versionName: version.versionName, + language: language, + similarity: row.similarity, + })); + + allResults.push(...versionResults); + + console.log(` โœ“ ${version.versionAbbreviation}: ${versionResults.length} results`); + } catch (error: any) { + console.error(` โœ— Error searching ${version.tableName}:`, error.message); + } + } + } + + // 4. Sort all results by similarity and limit + allResults.sort((a, b) => b.similarity - a.similarity); + const topResults = allResults.slice(0, limit); + + console.log(`โœ… Total results: ${topResults.length}`); + return topResults; +} + +/** + * Search with fallback logic: + * 1. Search primary language + * 2. If insufficient results, fallback to English + * + * @param query - User's question + * @param primaryLanguage - User's language (e.g., 'ro') + * @param options - Search options + * @returns Search results with fallback indicator + */ +export async function searchWithFallback( + query: string, + primaryLanguage: string, + options: VectorSearchOptions = {} +): Promise<{ + results: VectorSearchResult[]; + usedFallback: boolean; + searchedLanguages: string[]; +}> { + const { limit = 10, similarityThreshold = 0.7 } = options; + + // Search primary language first + const primaryResults = await searchBibleVectors( + query, + [primaryLanguage], + { limit, similarityThreshold } + ); + + // Check if we need fallback + const needsFallback = ( + primaryResults.length === 0 || + primaryResults.length < 3 || + (primaryResults[0]?.similarity || 0) < 0.75 + ); + + if (!needsFallback || primaryLanguage === 'en') { + return { + results: primaryResults, + usedFallback: false, + searchedLanguages: [primaryLanguage], + }; + } + + // Fallback to English + console.log('โš ๏ธ Insufficient results, falling back to English...'); + const englishResults = await searchBibleVectors( + query, + ['en'], + { limit, similarityThreshold } + ); + + // Combine results (prioritize primary language) + const combinedResults = [...primaryResults, ...englishResults] + .sort((a, b) => b.similarity - a.similarity) + .slice(0, limit); + + return { + results: combinedResults, + usedFallback: true, + searchedLanguages: [primaryLanguage, 'en'], + }; +} +``` + +--- + +### Phase 3: AI Chat Integration (Day 4-5) + +#### Step 3.1: Create AI Response Generator + +**File:** `/lib/ai/chat.ts` + +```typescript +import OpenAI from 'openai'; +import { VectorSearchResult } from '../vector-db/search'; + +const openai = new OpenAI({ + apiKey: process.env.OPENAI_API_KEY, +}); + +export interface ChatMessage { + role: 'user' | 'assistant' | 'system'; + content: string; +} + +export interface GenerateResponseOptions { + searchResults: VectorSearchResult[]; + userQuestion: string; + userLanguage: string; + conversationHistory?: ChatMessage[]; + usedFallback: boolean; +} + +/** + * Build system prompt for Biblical AI assistant + */ +function buildSystemPrompt(language: string, usedFallback: boolean): string { + const prompts = { + en: `You are a knowledgeable Biblical AI assistant. Your role is to provide accurate, +thoughtful answers based on Scripture. Always cite Bible verses with their version, book, +chapter, and verse. Provide context and explain the meaning clearly. + +${usedFallback ? 'Note: Some verses are from English versions as complete translations in the user\'s language were not available.' : ''} + +Format your citations as: [Version] Book Chapter:Verse +Example: [KJV] John 3:16 or [Cornilescu] Ioan 3:16`, + + ro: `Eศ™ti un asistent AI biblic priceput. Rolul tฤƒu este sฤƒ oferi rฤƒspunsuri precise ศ™i +gรขndite bazate pe Scripturฤƒ. Citeazฤƒ รฎntotdeauna versetele biblice cu versiunea, cartea, +capitolul ศ™i versetul. Oferฤƒ context ศ™i explicฤƒ semnificaศ›ia clar. + +${usedFallback ? 'Notฤƒ: Unele versete sunt din versiuni engleze deoarece traducerile complete รฎn romรขnฤƒ nu erau disponibile.' : ''} + +Formateazฤƒ citฤƒrile astfel: [Versiune] Carte Capitol:Verset +Exemplu: [Cornilescu] Ioan 3:16`, + + es: `Eres un asistente bรญblico de IA conocedor. Tu funciรณn es proporcionar respuestas +precisas y reflexivas basadas en las Escrituras. Siempre cita los versรญculos bรญblicos con +su versiรณn, libro, capรญtulo y versรญculo. Proporciona contexto y explica el significado claramente. + +${usedFallback ? 'Nota: Algunos versรญculos son de versiones en inglรฉs ya que no habรญa traducciones completas disponibles en espaรฑol.' : ''} + +Formatea tus citas como: [Versiรณn] Libro Capรญtulo:Versรญculo +Ejemplo: [RVR1960] Juan 3:16`, + + it: `Sei un assistente biblico AI esperto. Il tuo ruolo รจ fornire risposte accurate e +ponderate basate sulle Scritture. Cita sempre i versetti biblici con la loro versione, libro, +capitolo e versetto. Fornisci contesto e spiega il significato chiaramente. + +${usedFallback ? 'Nota: Alcuni versetti provengono da versioni inglesi poichรฉ traduzioni complete in italiano non erano disponibili.' : ''} + +Formatta le tue citazioni come: [Versione] Libro Capitolo:Versetto +Esempio: [NR2006] Giovanni 3:16`, + }; + + return prompts[language as keyof typeof prompts] || prompts.en; +} + +/** + * Format search results into context for AI + */ +function formatSearchResultsContext(results: VectorSearchResult[]): string { + if (results.length === 0) { + return 'No specific Bible verses were found for this question.'; + } + + let context = 'Relevant Bible verses:\n\n'; + + results.forEach((result, index) => { + context += `${index + 1}. [${result.version}] ${result.book} ${result.chapter}:${result.verse}\n`; + context += ` "${result.text}"\n`; + context += ` (Similarity: ${(result.similarity * 100).toFixed(1)}%)\n\n`; + }); + + return context; +} + +/** + * Generate AI response based on vector search results + */ +export async function generateBiblicalResponse( + options: GenerateResponseOptions +): Promise { + const { + searchResults, + userQuestion, + userLanguage, + conversationHistory = [], + usedFallback, + } = options; + + // Build messages array + const messages: ChatMessage[] = [ + { + role: 'system', + content: buildSystemPrompt(userLanguage, usedFallback), + }, + { + role: 'system', + content: formatSearchResultsContext(searchResults), + }, + ...conversationHistory.slice(-6), // Include last 3 exchanges for context + { + role: 'user', + content: userQuestion, + }, + ]; + + try { + const response = await openai.chat.completions.create({ + model: 'gpt-4-turbo-preview', + messages: messages as any, + temperature: 0.3, // Low temperature for factual responses + max_tokens: 1500, + presence_penalty: 0.1, + frequency_penalty: 0.1, + }); + + const answer = response.choices[0]?.message?.content || + 'I apologize, but I could not generate a response.'; + + return answer; + } catch (error: any) { + console.error('AI response generation failed:', error); + throw new Error(`Failed to generate response: ${error.message}`); + } +} +``` + +#### Step 3.2: Update Chat API Route + +**File:** `/app/api/chat/route.ts` + +```typescript +import { NextRequest, NextResponse } from 'next/server'; +import { getUserFromToken } from '@/lib/auth'; +import { searchWithFallback } from '@/lib/vector-db/search'; +import { generateBiblicalResponse } from '@/lib/ai/chat'; +import { prisma } from '@/lib/db'; + +export async function POST(request: NextRequest) { + try { + const { message, locale, conversationId } = await request.json(); + + // Validate input + if (!message || !message.trim()) { + return NextResponse.json( + { error: 'Message is required' }, + { status: 400 } + ); + } + + // Get user (optional) + const token = request.headers.get('authorization')?.replace('Bearer ', ''); + const user = token ? await getUserFromToken(token) : null; + + // Determine language (default to 'en' if not provided) + const userLanguage = locale || 'en'; + + console.log(`๐Ÿ’ฌ Chat request: "${message.substring(0, 50)}..." [${userLanguage}]`); + + // STEP 1: Vector search with fallback + const searchStartTime = Date.now(); + const { results, usedFallback, searchedLanguages } = await searchWithFallback( + message, + userLanguage, + { + limit: 10, + similarityThreshold: 0.7, + } + ); + const searchDuration = Date.now() - searchStartTime; + + console.log(`๐Ÿ” Vector search completed in ${searchDuration}ms`); + console.log(` Results: ${results.length}`); + console.log(` Used fallback: ${usedFallback}`); + console.log(` Searched languages: ${searchedLanguages.join(', ')}`); + + // STEP 2: Get conversation history (if conversationId provided) + let conversationHistory: any[] = []; + if (conversationId && user) { + const conversation = await prisma.conversation.findUnique({ + where: { id: conversationId, userId: user.id }, + include: { + messages: { + orderBy: { createdAt: 'asc' }, + take: 10, // Last 5 exchanges + }, + }, + }); + + if (conversation) { + conversationHistory = conversation.messages.map(msg => ({ + role: msg.role, + content: msg.content, + })); + } + } + + // STEP 3: Generate AI response + const aiStartTime = Date.now(); + const response = await generateBiblicalResponse({ + searchResults: results, + userQuestion: message, + userLanguage, + conversationHistory, + usedFallback, + }); + const aiDuration = Date.now() - aiStartTime; + + console.log(`๐Ÿค– AI response generated in ${aiDuration}ms`); + + // STEP 4: Save conversation (if user is logged in) + if (user) { + let conversation; + + if (conversationId) { + // Add to existing conversation + conversation = await prisma.conversation.findUnique({ + where: { id: conversationId, userId: user.id }, + }); + } + + if (!conversation) { + // Create new conversation + conversation = await prisma.conversation.create({ + data: { + userId: user.id, + title: message.substring(0, 100), // Use first message as title + }, + }); + } + + // Save user message + await prisma.message.create({ + data: { + conversationId: conversation.id, + role: 'user', + content: message, + }, + }); + + // Save AI response + await prisma.message.create({ + data: { + conversationId: conversation.id, + role: 'assistant', + content: response, + metadata: { + searchResults: results.slice(0, 5), // Top 5 results + usedFallback, + searchDuration, + aiDuration, + }, + }, + }); + + conversationId = conversation.id; + } + + // STEP 5: Return response + return NextResponse.json({ + response, + conversationId, + metadata: { + searchResults: results.slice(0, 5), + usedFallback, + searchedLanguages, + timings: { + search: searchDuration, + ai: aiDuration, + total: searchDuration + aiDuration, + }, + }, + }); + + } catch (error: any) { + console.error('Chat API error:', error); + return NextResponse.json( + { error: error.message || 'Failed to process chat request' }, + { status: 500 } + ); + } +} + +export const runtime = 'nodejs'; +export const dynamic = 'force-dynamic'; +``` + +--- + +### Phase 4: Testing & Validation (Day 6-7) + +#### Step 4.1: Create Test Suite + +**File:** `/scripts/test-vector-search.ts` + +```typescript +import { searchWithFallback } from '@/lib/vector-db/search'; + +interface TestCase { + question: string; + language: string; + expectedBook?: string; + expectedMinResults: number; +} + +const testCases: TestCase[] = [ + // English tests + { + question: 'What does the Bible say about love?', + language: 'en', + expectedBook: '1 Corinthians', + expectedMinResults: 5, + }, + { + question: 'Who was Jesus?', + language: 'en', + expectedBook: 'John', + expectedMinResults: 5, + }, + + // Romanian tests + { + question: 'Ce spune Biblia despre iubire?', + language: 'ro', + expectedBook: '1 Corinteni', + expectedMinResults: 3, + }, + { + question: 'Cine a fost Moise?', + language: 'ro', + expectedBook: 'Exod', + expectedMinResults: 3, + }, + + // Spanish tests + { + question: 'ยฟQuรฉ dice la Biblia sobre la fe?', + language: 'es', + expectedBook: 'Hebreos', + expectedMinResults: 3, + }, + + // Italian tests + { + question: 'Chi era Davide?', + language: 'it', + expectedBook: '1 Samuele', + expectedMinResults: 2, + }, + + // Fallback test (incomplete Italian version) + { + question: 'Tell me about Job', // Asking in English but with Italian locale + language: 'it', + expectedMinResults: 2, // Should fallback to English + }, +]; + +async function runTests() { + console.log('๐Ÿงช Starting Vector Search Tests\n'); + + let passedTests = 0; + let failedTests = 0; + + for (const [index, testCase] of testCases.entries()) { + console.log(`Test ${index + 1}/${testCases.length}: ${testCase.question} [${testCase.language}]`); + + try { + const startTime = Date.now(); + const { results, usedFallback, searchedLanguages } = await searchWithFallback( + testCase.question, + testCase.language, + { limit: 10, similarityThreshold: 0.7 } + ); + const duration = Date.now() - startTime; + + // Check results count + const hasEnoughResults = results.length >= testCase.expectedMinResults; + + // Check if expected book is in results (if specified) + const hasExpectedBook = testCase.expectedBook + ? results.some(r => r.book.includes(testCase.expectedBook!)) + : true; + + if (hasEnoughResults && hasExpectedBook) { + console.log(` โœ… PASSED (${duration}ms)`); + console.log(` Found ${results.length} results`); + console.log(` Top result: [${results[0]?.version}] ${results[0]?.book} ${results[0]?.chapter}:${results[0]?.verse}`); + console.log(` Similarity: ${(results[0]?.similarity * 100).toFixed(1)}%`); + console.log(` Used fallback: ${usedFallback}`); + console.log(` Languages: ${searchedLanguages.join(', ')}\n`); + passedTests++; + } else { + console.log(` โŒ FAILED`); + console.log(` Expected min results: ${testCase.expectedMinResults}, got: ${results.length}`); + if (testCase.expectedBook) { + console.log(` Expected book: ${testCase.expectedBook}, found: ${hasExpectedBook}`); + } + console.log(''); + failedTests++; + } + } catch (error: any) { + console.log(` โŒ ERROR: ${error.message}\n`); + failedTests++; + } + } + + console.log(`\n๐Ÿ“Š Test Summary:`); + console.log(` โœ… Passed: ${passedTests}`); + console.log(` โŒ Failed: ${failedTests}`); + console.log(` Total: ${testCases.length}`); + console.log(` Success Rate: ${((passedTests / testCases.length) * 100).toFixed(1)}%`); +} + +runTests().catch(console.error); +``` + +**Run tests:** +```bash +npx tsx scripts/test-vector-search.ts +``` + +--- + +## 7. Vector Search Logic + +### 7.1 Search Priority Algorithm + +```typescript +/** + * Multi-Language Search Algorithm + * + * Priority Order: + * 1. Primary Language Complete Versions (is_complete = true) + * 2. Primary Language Partial Versions (is_complete = false) + * 3. English Complete Versions (fallback) + * + * Quality Checks: + * - Minimum results: 3 + * - Minimum similarity: 0.7 + * - Top result similarity: 0.75 (for confidence) + */ + +// Pseudocode +function searchMultiLanguage(query, primaryLanguage) { + // Step 1: Search primary language + primaryResults = searchLanguage(query, primaryLanguage) + + // Step 2: Quality check + if (hasGoodQuality(primaryResults)) { + return { + results: primaryResults, + usedFallback: false + } + } + + // Step 3: Fallback to English + if (primaryLanguage !== 'en') { + englishResults = searchLanguage(query, 'en') + combinedResults = merge(primaryResults, englishResults) + + return { + results: combinedResults, + usedFallback: true + } + } + + // Step 4: Return whatever we have + return { + results: primaryResults, + usedFallback: false + } +} + +function hasGoodQuality(results) { + return ( + results.length >= 3 && + results[0].similarity >= 0.75 + ) +} +``` + +### 7.2 Similarity Scoring + +**Cosine Similarity Interpretation:** +``` +1.0 = Perfect match (identical) +0.9-1.0 = Extremely relevant +0.8-0.9 = Highly relevant +0.7-0.8 = Relevant (threshold) +0.6-0.7 = Somewhat relevant +< 0.6 = Not relevant (filtered out) +``` + +**Threshold Configuration:** +```typescript +const SIMILARITY_THRESHOLDS = { + minimum: 0.7, // Filter out results below this + confident: 0.75, // Consider search "confident" if top result above this + excellent: 0.85, // Exceptional match +}; +``` + +--- + +## 8. API Integration + +### 8.1 Frontend Chat Component Updates + +**File:** `/components/chat/floating-chat.tsx` + +**Add to existing component:** + +```typescript +// Add loading state for vector search +const [isSearching, setIsSearching] = useState(false); + +// Update sendMessage function +const sendMessage = async () => { + if (!inputMessage.trim()) return; + + const userMessage = inputMessage.trim(); + setInputMessage(''); + + // Add user message to UI + setMessages(prev => [...prev, { + role: 'user', + content: userMessage, + }]); + + setIsSearching(true); // Show "searching Bible..." indicator + + try { + const token = getToken(); + const response = await fetch('/api/chat', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + ...(token && { Authorization: `Bearer ${token}` }), + }, + body: JSON.stringify({ + message: userMessage, + locale: locale, + conversationId: currentConversationId, + }), + }); + + const data = await response.json(); + + if (!response.ok) { + throw new Error(data.error || 'Failed to get response'); + } + + // Add AI response to UI + setMessages(prev => [...prev, { + role: 'assistant', + content: data.response, + metadata: data.metadata, // Includes search results, timings + }]); + + // Update conversation ID + if (data.conversationId) { + setCurrentConversationId(data.conversationId); + } + + } catch (error: any) { + console.error('Chat error:', error); + setMessages(prev => [...prev, { + role: 'assistant', + content: 'I apologize, but I encountered an error. Please try again.', + }]); + } finally { + setIsSearching(false); + } +}; +``` + +**Add search indicator:** + +```tsx +{isSearching && ( + + + + Searching Bible verses... + + +)} +``` + +--- + +## 9. Testing Strategy + +### 9.1 Test Scenarios + +**Scenario 1: English Question** +``` +Input: "What does the Bible say about faith?" +Language: en +Expected: + - Search: bible_vectors_kjv, bible_vectors_niv, bible_vectors_esv + - Results: Hebrews 11:1, Romans 10:17, Ephesians 2:8-9 + - Citations: [KJV] Hebrews 11:1, [NIV] Hebrews 11:1 + - Fallback: No +``` + +**Scenario 2: Romanian Question** +``` +Input: "Ce spune Biblia despre credinศ›ฤƒ?" +Language: ro +Expected: + - Search: bible_vectors_cornilescu + - Results: Evrei 11:1, Romani 10:17 + - Citations: [Cornilescu] Evrei 11:1 + - Fallback: No (if Romanian complete) +``` + +**Scenario 3: Italian with Fallback** +``` +Input: "Chi era Giobbe?" +Language: it +Expected: + - Search: bible_vectors_nuova_riveduta (incomplete) + - Results: Limited results + - Fallback: Yes (search English versions) + - Citations: [KJV] Job 1:1, [NIV] Job 1:1 + - Response: Italian with English verse references +``` + +**Scenario 4: Obscure Topic** +``` +Input: "Tell me about the Nephilim" +Language: en +Expected: + - Search: All English versions + - Results: Genesis 6:4, Numbers 13:33 + - Citations: Multiple versions showing different translations + - Context: Explanation of who Nephilim were +``` + +### 9.2 Performance Benchmarks + +**Target Metrics:** +``` +Vector Search: < 2000ms +AI Generation: < 3000ms +Total Response Time: < 5000ms +Concurrent Users: 100+ +Success Rate: > 95% +``` + +**Load Testing:** +```bash +# Use Apache Bench or similar +ab -n 100 -c 10 -H "Content-Type: application/json" \ + -p test-request.json \ + http://localhost:3010/api/chat +``` + +--- + +## 10. Deployment & Monitoring + +### 10.1 Pre-Deployment Checklist + +- [ ] All vector tables verified and populated +- [ ] bible_version_config table populated correctly +- [ ] Environment variables set (OPENAI_API_KEY, VECTOR_DB_URL) +- [ ] Database connection pool configured (max: 20) +- [ ] Vector search tested for all languages +- [ ] Fallback logic tested +- [ ] AI response quality reviewed +- [ ] Performance benchmarks met +- [ ] Error handling tested +- [ ] Logging configured + +### 10.2 Monitoring Setup + +**Metrics to Track:** +1. **Search Performance** + - Vector search duration + - AI generation duration + - Total response time + - Cache hit rate + +2. **Quality Metrics** + - Average similarity score + - Fallback frequency per language + - Results count distribution + - User satisfaction (if tracked) + +3. **Error Rates** + - Vector DB connection failures + - AI API errors + - Embedding generation failures + - Timeout errors + +**Logging Example:** +```typescript +// Add to chat API route +console.log({ + timestamp: new Date().toISOString(), + userId: user?.id || 'anonymous', + language: userLanguage, + questionLength: message.length, + searchDuration, + aiDuration, + totalDuration: searchDuration + aiDuration, + resultsCount: results.length, + topSimilarity: results[0]?.similarity, + usedFallback, + searchedLanguages, +}); +``` + +### 10.3 Optimization Opportunities + +**Future Enhancements:** +1. **Caching Layer** + - Cache common questions/embeddings (Redis) + - Cache Bible version configs (in-memory) + - Cache top searches by language + +2. **Advanced Search** + - Semantic search refinement + - Cross-reference discovery + - Topic clustering + - Historical context integration + +3. **Personalization** + - User's preferred Bible version + - Reading history integration + - Personalized recommendations + +4. **Analytics** + - Popular questions tracking + - Language usage statistics + - Conversion tracking (chat โ†’ Bible reader) + +--- + +## Implementation Checklist + +### Phase 1: Setup (Day 1) +- [ ] Run connection verification script +- [ ] Enumerate all vector tables +- [ ] Create bible_version_config table +- [ ] Populate version mappings +- [ ] Test vector DB connections + +### Phase 2: Vector Search (Day 2-3) +- [ ] Create vector DB connection pool +- [ ] Implement version config service +- [ ] Build embedding service with cache +- [ ] Create multi-language search function +- [ ] Implement fallback logic +- [ ] Write unit tests for search + +### Phase 3: AI Integration (Day 4-5) +- [ ] Build system prompt generator +- [ ] Create response formatter +- [ ] Update chat API route +- [ ] Integrate vector search +- [ ] Add conversation persistence +- [ ] Test end-to-end flow + +### Phase 4: Testing (Day 6-7) +- [ ] Run automated test suite +- [ ] Test all 4 languages +- [ ] Test fallback scenarios +- [ ] Performance testing +- [ ] Quality review +- [ ] User acceptance testing + +### Phase 5: Deployment (Day 8) +- [ ] Deploy to production +- [ ] Monitor logs +- [ ] Track performance metrics +- [ ] Gather user feedback +- [ ] Document issues/improvements + +--- + +## Appendix + +### A. SQL Queries Reference + +**Create Version Config Table:** +```sql +CREATE TABLE bible_version_config ( + id SERIAL PRIMARY KEY, + table_name VARCHAR(100) UNIQUE NOT NULL, + version_name VARCHAR(100) NOT NULL, + version_abbreviation VARCHAR(20) NOT NULL, + language VARCHAR(5) NOT NULL, + is_complete BOOLEAN DEFAULT true, + books_count INTEGER, + verses_count INTEGER, + created_at TIMESTAMP DEFAULT NOW(), + metadata JSONB +); + +CREATE INDEX idx_version_language ON bible_version_config(language); +CREATE INDEX idx_version_table ON bible_version_config(table_name); +``` + +**Count Verses Per Version:** +```sql +-- Replace {table_name} with actual table +SELECT + '{version_abbreviation}' as version, + COUNT(*) as total_verses, + COUNT(DISTINCT book) as total_books +FROM {table_name}; +``` + +**Find Missing Books:** +```sql +-- Check which books are missing in a version +WITH all_books AS ( + SELECT DISTINCT book FROM bible_vectors_kjv -- Use complete English version as reference +) +SELECT ab.book +FROM all_books ab +LEFT JOIN bible_vectors_nuova_riveduta nr ON ab.book = nr.book +WHERE nr.book IS NULL; +``` + +### B. Environment Variables + +```bash +# AI API Keys +OPENAI_API_KEY=sk-proj-... +ANTHROPIC_API_KEY=sk-ant-... # Optional + +# Vector Database +VECTOR_DB_URL=postgresql://user:password@host:5432/database +VECTOR_DB_PASSWORD=... # If separate + +# Application +NEXT_PUBLIC_APP_URL=https://biblical-guide.com +NODE_ENV=production + +# Optional: Caching +REDIS_URL=redis://... # For future caching layer +``` + +### C. Troubleshooting Guide + +**Issue: Vector search returns no results** +``` +Possible causes: +1. Embedding dimension mismatch +2. Similarity threshold too high +3. Table name incorrect +4. pgvector extension not installed + +Debug: +- Check embedding dimensions: SELECT pg_column_size(embedding) / 4 FROM table LIMIT 1; +- Lower threshold: Try 0.5 instead of 0.7 +- Verify table exists: SELECT * FROM pg_tables WHERE tablename = 'bible_vectors_kjv'; +- Check extension: SELECT * FROM pg_extension WHERE extname = 'vector'; +``` + +**Issue: AI responses are not in user's language** +``` +Possible causes: +1. System prompt not specifying language +2. Locale not passed correctly +3. Fallback message not translated + +Debug: +- Check locale parameter in API request +- Verify system prompt includes language instruction +- Review response generation function +``` + +**Issue: Slow vector search (> 5 seconds)** +``` +Possible causes: +1. Missing vector index +2. Too many tables searched +3. Large result limit +4. Database connection pool exhausted + +Solutions: +- Create index: CREATE INDEX ON table USING ivfflat (embedding vector_cosine_ops); +- Limit tables searched (only user's language first) +- Reduce limit from 20 to 10 +- Increase connection pool size +``` + +--- + +## Next Steps + +1. **Immediate:** Run Phase 1 verification scripts +2. **Day 2-3:** Implement vector search service +3. **Day 4-5:** Integrate into chat API +4. **Day 6-7:** Comprehensive testing +5. **Day 8:** Production deployment + +**Questions to Answer Before Starting:** +1. What is your vector database provider? (Supabase, PostgreSQL+pgvector, Pinecone, etc.) +2. Are all embeddings using OpenAI's ada-002 model (1536 dimensions)? +3. Do you have a complete list of all Bible version table names? +4. Which AI model do you prefer? (GPT-4, Claude, etc.) + +--- + +**Document End** + +This plan will be updated as implementation progresses. \ No newline at end of file diff --git a/AI_CHAT_STATUS_UPDATE.md b/AI_CHAT_STATUS_UPDATE.md new file mode 100644 index 0000000..2e6b20f --- /dev/null +++ b/AI_CHAT_STATUS_UPDATE.md @@ -0,0 +1,287 @@ +# AI Chat System - Status Update + +**Date:** 2025-10-10 +**Status:** โœ… Azure OpenAI Fixed | โš ๏ธ Need New Vector Tables + +--- + +## ๐ŸŽ‰ GOOD NEWS: Azure OpenAI is Working! + +### โœ… What We Fixed + +Both Azure OpenAI APIs are now **fully operational**: + +| API | Status | Details | +|-----|--------|---------| +| **Chat API** | โœ… WORKING | GPT-4o responding correctly | +| **Embedding API** | โœ… WORKING | text-embedding-ada-002 generating 1536-dim vectors | + +**Updated Configuration:** +```bash +AZURE_OPENAI_ENDPOINT=https://footprints-ai.openai.azure.com +AZURE_OPENAI_KEY=42702a67a41547919877a2ab8e4837f9 + +# Chat +AZURE_OPENAI_DEPLOYMENT=gpt-4o +AZURE_OPENAI_API_VERSION=2025-01-01-preview + +# Embeddings +AZURE_OPENAI_EMBED_DEPLOYMENT=Text-Embedding-ada-002-V2 +AZURE_OPENAI_EMBED_API_VERSION=2023-05-15 +EMBED_DIMS=1536 +``` + +--- + +## โš ๏ธ CRITICAL ISSUE: Embedding Dimension Mismatch + +### The Problem + +- **Existing 116 vector tables:** 4096-dimensional embeddings +- **Our embedding model (ada-002):** 1536-dimensional embeddings +- **Result:** **Cannot use existing tables** โŒ + +### What This Means + +The 116 Bible versions currently in the database were created with a **different embedding model** (likely text-embedding-3-large with 4096 dims). We cannot search them with our 1536-dim embeddings because the dimensions must match exactly. + +### The Solution + +Create **new vector tables** for your priority languages with **1536-dim embeddings**: + +1. โœ… **English** - Use existing Bible data (KJV, ASV, etc.) +2. โŒ **Romanian** - Need Bible source data +3. โŒ **Spanish** - Need Bible source data +4. โŒ **Italian** - Need Bible source data + +--- + +## ๐Ÿ“‹ What We Need To Do Next + +### Option 1: Create New 1536-Dim Tables (RECOMMENDED) + +**Pros:** +- โœ… Works with our current Azure setup +- โœ… Lower cost (ada-002 is cheaper than 3-large) +- โœ… Faster searches (smaller vectors) +- โœ… Sufficient quality for Bible search + +**Steps:** +1. Find/prepare Bible source data for each language +2. Generate 1536-dim embeddings using our ada-002 deployment +3. Create new tables: `bv_1536_ro_cornilescu`, `bv_1536_es_rvr1960`, etc. +4. Import embeddings into new tables +5. Update search logic to use new tables + +### Option 2: Use Different Embedding Model (Not Recommended) + +Deploy text-embedding-3-large (4096-dim) to match existing tables. + +**Cons:** +- โŒ Higher cost +- โŒ Slower searches +- โŒ Requires Azure deployment changes +- โŒ Still missing Romanian/Spanish/Italian in existing tables + +--- + +## ๐Ÿ—‚๏ธ Bible Source Data Status + +### What We Have + +โœ… **Romanian (Fidela):** `/bibles/Biblia-Fidela-limba-romana.md` +- Ready to process! +- Can generate embeddings immediately + +### What We Need + +โŒ **Romanian (Cornilescu):** Most popular Romanian version +- Need to source this Bible translation +- Options: Bible Gateway API, online sources, existing files + +โŒ **Spanish (RVR1960):** Most popular Spanish version +- Reina-Valera 1960 +- Need to source + +โŒ **Italian (Nuova Diodati):** Popular Italian version +- Need to source + +โŒ **English versions:** KJV, ASV, NIV, etc. +- Can source from Bible Gateway, bible.org, or similar + +--- + +## ๐Ÿš€ Recommended Next Steps + +### Immediate (Today) + +1. **Test the chat system** with a simple fallback: + - Temporarily disable vector search + - Have chat work without Bible verse context + - Verify end-to-end flow is working + +2. **Process Romanian Fidela Bible:** + - Read `/bibles/Biblia-Fidela-limba-romana.md` + - Parse into verse-by-verse format + - Generate embeddings using ada-002 + - Create table `ai_bible.bv_1536_ro_fidela` + - Import data + +### Short-term (This Week) + +3. **Source English Bible data:** + - Download KJV (public domain) + - Parse and generate embeddings + - Create table `ai_bible.bv_1536_en_kjv` + +4. **Source Romanian Cornilescu:** + - Find public domain source + - Parse and generate embeddings + - Create table `ai_bible.bv_1536_ro_cornilescu` + +5. **Source Spanish RVR1960:** + - Find public domain source + - Parse and generate embeddings + - Create table `ai_bible.bv_1536_es_rvr1960` + +6. **Source Italian Nuova Diodati:** + - Find source + - Parse and generate embeddings + - Create table `ai_bible.bv_1536_it_nuovadiodati` + +### Medium-term (Next 2 Weeks) + +7. **Implement English Fallback Logic:** + - Search primary language first + - Fall back to English if results are poor + - Add language indicators in citations + +8. **Create Version Metadata Table:** + - Track which versions are available + - Map versions to languages + - Enable smart version selection + +9. **Testing & Optimization:** + - Test all 4 languages + - Optimize query performance + - Add monitoring + +--- + +## ๐Ÿ“Š Database Schema for New Tables + +### Table Naming Convention + +``` +ai_bible.bv_1536_{language}_{version} + +Examples: +- ai_bible.bv_1536_en_kjv +- ai_bible.bv_1536_ro_fidela +- ai_bible.bv_1536_ro_cornilescu +- ai_bible.bv_1536_es_rvr1960 +- ai_bible.bv_1536_it_nuovadiodati +``` + +### Table Structure + +```sql +CREATE TABLE ai_bible.bv_1536_ro_fidela ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + testament TEXT NOT NULL, -- 'OT' or 'NT' + book TEXT NOT NULL, + chapter INTEGER NOT NULL, + verse INTEGER NOT NULL, + language TEXT NOT NULL, -- 'ro' + translation TEXT NOT NULL, -- 'FIDELA' + ref TEXT NOT NULL, -- 'Genesis 1:1' + text_raw TEXT NOT NULL, -- Original verse text + text_norm TEXT, -- Normalized for search + tsv TSVECTOR, -- Full-text search index + embedding VECTOR(1536), -- 1536-dimensional embedding + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- Create indexes +CREATE INDEX idx_bv_1536_ro_fidela_ref ON ai_bible.bv_1536_ro_fidela(ref); +CREATE INDEX idx_bv_1536_ro_fidela_book_chapter ON ai_bible.bv_1536_ro_fidela(book, chapter); +CREATE INDEX idx_bv_1536_ro_fidela_tsv ON ai_bible.bv_1536_ro_fidela USING gin(tsv); +CREATE INDEX idx_bv_1536_ro_fidela_embedding ON ai_bible.bv_1536_ro_fidela + USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100); +``` + +--- + +## ๐Ÿ› ๏ธ Implementation Script Needed + +We need a script to: + +1. **Parse Bible source file** (Markdown, JSON, CSV, etc.) +2. **Generate embeddings** for each verse +3. **Create table** if not exists +4. **Insert verses** with embeddings +5. **Create indexes** + +**Example workflow:** +```bash +# Process Romanian Fidela Bible +npx tsx scripts/import-bible.ts \ + --source ./bibles/Biblia-Fidela-limba-romana.md \ + --language ro \ + --translation FIDELA \ + --table bv_1536_ro_fidela +``` + +--- + +## ๐Ÿ’ก Quick Test - Chat Without Vector Search + +To verify the chat system works end-to-end, we can temporarily: + +1. Modify chat API to skip vector search +2. Test chat with general biblical knowledge (GPT-4o has Bible knowledge) +3. Verify authentication, conversation saving, and UI work +4. Then add vector search back once tables are ready + +**Would you like me to:** +- โ“ Test chat without vector search first? +- โ“ Start processing the Romanian Fidela Bible? +- โ“ Create the Bible import script? +- โ“ Something else? + +--- + +## ๐Ÿ“„ Files Updated + +| File | Status | Purpose | +|------|--------|---------| +| `.env.local` | โœ… Updated | New Azure credentials, 1536 dims | +| `lib/vector-search.ts` | โœ… Updated | Support separate embed API version | +| `scripts/test-azure-quick.ts` | โœ… Created | Quick API testing | +| `AI_CHAT_STATUS_UPDATE.md` | โœ… Created | This document | + +--- + +## โœ… Summary + +**What's Working:** +- โœ… Azure OpenAI Chat (GPT-4o) +- โœ… Azure OpenAI Embeddings (ada-002, 1536-dim) +- โœ… Database connection +- โœ… pgvector extension +- โœ… Search code (just needs right tables) + +**What's Blocked:** +- โŒ Cannot use existing 116 tables (4096-dim vs 1536-dim mismatch) +- โŒ Need new vector tables for Romanian/Spanish/Italian/English +- โŒ Need Bible source data for Spanish and Italian + +**Next Decision Point:** +Choose what to do next: +1. Test chat system without vector search (quick validation) +2. Start creating vector tables with Fidela Romanian Bible (first language) +3. Source and process English KJV (for fallback) +4. All of the above in parallel + +**Your call!** ๐Ÿš€ diff --git a/AI_CHAT_VERIFICATION_FINDINGS.md b/AI_CHAT_VERIFICATION_FINDINGS.md new file mode 100644 index 0000000..632169b --- /dev/null +++ b/AI_CHAT_VERIFICATION_FINDINGS.md @@ -0,0 +1,334 @@ +# AI Chat System Verification Findings + +**Date:** 2025-10-10 +**Status:** ๐ŸŸก Partially Operational - Configuration Issue Found + +## Executive Summary + +The AI chat vector database is **fully operational** with 116 Bible versions across 47 languages, all with complete embeddings. However, there is a **critical configuration issue** with the Azure OpenAI API deployments that prevents the chat from functioning. + +--- + +## โœ… What's Working + +### 1. Vector Database Infrastructure (100% Operational) +- **Database Connection:** PostgreSQL 17.5 โœ“ +- **pgvector Extension:** v0.8.0 installed โœ“ +- **Schema:** `ai_bible` schema exists โœ“ + +### 2. Bible Vector Tables (116 Tables - Fully Populated) + +| Metric | Value | +|--------|-------| +| Total Vector Tables | **116** | +| Languages Supported | **47** | +| Embedding Coverage | **100%** for all tables | +| Table Structure | Correct (all have embedding, tsv, ref, text_raw, etc.) | + +**Sample Table Statistics:** +- `bv_ab_aau`: 7,923 verses (100% embedded) +- `bv_ac_aca`: 4,406 verses (100% embedded) +- `bv_ac_acr_acc`: 7,930 verses (100% embedded) + +### 3. Languages Available + +The system currently supports **47 languages** including: +- **English (en):** 9 versions (ASV, Brenton, KJV, KJV2006, LXX2012, RV, T4T, UK_LXX2012, WEB_C) +- **German (de):** 2 versions +- **Dutch (nl):** 3 versions +- **French (fr):** 1 version +- And 43+ other languages + +**Note:** User requested support for **Romanian (ro), Spanish (es), and Italian (it)** but these languages are **NOT found** in the vector database. This is a critical gap. + +### 4. Current Vector Search Implementation + +The existing code in `/root/biblical-guide/lib/vector-search.ts` already implements: +- โœ… Multi-table search across all versions for a given language +- โœ… Hybrid search (vector + full-text) +- โœ… Language-based table filtering +- โœ… Proper query pattern: `bv_{lang}_{version}` + +--- + +## โŒ What's Broken + +### 1. Azure OpenAI API Configuration (CRITICAL) + +**Problem:** The deployment names in `.env.local` do not exist in the Azure OpenAI resource. + +**Environment Variables:** +```bash +AZURE_OPENAI_DEPLOYMENT=gpt-4o # โŒ Deployment NOT FOUND (404) +AZURE_OPENAI_EMBED_DEPLOYMENT=embed-3 # โŒ Deployment NOT FOUND (404) +``` + +**Error Message:** +``` +DeploymentNotFound: The API deployment for this resource does not exist. +``` + +**Impact:** +- Chat API cannot generate responses +- Embedding generation fails +- Vector search cannot create query embeddings + +### 2. Missing Priority Languages + +**User Requirements:** Romanian (ro), Spanish (es), Italian (it) + +**Current Status:** +- โŒ **Romanian (ro):** NOT in vector database +- โŒ **Spanish (es):** NOT in vector database +- โŒ **Italian (it):** NOT in vector database + +**Available Languages:** The current 47 languages are mostly obscure languages (ab, ac, ad, ag, etc.) and do NOT include the user's priority languages. + +--- + +## ๐Ÿ”ง Required Fixes + +### Priority 1: Fix Azure OpenAI Deployments (IMMEDIATE) + +**Action Required:** +1. Identify the correct deployment names in the Azure OpenAI resource +2. Update `.env.local` with correct values: + - `AZURE_OPENAI_DEPLOYMENT=` + - `AZURE_OPENAI_EMBED_DEPLOYMENT=` + +**Options to Find Correct Deployment Names:** +- Option A: Check Azure Portal โ†’ Azure OpenAI โ†’ Deployments +- Option B: Contact Azure admin who created the resource +- Option C: Check deployment history/documentation + +**Expected Deployment Patterns:** +- Chat: Usually named like `gpt-4`, `gpt-4-32k`, `gpt-35-turbo`, etc. +- Embeddings: Usually named like `text-embedding-ada-002`, `text-embedding-3-small`, etc. + +### Priority 2: Add Priority Language Vector Tables (HIGH) + +**Missing Tables Needed:** +```sql +-- Romanian versions +ai_bible.bv_ro_cornilescu (Cornilescu Bible) +ai_bible.bv_ro_fidela (Fidela Bible - mentioned in BIBLE_MD_PATH) + +-- Spanish versions +ai_bible.bv_es_rvr1960 (Reina-Valera 1960) +ai_bible.bv_es_nvi (Nueva Versiรณn Internacional) + +-- Italian versions +ai_bible.bv_it_nuovadiodati (Nuova Diodati) +ai_bible.bv_it_nuovariveduta (Nuova Riveduta) +``` + +**Action Required:** +1. Verify if these Bible versions exist in source data +2. Create embeddings for each version +3. Import into `ai_bible` schema with proper naming + +### Priority 3: Implement English Fallback (MEDIUM) + +**Current Behavior:** +- Search only looks in language-specific tables (e.g., only `bv_ro_*` for Romanian) +- If language not found, returns empty results + +**Required Behavior:** +1. Search in primary language tables first +2. Check result quality (min 3 results, top similarity > 0.75) +3. If insufficient โ†’ fallback to English (`bv_en_*` tables) +4. Return combined results with language indicators + +**Implementation:** Already planned in `/root/biblical-guide/AI_CHAT_FIX_PLAN.md` + +--- + +## ๐Ÿ“Š Current System Architecture + +### Vector Search Flow (Working) +``` +User Query + โ†“ +getEmbedding(query) โŒ FAILS HERE - Deployment Not Found + โ†“ +searchBibleHybrid(query, language, limit) + โ†“ +getAllVectorTables(language) โœ“ Returns tables like ["ai_bible.bv_en_eng_kjv", ...] + โ†“ +For each table: + - Vector similarity search (embedding <=> query) + - Full-text search (tsv @@ plainto_tsquery) + - Combine scores (0.7 * vector + 0.3 * text) + โ†“ +Sort by combined_score and return top results +``` + +### Chat API Flow (Partially Working) +``` +User Message + โ†“ +[Auth Check] โœ“ Working + โ†“ +[Conversation Management] โœ“ Working + โ†“ +generateBiblicalResponse(message, locale, history) + โ†“ +searchBibleHybrid(message, locale, 5) โŒ FAILS - Embedding API 404 + โ†“ +[Build Context with Verses] โœ“ Would work if embeddings worked + โ†“ +[Call Azure OpenAI Chat API] โŒ FAILS - Chat API 404 + โ†“ +[Save to Database] โœ“ Working +``` + +--- + +## ๐ŸŽฏ Implementation Plan + +### Phase 1: Fix Azure OpenAI (Day 1 - URGENT) + +1. **Identify Correct Deployments** + - Check Azure Portal + - List all available deployments in the resource + - Document deployment names and models + +2. **Update Environment Configuration** + - Update `.env.local` with correct deployment names + - Verify API version compatibility + - Test connection with verification script + +3. **Validate Fix** + - Run `npx tsx scripts/verify-ai-system.ts` + - Confirm both Chat API and Embedding API pass + - Test end-to-end chat flow + +### Phase 2: Add Priority Languages (Days 2-3) + +1. **Romanian (ro)** + - Source Bible data for Cornilescu and Fidela versions + - Create embeddings using Azure OpenAI + - Import into `ai_bible.bv_ro_cornilescu` and `ai_bible.bv_ro_fidela` + +2. **Spanish (es)** + - Source Bible data for RVR1960 and NVI + - Create embeddings + - Import into respective tables + +3. **Italian (it)** + - Source Bible data for Nuova Diodati and Nuova Riveduta + - Create embeddings + - Import into respective tables + +### Phase 3: Implement Fallback Logic (Day 4) + +1. **Update `searchBibleHybrid` Function** + - Add quality check logic + - Implement English fallback + - Add language indicators to results + +2. **Update Chat API Response** + - Include source language in citations + - Inform user when fallback was used + - Format: `[KJV - English fallback] John 3:16` + +### Phase 4: Testing (Day 5) + +1. **Test Each Language** + - Romanian queries โ†’ Romanian results + - Spanish queries โ†’ Spanish results + - Italian queries โ†’ Italian results + - Unsupported language โ†’ English fallback + +2. **Test Edge Cases** + - Empty results handling + - Mixed language queries + - Very specific vs. general queries + +3. **Performance Testing** + - Query response time (target < 2s) + - Multi-table search performance + - Concurrent user handling + +--- + +## ๐Ÿ“ Next Steps + +### Immediate Actions (Today) + +1. โœ… Run verification script (COMPLETED) +2. โœ… Document findings (COMPLETED) +3. ๐Ÿ”ฒ Fix Azure OpenAI deployment configuration + - Identify correct deployment names + - Update `.env.local` + - Re-run verification script + +### Short-term Actions (This Week) + +4. ๐Ÿ”ฒ Source Romanian Bible data (Cornilescu, Fidela) +5. ๐Ÿ”ฒ Source Spanish Bible data (RVR1960, NVI) +6. ๐Ÿ”ฒ Source Italian Bible data (Nuova Diodati, Nuova Riveduta) +7. ๐Ÿ”ฒ Create embeddings for all priority language versions +8. ๐Ÿ”ฒ Import into vector database + +### Medium-term Actions (Next 2 Weeks) + +9. ๐Ÿ”ฒ Implement English fallback logic +10. ๐Ÿ”ฒ Add version metadata table (`bible_version_config`) +11. ๐Ÿ”ฒ Create comprehensive test suite +12. ๐Ÿ”ฒ Monitor performance and optimize queries + +--- + +## ๐Ÿšจ Critical Blockers + +1. **Azure OpenAI Deployment Names** (Blocking ALL functionality) + - Cannot generate embeddings + - Cannot generate chat responses + - Need Azure admin access to resolve + +2. **Missing Priority Languages** (Blocking user requirements) + - Romanian not available + - Spanish not available + - Italian not available + - Need Bible data sources and embeddings pipeline + +--- + +## ๐Ÿ“ˆ Success Metrics + +**Current Status:** +- โœ… Database: 100% +- โŒ API Configuration: 0% +- โŒ Language Support: 0% (for priority languages) +- โš ๏ธ Code Implementation: 80% (search logic exists, just needs API fix) + +**Target Status:** +- โœ… Database: 100% +- โœ… API Configuration: 100% +- โœ… Language Support: 100% (ro, es, it, en) +- โœ… Code Implementation: 100% + +--- + +## ๐Ÿ“š Reference Documents + +- `/root/biblical-guide/AI_CHAT_FIX_PLAN.md` - Original implementation plan +- `/root/biblical-guide/scripts/verify-ai-system.ts` - Verification script +- `/root/biblical-guide/lib/vector-search.ts` - Current search implementation +- `/root/biblical-guide/app/api/chat/route.ts` - Chat API implementation + +--- + +## Contact & Support + +**Azure OpenAI Resource:** +- Endpoint: `https://azureopenaiinstant.openai.azure.com` +- API Version: `2024-05-01-preview` +- **Action Needed:** Verify deployment names in Azure Portal + +**Vector Database:** +- Host: `10.0.0.207:5432` +- Database: `biblical-guide` +- Schema: `ai_bible` +- Status: โœ… Fully Operational diff --git a/app/[locale]/bible/reader.tsx b/app/[locale]/bible/reader.tsx index e060c4a..c877a99 100644 --- a/app/[locale]/bible/reader.tsx +++ b/app/[locale]/bible/reader.tsx @@ -9,6 +9,7 @@ import { OfflineBibleReader } from '@/components/bible/offline-bible-reader' import { offlineStorage } from '@/lib/offline-storage' import { InstallPrompt, useInstallPrompt } from '@/components/pwa/install-prompt' import { useSwipeable } from 'react-swipeable' +import { AuthModal } from '@/components/auth/auth-modal' import { Box, Typography, @@ -315,6 +316,11 @@ export default function BibleReaderNew({ initialVersion, initialBook, initialCha verse: null }) + // Auth modal state + const [authModalOpen, setAuthModalOpen] = useState(false) + const [authModalMessage, setAuthModalMessage] = useState('') + const [pendingAction, setPendingAction] = useState<(() => void) | null>(null) + // Refs const contentRef = useRef(null) const verseRefs = useRef<{[key: number]: HTMLDivElement}>({}) @@ -990,6 +996,26 @@ export default function BibleReaderNew({ initialVersion, initialBook, initialCha } } + const requireAuth = (action: () => void, message: string) => { + if (!user) { + setAuthModalMessage(message) + setPendingAction(() => action) + setAuthModalOpen(true) + return false + } + return true + } + + const handleAuthSuccess = () => { + setAuthModalOpen(false) + setAuthModalMessage('') + // Execute pending action if there is one + if (pendingAction) { + pendingAction() + setPendingAction(null) + } + } + const handlePreviousChapter = () => { // Trigger transition animation setIsTransitioning(true) @@ -1077,9 +1103,8 @@ export default function BibleReaderNew({ initialVersion, initialBook, initialCha const handleChapterBookmark = async () => { if (!selectedBook || !selectedChapter) return - // If user is not authenticated, redirect to login - if (!user) { - router.push(`/${locale}/login?redirect=${encodeURIComponent(`/${locale}/bible?version=${selectedVersion}&book=${selectedBook}&chapter=${selectedChapter}`)}`) + // If user is not authenticated, show auth modal + if (!requireAuth(handleChapterBookmark, 'Please login to bookmark this chapter')) { return } @@ -1123,9 +1148,8 @@ export default function BibleReaderNew({ initialVersion, initialBook, initialCha } const handleVerseBookmark = async (verse: BibleVerse) => { - // If user is not authenticated, redirect to login - if (!user) { - router.push(`/${locale}/login?redirect=${encodeURIComponent(`/${locale}/bible?version=${selectedVersion}&book=${selectedBook}&chapter=${selectedChapter}&verse=${verse.verseNum}`)}`) + // If user is not authenticated, show auth modal + if (!requireAuth(() => handleVerseBookmark(verse), 'Please login to bookmark this verse')) { return } @@ -1184,9 +1208,8 @@ export default function BibleReaderNew({ initialVersion, initialBook, initialCha } const handleVerseChat = (verse: BibleVerse) => { - // If user is not authenticated, redirect to login - if (!user) { - router.push(`/${locale}/login?redirect=${encodeURIComponent(`/${locale}/bible?version=${selectedVersion}&book=${selectedBook}&chapter=${selectedChapter}&verse=${verse.verseNum}`)}`) + // If user is not authenticated, show auth modal + if (!requireAuth(() => handleVerseChat(verse), 'Please login to ask AI about this verse')) { return } @@ -1255,9 +1278,8 @@ export default function BibleReaderNew({ initialVersion, initialBook, initialCha } const handleHighlightVerse = async (verse: BibleVerse, color: TextHighlight['color']) => { - // If user is not authenticated, redirect to login - if (!user) { - router.push(`/${locale}/login?redirect=${encodeURIComponent(`/${locale}/bible?version=${selectedVersion}&book=${selectedBook}&chapter=${selectedChapter}&verse=${verse.verseNum}`)}`) + // If user is not authenticated, show auth modal + if (!requireAuth(() => handleHighlightVerse(verse, color), 'Please login to highlight this verse')) { return } @@ -1397,8 +1419,8 @@ export default function BibleReaderNew({ initialVersion, initialBook, initialCha } const handleSetFavoriteVersion = async () => { - if (!user) { - router.push(`/${locale}/login?redirect=${encodeURIComponent(`/${locale}/bible?version=${selectedVersion}&book=${selectedBook}&chapter=${selectedChapter}`)}`) + // If user is not authenticated, show auth modal + if (!requireAuth(handleSetFavoriteVersion, 'Please login to set your default Bible version')) { return } @@ -2667,6 +2689,19 @@ export default function BibleReaderNew({ initialVersion, initialBook, initialCha {copyFeedback.message} + + {/* Auth Modal */} + { + setAuthModalOpen(false) + setAuthModalMessage('') + setPendingAction(null) + }} + onSuccess={handleAuthSuccess} + message={authModalMessage} + defaultTab="login" + /> ) } diff --git a/app/[locale]/page.tsx b/app/[locale]/page.tsx index 285e90e..87cefc9 100644 --- a/app/[locale]/page.tsx +++ b/app/[locale]/page.tsx @@ -1,145 +1,70 @@ 'use client' import { Container, - Card, - CardContent, Typography, Box, Button, Paper, useTheme, - Accordion, - AccordionSummary, - AccordionDetails, - TextField, - Chip, - Avatar, - IconButton, - Tooltip, + Divider, + Card, + CardContent, + List, + ListItem, + ListItemIcon, + ListItemText, } from '@mui/material' import { MenuBook, Chat, - Favorite as Prayer, - Search, - AutoStories, Favorite, - ExpandMore, - PlayArrow, - Share, - Bookmark, - TrendingUp, - QuestionAnswer, + Search, + Language, + CloudOff, + Security, + AutoStories, + Public, + VolunteerActivism, + CheckCircle, } from '@mui/icons-material' import { useRouter } from 'next/navigation' -import { useTranslations, useLocale } from 'next-intl' -import { useState, useEffect } from 'react' +import { useLocale } from 'next-intl' export default function Home() { const theme = useTheme() const router = useRouter() - const t = useTranslations('home') - const tSeo = useTranslations('seo') const locale = useLocale() - const [userCount, setUserCount] = useState(2847) - const [expandedFaq, setExpandedFaq] = useState(false) - const [email, setEmail] = useState('') - const [dailyVerse, setDailyVerse] = useState<{ - date: string - verse: string - reference: string - } | null>(null) - const [stats] = useState<{ - bibleVersions: number - verses: number - books: number - }>({ - bibleVersions: 1416, - verses: 17000000, - books: 66 - }) - - // Fetch daily verse - useEffect(() => { - const fetchDailyVerse = async () => { - try { - const response = await fetch(`/api/daily-verse?locale=${locale}`) - if (response.ok) { - const result = await response.json() - setDailyVerse(result.data) - } - } catch (error) { - console.error('Failed to fetch daily verse:', error) - // Fallback to static content if API fails - setDailyVerse({ - date: getCurrentDate(), - verse: t('dailyVerse.verse'), - reference: t('dailyVerse.reference') - }) - } - } - fetchDailyVerse() - }, [locale, t]) - - - // Simulate live user counter - useEffect(() => { - const interval = setInterval(() => { - setUserCount(prev => prev + Math.floor(Math.random() * 3)) - }, 5000) - return () => clearInterval(interval) - }, []) - - // Generate current date and year - const getCurrentDate = () => { - const now = new Date() - if (locale === 'ro') { - return now.toLocaleDateString('ro-RO', { - year: 'numeric', - month: 'long', - day: 'numeric' - }) - } else { - return now.toLocaleDateString('en-US', { - year: 'numeric', - month: 'long', - day: 'numeric' - }) - } - } - - const getCurrentYear = () => { - return new Date().getFullYear() - } const features = [ { - title: t('features.bible.title'), - description: t('features.bible.description'), - icon: , - path: '/bible', - color: theme.palette.primary.main, + icon: , + title: 'A Global Bible Library', + description: '1,200+ versions, from ancient Hebrew to modern translations', }, { - title: t('features.chat.title'), - description: t('features.chat.description'), - icon: , - path: '/__open-chat__', - color: theme.palette.secondary.main, + icon: , + title: 'Multilingual Access', + description: '7 languages today, 40+ tomorrow', }, { - title: t('features.prayers.title'), - description: t('features.prayers.description'), - icon: , - path: '/prayers', - color: theme.palette.success.main, + icon: , + title: 'A Prayer Wall Without Borders', + description: 'Believers praying for one another in real time', }, { - title: t('features.search.title'), - description: t('features.search.description'), - icon: , - path: '/search', - color: theme.palette.info.main, + icon: , + title: 'AI Bible Chat', + description: 'Answers grounded in Scripture, not opinion', + }, + { + icon: , + title: 'Complete Privacy', + description: 'No ads, no tracking, no data sale โ€” ever', + }, + { + icon: , + title: 'Offline Access', + description: 'Because the Word should reach even where the internet cannot', }, ] @@ -150,474 +75,581 @@ export default function Home() { sx={{ background: 'linear-gradient(135deg, #009688 0%, #00796B 100%)', color: 'white', - py: 8, - mb: 6, + py: { xs: 12, md: 20 }, + textAlign: 'center', + position: 'relative', + overflow: 'hidden', }} > - - - - - {t('hero.title')} - - - {t('hero.subtitle')} - - - {t('hero.description')} - - - - {t('hero.liveCounter')} - - - - - - - - - - - - + + + Biblical Guide + + + Every Scripture. Every Language. Forever Free. + + + + - {/* Interactive Demo Section */} - - - {t('demo.title')} + {/* Mission Section */} + + + The Word Should Never Have a Price Tag - - {t('demo.subtitle')} + + Most Bible apps today hide the Word of God behind ads, upgrades, or premium study tools. + + Biblical Guide is different. + + + No subscriptions. No tracking. No paywalls. + + + Just Scripture โ€” in every language, for every believer โ€” free forever. + + - - - - - - - - {t('demo.userQuestion')} - - - - - {t('demo.aiResponse')} - - - - - - - - - + + + {/* Donation Pitch Section */} + + + Your Gift Keeps the Gospel Free + + + Every donation directly supports the servers, translations, and technology that make Biblical Guide possible. + + + When you give, you are not paying for access โ€” you are keeping access open for millions who cannot afford to pay. + + + + Freely you have received; freely give. + + + โ€” Matthew 10:8 + - {/* Daily Verse Section */} - - - - {t('dailyVerse.title')} + {/* Features Section */} + + + + What Your Support Sustains - - {dailyVerse?.date || getCurrentDate()} + + Your donation keeps every verse, every prayer, every word โ€” free to all. - - - {dailyVerse?.verse || t('dailyVerse.verse')} - - - {dailyVerse?.reference || t('dailyVerse.reference')} - - - - - { - const verseText = dailyVerse?.verse || t('dailyVerse.verse') - const reference = dailyVerse?.reference || t('dailyVerse.reference') - const discussMessage = locale === 'ro' - ? `Poศ›i sฤƒ รฎmi explici mai mult despre acest verset: "${verseText}" (${reference})?` - : `Can you explain more about this verse: "${verseText}" (${reference})?` - - window.dispatchEvent(new CustomEvent('floating-chat:open', { - detail: { - fullscreen: true, - initialMessage: discussMessage - } - })) + + {features.map((feature, index) => ( + + - - - - - - - - - - - - - - - - - - - {t('dailyVerse.tomorrow')} - - - - - - - {/* How It Works Section */} - - - {t('howItWorks.title')} - - - {t('howItWorks.subtitle')} - - - - {[ - { icon: , title: t('howItWorks.step1.title'), description: t('howItWorks.step1.description') }, - { icon: , title: t('howItWorks.step2.title'), description: t('howItWorks.step2.description') }, - { icon: , title: t('howItWorks.step3.title'), description: t('howItWorks.step3.description') }, - ].map((step, index) => ( - - - {step.icon} - - - {step.title} - - - {step.description} - - - {index + 1} - - - ))} - - - - - - - - {/* Community Prayer Wall */} - - - - {t('prayerWall.title')} - - - - {[ - { text: t('prayerWall.prayer1'), time: t('prayerWall.time1'), count: 32 }, - { text: t('prayerWall.prayer2'), time: t('prayerWall.time2'), count: 47 }, - { text: t('prayerWall.prayer3'), time: t('prayerWall.time3'), count: 89, type: 'celebration' }, - ].map((prayer, index) => ( - - - - {prayer.text} - - - - {prayer.time} - - - - - - ))} - - - - - - - - - - {/* Features Section */} - - - {t('features.title')} - - - {t('features.subtitle')} - - - - {features.map((feature, index) => ( - - { - if (feature.path === '/__open-chat__') { - window.dispatchEvent(new CustomEvent('floating-chat:open', { detail: { fullscreen: true } })) - } else { - router.push(`/${locale}${feature.path}`) - } - }} - > - - - + + {feature.icon} - + {feature.title} - + {feature.description} - - - - - ))} - - - - {/* Testimonials Section */} - - - {t('testimonials.title')} - - - {t('testimonials.subtitle')} - - - - {[ - { name: t('testimonials.testimonial1.name'), role: t('testimonials.testimonial1.role'), text: t('testimonials.testimonial1.text'), avatar: '๐Ÿ‘ฉ' }, - { name: t('testimonials.testimonial2.name'), role: t('testimonials.testimonial2.role'), text: t('testimonials.testimonial2.text'), avatar: '๐Ÿ‘จโ€๐Ÿ’ผ' }, - { name: t('testimonials.testimonial3.name'), role: t('testimonials.testimonial3.role'), text: t('testimonials.testimonial3.text'), avatar: '๐Ÿ‘จ' }, - { name: t('testimonials.testimonial4.name'), role: t('testimonials.testimonial4.role'), text: t('testimonials.testimonial4.text'), avatar: '๐Ÿ‘ฉโ€๐Ÿซ' }, - ].map((testimonial, index) => ( - - - - "{testimonial.text}" - - - - {testimonial.avatar} - - - - {testimonial.name} - - - {testimonial.role} - - - - - - ))} - - - - - - - - {/* FAQ Section */} - - - {t('faq.title')} - - - - {[ - { id: 'accurate', question: t('faq.questions.accurate'), answer: t('faq.answers.accurate') }, - { id: 'free', question: t('faq.questions.free'), answer: t('faq.answers.free') }, - { id: 'languages', question: t('faq.questions.languages'), answer: t('faq.answers.languages') }, - { id: 'offline', question: t('faq.questions.offline'), answer: t('faq.answers.offline') }, - { id: 'privacy', question: t('faq.questions.privacy'), answer: t('faq.answers.privacy') }, - { id: 'versions', question: t('faq.questions.versions'), answer: t('faq.answers.versions') }, - ].map((faq) => ( - setExpandedFaq(isExpanded ? faq.id : false)} - sx={{ mb: 1 }} - > - }> - {faq.question} - - - - {faq.answer} - - - - ))} - - - - - - - - - {/* Stats Section */} - - - - - - {stats.bibleVersions.toLocaleString()} - - {t('stats.bibleVersions')} - - - - 17M+ - - {t('stats.verses')} - - - - 24/7 - - {t('stats.aiAvailable')} - + + + + ))} - + - {/* Newsletter CTA Section */} - + {/* Donation Options Section */} + + + How You Can Support + + + + + + + + + + ๐ŸŽฏ + Support us on Kickstarter (coming soon) + + + + + + Every contribution โ€” big or small โ€” helps keep Scripture open to everyone, everywhere. + + + + {/* Why It Matters Section */} + - - {t('newsletter.title')} + + Why It Matters - - {t('newsletter.description')} + + + + + Each day, someone opens a Bible app and hits a paywall. + + + + + Each day, a believer loses connection and can't read the Word offline. + + + + + Each day, the Gospel becomes harder to reach for someone who needs it most. + + + + + + Together, we can change that. - - setEmail(e.target.value)} - sx={{ flex: 1, minWidth: 250 }} - /> - + + + Every verse you read today stays free tomorrow. + + + + {/* Footer CTA */} + + + + Biblical-Guide.com + + + Every Scripture. Every Language. Forever Free. + + + + + + + - - + ) -} \ No newline at end of file +} diff --git a/app/[locale]/prayers/page.tsx b/app/[locale]/prayers/page.tsx index 708d8f7..47ac715 100644 --- a/app/[locale]/prayers/page.tsx +++ b/app/[locale]/prayers/page.tsx @@ -18,6 +18,7 @@ import { ListItemText, MenuItem, useTheme, + useMediaQuery, CircularProgress, Skeleton, Alert, @@ -29,6 +30,9 @@ import { Checkbox, SelectChangeEvent, Switch, + Accordion, + AccordionSummary, + AccordionDetails, } from '@mui/material' import { Favorite, @@ -42,10 +46,12 @@ import { AutoAwesome, Edit, Login, + ExpandMore, } from '@mui/icons-material' import { useState, useEffect, useMemo } from 'react' import { useTranslations, useLocale, useFormatter } from 'next-intl' import { useAuth } from '@/hooks/use-auth' +import { AuthModal } from '@/components/auth/auth-modal' interface PrayerRequest { id: string @@ -68,6 +74,7 @@ export default function PrayersPage() { const tc = useTranslations('common') const f = useFormatter() const { user } = useAuth() + const isMobile = useMediaQuery(theme.breakpoints.down('md')) const [prayers, setPrayers] = useState([]) const [selectedCategory, setSelectedCategory] = useState('all') const [openDialog, setOpenDialog] = useState(false) @@ -82,12 +89,14 @@ export default function PrayersPage() { const [isGenerating, setIsGenerating] = useState(false) const [loading, setLoading] = useState(true) const [viewMode, setViewMode] = useState<'private' | 'public'>(user ? 'private' : 'public') - const [selectedLanguages, setSelectedLanguages] = useState([locale]) + const [selectedLanguage, setSelectedLanguage] = useState(locale) + const [authModalOpen, setAuthModalOpen] = useState(false) - const languagesKey = useMemo(() => selectedLanguages.slice().sort().join(','), [selectedLanguages]) const languageOptions = useMemo(() => ([ { value: 'en', label: t('languageFilter.options.en') }, - { value: 'ro', label: t('languageFilter.options.ro') } + { value: 'ro', label: t('languageFilter.options.ro') }, + { value: 'es', label: t('languageFilter.options.es') }, + { value: 'it', label: t('languageFilter.options.it') } ]), [t]) const languageLabelMap = useMemo(() => ( languageOptions.reduce((acc, option) => { @@ -106,21 +115,10 @@ export default function PrayersPage() { useEffect(() => { if (viewMode === 'public') { - setSelectedLanguages(prev => { - if (prev.includes(locale)) { - return prev - } - return [...prev, locale] - }) + setSelectedLanguage(locale) } }, [locale, viewMode]) - useEffect(() => { - if (viewMode === 'public' && selectedLanguages.length === 0) { - setSelectedLanguages([locale]) - } - }, [viewMode, selectedLanguages, locale]) - const categories = [ { value: 'personal', label: t('categories.personal'), color: 'primary' }, { value: 'family', label: t('categories.family'), color: 'secondary' }, @@ -148,8 +146,7 @@ export default function PrayersPage() { params.append('visibility', viewMode) if (viewMode === 'public') { - const languagesToQuery = selectedLanguages.length > 0 ? selectedLanguages : [locale] - languagesToQuery.forEach(lang => params.append('languages', lang)) + params.append('languages', selectedLanguage) } const headers: Record = {} @@ -185,7 +182,7 @@ export default function PrayersPage() { useEffect(() => { fetchPrayers() - }, [selectedCategory, user, viewMode, languagesKey]) + }, [selectedCategory, user, viewMode, selectedLanguage]) const handleGenerateAIPrayer = async () => { if (!aiPrompt.trim()) return @@ -225,14 +222,9 @@ export default function PrayersPage() { } } - const handleLanguageChange = (event: SelectChangeEvent) => { + const handleLanguageChange = (event: SelectChangeEvent) => { const value = event.target.value - const parsed = typeof value === 'string' - ? value.split(',') - : (value as string[]) - - const uniqueValues = Array.from(new Set(parsed.filter(Boolean))) - setSelectedLanguages(uniqueValues) + setSelectedLanguage(value) } const handleSubmitPrayer = async () => { @@ -273,12 +265,18 @@ export default function PrayersPage() { const handleOpenDialog = () => { if (!user) { - // Could redirect to login or show login modal + setAuthModalOpen(true) return } setOpenDialog(true) } + const handleAuthSuccess = () => { + setAuthModalOpen(false) + // After successful auth, open the add prayer dialog + setOpenDialog(true) + } + const handlePrayFor = async (prayerId: string) => { try { const headers: HeadersInit = { @@ -371,80 +369,101 @@ export default function PrayersPage() { fullWidth variant="contained" color="primary" - startIcon={} - onClick={() => { - // Could redirect to login page or show login modal - console.log('Please login to add prayers') - }} + startIcon={} + onClick={handleOpenDialog} sx={{ mb: 3 }} > - {locale === 'en' ? 'Login to Add Prayer' : 'Conecteazฤƒ-te pentru a adฤƒuga'} + {t('addPrayer')} )} - - {t('categories.title')} - - - setSelectedCategory('all')} - sx={{ justifyContent: 'flex-start', cursor: 'pointer' }} - /> - {categories.map((category) => ( - setSelectedCategory(category.value)} - sx={{ justifyContent: 'flex-start', cursor: 'pointer' }} - /> - ))} - + {/* Categories Accordion */} + + } + aria-controls="categories-content" + id="categories-header" + > + + {t('categories.title')} + + + + + setSelectedCategory('all')} + sx={{ justifyContent: 'flex-start', cursor: 'pointer' }} + /> + {categories.map((category) => ( + setSelectedCategory(category.value)} + sx={{ justifyContent: 'flex-start', cursor: 'pointer' }} + /> + ))} + + + + {/* Language Filter Accordion */} {viewMode === 'public' && ( - - - {t('languageFilter.title')} - - - - - - {t('languageFilter.helper')} - - + + } + aria-controls="language-content" + id="language-header" + > + + {t('languageFilter.title')} + + + + + + + + {t('languageFilter.helper')} + + + )} - - {t('stats.title')} - - - โ€ข {t('stats.activeRequests', { count: prayers.length })}
- โ€ข {t('stats.totalPrayers', { count: prayers.reduce((sum, p) => sum + p.prayerCount, 0) })}
- โ€ข {t('stats.youPrayed', { count: prayers.filter(p => p.isPrayedFor).length })} -
+ {/* Stats Accordion */} + + } + aria-controls="stats-content" + id="stats-header" + > + + {t('stats.title')} + + + + + โ€ข {t('stats.activeRequests', { count: prayers.length })}
+ โ€ข {t('stats.totalPrayers', { count: prayers.reduce((sum, p) => sum + p.prayerCount, 0) })}
+ โ€ข {t('stats.youPrayed', { count: prayers.filter(p => p.isPrayedFor).length })} +
+
+
@@ -773,6 +792,15 @@ export default function PrayersPage() { + + {/* Auth Modal */} + setAuthModalOpen(false)} + onSuccess={handleAuthSuccess} + message={t('authRequired')} + defaultTab="login" + />
) diff --git a/components/auth/auth-modal.tsx b/components/auth/auth-modal.tsx new file mode 100644 index 0000000..f5bd4a2 --- /dev/null +++ b/components/auth/auth-modal.tsx @@ -0,0 +1,334 @@ +'use client' + +import { useState } from 'react' +import { + Dialog, + DialogContent, + DialogTitle, + TextField, + Button, + Box, + Typography, + Alert, + IconButton, + Tabs, + Tab, + InputAdornment, + CircularProgress +} from '@mui/material' +import { Close, Visibility, VisibilityOff } from '@mui/icons-material' +import { useTranslations } from 'next-intl' +import { useAuth } from '@/hooks/use-auth' + +interface AuthModalProps { + open: boolean + onClose: () => void + onSuccess?: () => void + defaultTab?: 'login' | 'register' + title?: string + message?: string +} + +export function AuthModal({ + open, + onClose, + onSuccess, + defaultTab = 'login', + title, + message +}: AuthModalProps) { + const t = useTranslations('auth') + const { login, register } = useAuth() + + const [tab, setTab] = useState<'login' | 'register'>(defaultTab) + const [showPassword, setShowPassword] = useState(false) + const [loading, setLoading] = useState(false) + const [error, setError] = useState(null) + + // Login form state + const [loginData, setLoginData] = useState({ + email: '', + password: '' + }) + + // Register form state + const [registerData, setRegisterData] = useState({ + name: '', + email: '', + password: '', + confirmPassword: '' + }) + + const handleTabChange = (event: React.SyntheticEvent, newValue: 'login' | 'register') => { + setTab(newValue) + setError(null) + } + + const handleLoginSubmit = async (e: React.FormEvent) => { + e.preventDefault() + setError(null) + setLoading(true) + + try { + const success = await login(loginData.email, loginData.password) + if (success) { + // Clear form + setLoginData({ email: '', password: '' }) + // Call success callback + onSuccess?.() + // Close modal + onClose() + } else { + setError(t('loginError')) + } + } catch (err: any) { + setError(err.message || t('connectionError')) + } finally { + setLoading(false) + } + } + + const handleRegisterSubmit = async (e: React.FormEvent) => { + e.preventDefault() + setError(null) + + // Validate passwords match + if (registerData.password !== registerData.confirmPassword) { + setError(t('passwordMismatch')) + return + } + + setLoading(true) + + try { + const success = await register( + registerData.email, + registerData.password, + registerData.name || undefined + ) + + if (success) { + // Clear form + setRegisterData({ name: '', email: '', password: '', confirmPassword: '' }) + // Call success callback + onSuccess?.() + // Close modal + onClose() + } else { + setError(t('registerError')) + } + } catch (err: any) { + setError(err.message || t('connectionError')) + } finally { + setLoading(false) + } + } + + const handleClose = () => { + if (!loading) { + setError(null) + onClose() + } + } + + return ( + + + + {title || (tab === 'login' ? t('welcomeBack') : t('joinUs'))} + + + + + + + + {message && ( + + {message} + + )} + + + + + + + {error && ( + + {error} + + )} + + {tab === 'login' ? ( + + setLoginData(prev => ({ ...prev, email: e.target.value }))} + required + disabled={loading} + sx={{ mb: 2 }} + autoComplete="email" + /> + setLoginData(prev => ({ ...prev, password: e.target.value }))} + required + disabled={loading} + sx={{ mb: 3 }} + autoComplete="current-password" + InputProps={{ + endAdornment: ( + + setShowPassword(!showPassword)} + edge="end" + disabled={loading} + > + {showPassword ? : } + + + ) + }} + /> + + + + {t('noAccount')}{' '} + + + + + ) : ( + + setRegisterData(prev => ({ ...prev, name: e.target.value }))} + disabled={loading} + sx={{ mb: 2 }} + autoComplete="name" + /> + setRegisterData(prev => ({ ...prev, email: e.target.value }))} + required + disabled={loading} + sx={{ mb: 2 }} + autoComplete="email" + /> + setRegisterData(prev => ({ ...prev, password: e.target.value }))} + required + disabled={loading} + sx={{ mb: 2 }} + autoComplete="new-password" + InputProps={{ + endAdornment: ( + + setShowPassword(!showPassword)} + edge="end" + disabled={loading} + > + {showPassword ? : } + + + ) + }} + /> + setRegisterData(prev => ({ ...prev, confirmPassword: e.target.value }))} + required + disabled={loading} + sx={{ mb: 3 }} + autoComplete="new-password" + error={registerData.confirmPassword !== '' && registerData.password !== registerData.confirmPassword} + helperText={ + registerData.confirmPassword !== '' && registerData.password !== registerData.confirmPassword + ? t('passwordMismatch') + : '' + } + /> + + + + {t('alreadyHaveAccount')}{' '} + + + + + )} + + + ) +} diff --git a/components/chat/floating-chat.tsx b/components/chat/floating-chat.tsx index 040b011..02fff80 100644 --- a/components/chat/floating-chat.tsx +++ b/components/chat/floating-chat.tsx @@ -45,6 +45,7 @@ import { import { useState, useRef, useEffect, useCallback } from 'react' import { useTranslations, useLocale } from 'next-intl' import ReactMarkdown from 'react-markdown' +import { AuthModal } from '@/components/auth/auth-modal' interface ChatMessage { id: string @@ -95,6 +96,7 @@ export default function FloatingChat() { const [showRenameDialog, setShowRenameDialog] = useState(false) const [showDeleteDialog, setShowDeleteDialog] = useState(false) const [newTitle, setNewTitle] = useState('') + const [authModalOpen, setAuthModalOpen] = useState(false) const messagesEndRef = useRef(null) const scrollToBottom = () => { @@ -123,6 +125,15 @@ export default function FloatingChat() { return () => window.removeEventListener('floating-chat:open', handler as EventListener) }, []) + // Listen for auth sign-in required events + useEffect(() => { + const handler = () => { + setAuthModalOpen(true) + } + window.addEventListener('auth:sign-in-required', handler as EventListener) + return () => window.removeEventListener('auth:sign-in-required', handler as EventListener) + }, []) + // Check authentication status useEffect(() => { checkAuthStatus() @@ -429,6 +440,12 @@ export default function FloatingChat() { const toggleFullscreen = () => setIsFullscreen(prev => !prev) + const handleAuthSuccess = () => { + setAuthModalOpen(false) + // Re-check auth status to update the UI + checkAuthStatus() + } + return ( <> {/* Floating Action Button */} @@ -999,6 +1016,17 @@ export default function FloatingChat() { )} + + {/* Auth Modal */} + setAuthModalOpen(false)} + onSuccess={handleAuthSuccess} + message={locale === 'ro' + ? 'Vฤƒ rugฤƒm sฤƒ vฤƒ autentificaศ›i pentru a accesa chat-ul AI ศ™i a salva conversaศ›iile.' + : 'Please sign in to access the AI chat and save your conversations.'} + defaultTab="login" + /> ) } diff --git a/lib/vector-search.ts b/lib/vector-search.ts index 39a573c..4a120bc 100644 --- a/lib/vector-search.ts +++ b/lib/vector-search.ts @@ -78,8 +78,9 @@ export async function getEmbedding(text: string): Promise { } // Fallback to Azure OpenAI + const embedApiVersion = process.env.AZURE_OPENAI_EMBED_API_VERSION || process.env.AZURE_OPENAI_API_VERSION const response = await fetch( - `${process.env.AZURE_OPENAI_ENDPOINT}/openai/deployments/${process.env.AZURE_OPENAI_EMBED_DEPLOYMENT}/embeddings?api-version=${process.env.AZURE_OPENAI_API_VERSION}`, + `${process.env.AZURE_OPENAI_ENDPOINT}/openai/deployments/${process.env.AZURE_OPENAI_EMBED_DEPLOYMENT}/embeddings?api-version=${embedApiVersion}`, { method: 'POST', headers: { diff --git a/logo.svg b/logo.svg new file mode 100644 index 0000000..a2e2566 --- /dev/null +++ b/logo.svg @@ -0,0 +1,4 @@ + + + + diff --git a/messages/en.json b/messages/en.json index b9ab7d3..87421f6 100644 --- a/messages/en.json +++ b/messages/en.json @@ -269,6 +269,8 @@ "prayers": { "title": "Prayers", "subtitle": "Share prayers and pray together with the community", + "addPrayer": "Add Prayer", + "authRequired": "Please sign in to add a prayer request and join our prayer community.", "viewModes": { "private": "My private prayers", "public": "Public prayer wall" @@ -279,7 +281,7 @@ }, "languageFilter": { "title": "Languages", - "helper": "Choose which languages to include. Your current language stays selected.", + "helper": "See prayers in other languages", "options": { "en": "English", "ro": "Romanian", diff --git a/messages/es.json b/messages/es.json index 8916b37..1517e03 100644 --- a/messages/es.json +++ b/messages/es.json @@ -269,6 +269,8 @@ "prayers": { "title": "Oraciones", "subtitle": "Comparte oraciones y ora junto con la comunidad", + "addPrayer": "Agregar oraciรณn", + "authRequired": "Por favor inicia sesiรณn para agregar una oraciรณn y unirte a nuestra comunidad de oraciรณn.", "viewModes": { "private": "Mis oraciones privadas", "public": "Muro de oraciรณn pรบblico" @@ -279,7 +281,7 @@ }, "languageFilter": { "title": "Idiomas", - "helper": "Elige quรฉ idiomas incluir. Tu idioma actual permanece seleccionado.", + "helper": "Ver oraciones en otros idiomas", "options": { "en": "Inglรฉs", "ro": "Rumano", diff --git a/messages/it.json b/messages/it.json index f06a14c..419ea6f 100644 --- a/messages/it.json +++ b/messages/it.json @@ -269,6 +269,8 @@ "prayers": { "title": "Preghiere", "subtitle": "Condividi preghiere e prega insieme alla comunitร ", + "addPrayer": "Aggiungi preghiera", + "authRequired": "Effettua l'accesso per aggiungere una preghiera e unirti alla nostra comunitร  di preghiera.", "viewModes": { "private": "Le mie preghiere private", "public": "Muro delle preghiere pubblico" @@ -279,7 +281,7 @@ }, "languageFilter": { "title": "Lingue", - "helper": "Scegli quali lingue includere. La tua lingua corrente rimane selezionata.", + "helper": "Vedi preghiere in altre lingue", "options": { "en": "Inglese", "ro": "Rumeno", diff --git a/messages/ro.json b/messages/ro.json index 5517554..4b5261d 100644 --- a/messages/ro.json +++ b/messages/ro.json @@ -269,6 +269,8 @@ "prayers": { "title": "Rugฤƒciuni", "subtitle": "Partajeazฤƒ rugฤƒciuni ศ™i roagฤƒ-te รฎmpreunฤƒ cu comunitatea", + "addPrayer": "Adaugฤƒ rugฤƒciune", + "authRequired": "Autentificฤƒ-te pentru a adฤƒuga o rugฤƒciune ศ™i a te alฤƒtura comunitฤƒศ›ii noastre de rugฤƒciune.", "viewModes": { "private": "Rugฤƒciunile mele", "public": "Peretele de rugฤƒciuni public" @@ -279,7 +281,7 @@ }, "languageFilter": { "title": "Limbi", - "helper": "Alege limbile pentru care vrei sฤƒ vezi rugฤƒciuni. Limba curentฤƒ rฤƒmรขne selectatฤƒ.", + "helper": "Vezi rugฤƒciuni รฎn alte limbi", "options": { "en": "Englezฤƒ", "ro": "Romรขnฤƒ",