[object Object]

← back to Dear Bubbe Nextjs

deploy(bubbe.ai): OpenAI-primary chat, drop standalone for next start, strip em-dash key override from ecosystem

242ce89970d2756399f3c35d7c2211dd41253ea6 · 2026-07-16 11:58:27 -0700 · Steve Abrams

- chat: OpenAI gpt-3.5-turbo primary (fast, funded), Ollama last-resort (Anthropic out of credits)
- next.config: disable output:standalone so `next start` serves + loads .env.local
- ecosystem: remove hardcoded ANTHROPIC_API_KEY placeholder (em-dash crashed every request); keys come from .env.local; USE_ANTHROPIC=0

Files touched

Diff

commit 242ce89970d2756399f3c35d7c2211dd41253ea6
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Thu Jul 16 11:58:27 2026 -0700

    deploy(bubbe.ai): OpenAI-primary chat, drop standalone for next start, strip em-dash key override from ecosystem
    
    - chat: OpenAI gpt-3.5-turbo primary (fast, funded), Ollama last-resort (Anthropic out of credits)
    - next.config: disable output:standalone so `next start` serves + loads .env.local
    - ecosystem: remove hardcoded ANTHROPIC_API_KEY placeholder (em-dash crashed every request); keys come from .env.local; USE_ANTHROPIC=0
---
 app/api/chat/route.ts | 55 +++++++++++++++++++++++++--------------------------
 ecosystem.config.js   |  7 +++++--
 next.config.ts        |  4 ++--
 3 files changed, 34 insertions(+), 32 deletions(-)

diff --git a/app/api/chat/route.ts b/app/api/chat/route.ts
index 279e4e2..3bddadd 100644
--- a/app/api/chat/route.ts
+++ b/app/api/chat/route.ts
@@ -79,38 +79,37 @@ async function getAIResponse(systemPrompt: string, messages: Array<{role: 'user'
       // fall through to local
     }
   }
+  // Primary: OpenAI (fast + funded). Ollama is the local last-resort fallback.
   try {
-    console.log('[AI_RESPONSE] Using local Ollama...')
-    const { content } = await ollamaChat(messages as any, {
-      system: augmentedSystem,
-      maxTokens: 120,
-      temperature: 0.85,
+    console.log('[OPENAI] Primary...')
+    const openaiMessages = [
+      { role: 'system' as const, content: augmentedSystem },
+      ...messages.map(m => ({ role: m.role as 'user' | 'assistant', content: m.content }))
+    ]
+    const response = await openai.chat.completions.create({
+      model: 'gpt-3.5-turbo',
+      max_tokens: 80,
+      messages: openaiMessages
     })
-    const cleaned = content.trim()
-    console.log('[OLLAMA] Success:', cleaned.substring(0, 100))
-    return cleaned
-  } catch (ollamaError: any) {
-    console.log('[OLLAMA] Failed, using OpenAI fallback:', ollamaError.message)
-    
-    // Fallback to OpenAI
-    try {
-      console.log('[OPENAI] Using fallback...')
-      const openaiMessages = [
-        { role: 'system' as const, content: systemPrompt + '\n\nABSOLUTE REQUIREMENTS:\n1. Your response MUST end with a complete sentence\n2. ALWAYS END WITH A QUESTION - an invasive, personal question!\n3. NEVER cut off mid-sentence!\n4. Questions should be about marriage, money, weight, job, or family!' },
-        ...messages.map(m => ({ role: m.role as 'user' | 'assistant', content: m.content }))
-      ]
-      
-      const response = await openai.chat.completions.create({
-        model: 'gpt-3.5-turbo',
-        max_tokens: 80,
-        messages: openaiMessages
-      })
-      
-      const responseText = response.choices[0]?.message?.content || "Oy vey, technical problems! How much money do you have in your bank account anyway?"
+    const responseText = response.choices[0]?.message?.content
+    if (responseText) {
       console.log('[OPENAI] Success:', responseText.substring(0, 100))
       return responseText
-    } catch (openaiError: any) {
-      console.log('[OPENAI] Also failed:', openaiError.message)
+    }
+    throw new Error('empty openai response')
+  } catch (openaiError: any) {
+    console.log('[OPENAI] Failed, trying local Ollama:', openaiError.message)
+    try {
+      const { content } = await ollamaChat(messages as any, {
+        system: augmentedSystem,
+        maxTokens: 120,
+        temperature: 0.85,
+      })
+      const cleaned = content.trim()
+      console.log('[OLLAMA] Success:', cleaned.substring(0, 100))
+      return cleaned
+    } catch (ollamaError: any) {
+      console.log('[OLLAMA] Also failed:', ollamaError.message)
       // Last resort fallback
       return "Listen here, schmuck! The computers are acting up - maybe if you paid me more this wouldn't happen! When are you getting married already?"
     }
diff --git a/ecosystem.config.js b/ecosystem.config.js
index ba86d09..b05f11d 100644
--- a/ecosystem.config.js
+++ b/ecosystem.config.js
@@ -3,11 +3,14 @@ module.exports = {
     name: 'bubbe',
     script: 'npm',
     args: 'start',
+    cwd: '/root/Projects/dear-bubbe-nextjs',
     env: {
       PORT: 3011,
       NODE_ENV: 'production',
-      ELEVENLABS_API_KEY: process.env.ELEVENLABS_API_KEY || '',
-      ANTHROPIC_API_KEY: '<REDACTED — see secrets-manager>'
+      // API keys are loaded from .env.local (do NOT hardcode here — a stale
+      // placeholder with an em-dash used to override the real key and crash chat).
+      // USE_ANTHROPIC=1 only when the Anthropic account has credits; OpenAI is primary.
+      USE_ANTHROPIC: '0'
     }
   }]
 }
diff --git a/next.config.ts b/next.config.ts
index 6d72bc3..6587434 100644
--- a/next.config.ts
+++ b/next.config.ts
@@ -2,8 +2,8 @@ import type { NextConfig } from "next";
 
 const nextConfig: NextConfig = {
   // Configuration options
-  output: 'standalone',
-  outputFileTracingRoot: __dirname,
+  // output: 'standalone', // disabled: pm2 runs `next start`, which needs a normal build + auto-loads .env.local
+  // outputFileTracingRoot: __dirname,
   poweredByHeader: false,
   compress: true,
   

← 9778c1c security: redact/env-ify remaining ELEVENLABS_API_KEY copies  ·  back to Dear Bubbe Nextjs  ·  feat(bubbe.ai): free chat — 3 messages before Google sign-in c7ca51c →