retired BH 1.0 on site:
super-embed
<!-- The Toast notification container -->
<div class="toast-container" id="toastContainer"></div>
<!-- The main Chatbot App container -->
<div class="app" id="app">
<!-- Quick Switch Panel -->
<div id="quickSwitchPanel" class="floating-panel floating-element">
<h3>Quick Switch</h3>
<select id="quickModelSelect"></select>
<select id="quickPersonaSelect"></select>
<button
class="chat-control-btn new-chat"
style="width: 100%; margin-top: 8px;"
onclick="window.applyQuickSwitch()"
>
Apply
</button>
</div>
<!-- Header -->
<header class="header">
<div class="logo">BrutallyHonest.ai</div>
<div class="header-actions">
<div class="credits-container" id="creditsDisplay">
<div class="credits-progress">
<div class="credits-text">
<span class="credits-number" id="creditsAmount">10</span> /
<span id="creditsMax">1000</span>
</div>
<div class="credits-bar">
<div class="credits-fill" id="creditsFill" style="width: 1%"></div>
</div>
</div>
<div style="font-size: 12px; color: var(--brand); font-weight: 600;">
as low as $2.99
</div>
</div>
<div class="theme-toggle" id="themeToggle">
<span id="themeIcon">āļø</span>
<span id="themeText">Light</span>
</div>
</div>
</header>
<!-- Explainer -->
<section class="explainer">
<h3>š„ The AI That Has Transformed Thousands</h3>
<p>Choose your AI personality and start chatting. <strong> </strong></p>
</section>
<!-- Error Display -->
<div class="error-message" id="errorMessage"></div>
<!-- Main Chat Interface -->
<div class="chat-container">
<div class="chat-header">
<div class="chat-title">
<span id="currentPersonaEmoji">š„</span>
<span id="currentPersonaName">Loading...</span>
<span id="currentModelInfo" style="font-size: 12px; color: var(--gray);"
>(GPT-4o-mini)</span
>
</div>
<div class="chat-controls">
<button class="chat-control-btn new-chat" id="newChatBtn">
⨠<span class="btn-text">New Chat</span>
</button>
<div class="control-group">
<button
class="chat-control-btn"
id="layoutToggle"
title="Toggle Layout"
>
š
</button>
<button
class="chat-control-btn"
id="chatFullscreenBtn"
title="Toggle Fullscreen"
>
ā¶
</button>
</div>
<div id="menuDropdown" class="menu-dropdown floating-element">
<button
class="chat-control-btn menu-toggle"
id="menuToggle"
title="More Options"
>
āÆ
</button>
<div class="menu-dropdown-content">
<button class="menu-item" id="quickSwitchBtn">
ā” Quick Switch
</button>
<hr
style="border: none; border-top: 1px solid var(--border); margin: 4px 0;"
/>
<button class="menu-item" id="saveBtn">š¾ Save Chat</button>
<button class="menu-item" id="clearBtn">šļø Clear Chat</button>
<button class="menu-item" id="exportBtn">š¤ Export Chat</button>
</div>
</div>
</div>
</div>
<div class="chat-messages" id="chatMessages">
<div class="message bot">
<div class="message-header">
<div class="message-avatar">š„</div>
<span>Loading...</span>
<span>ā¢</span>
<span>Just now</span>
</div>
<div class="message-bubble">
Welcome! Configuring your experience...
<button
class="copy-button"
onclick="copyMessage(this)"
data-text="Welcome! Configuring your experience..."
>
Copy
</button>
</div>
</div>
</div>
<div class="chat-input-area">
<div class="chat-input-container">
<textarea
class="chat-input"
id="chatInput"
placeholder="Type your message here..."
rows="1"
></textarea>
<button class="send-button" id="sendButton" title="Send (Enter)">
<span class="send-icon">ā</span>
</button>
</div>
</div>
</div>
<!-- Model & Persona Selection -->
<div class="persona-selection-container" id="personaSelectionContainer">
<h4 style="font-weight: 600; margin: 24px 0 16px; color: var(--brand);">
Choose Your AI Personality
</h4>
<div class="loading-placeholder" id="personasLoadingPlaceholder">
<div class="loading-animation"></div>
Loading personalities...
</div>
<div class="persona-grid" id="personaGrid"></div>
</div>
</div>
<!-- Credits Modal -->
<div class="modal" id="creditsModal">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-title">š Get More Credits</h2>
<button class="modal-close" id="closeCreditsModal">Ć</button>
</div>
<div class="pricing-option recommended">
<div class="pricing-title">Monthly Subscription</div>
<div class="pricing-price">
$9<span style="font-size: 12px; color: var(--gray);">/month</span>
</div>
<ul class="pricing-features">
<li>500 credits per month</li>
<li>Unlimited free models</li>
<li>Access to all premium models</li>
<li>Credits roll over (up to 1000)</li>
<li>Priority support</li>
</ul>
<button class="action-button" onclick="purchaseMonthly()">
Subscribe Now āØ
</button>
</div>
<div class="pricing-option">
<div class="pricing-title">Pay As You Go</div>
<div class="pricing-price">From $2.99</div>
<ul class="pricing-features">
<li>100 credits for $2.99</li>
<li>250 credits for $5.99</li>
<li>500 credits for $9.99</li>
<li>Credits never expire</li>
</ul>
<button class="action-button" onclick="purchaseCredits()">
Buy Credits š°
</button>
</div>
</div>
</div>
<!-- External scripts required by the chatbot -->
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<!-- All the CSS for the chatbot -->
<style>
:root {
/* Light Theme (Default) */
--black: #FFFFFF;
--black-soft: #F8F9FA;
--black-card: #F1F3F4;
--border: #E8EAED;
--border-light: #DADCE0;
--white: #000000;
--gray: #5F6368;
--gray-light: #3C4043;
--gray-dark: #80868B;
--brand: #5D5CDE;
--brand-light: #7C7CE8;
--brand-dark: #4B4BC7;
--accent: #EF4444;
--success: #22C55E;
--warning: #F59E0B;
--gold: #FCD34D;
--gradient-brand: linear-gradient(135deg, #5D5CDE 0%, #7C7CE8 100%);
--gradient-fire: linear-gradient(135deg, #EF4444 0%, #F59E0B 100%);
--gradient-success: linear-gradient(135deg, #22C55E 0%, #4ADE80 100%);
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.08);
--shadow: 0 1px 3px 0 rgb(0 0 0 / 0.12), 0 1px 2px -1px rgb(0 0 0 / 0.12);
--shadow-lg: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -1px rgb(0 0 0 / 0.06);
--shadow-xl: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -2px rgb(0 0 0 / 0.05);
--shadow-glow: 0 0 0 1px rgba(93, 92, 222, 0.3), 0 0 20px rgba(93, 92, 222, 0.2);
}
[data-theme="dark"] {
--black: #0F0F0F;
--black-soft: #1A1A1A;
--black-card: #262626;
--border: #404040;
--border-light: #525252;
--white: #FFFFFF;
--gray: #A3A3A3;
--gray-light: #D4D4D4;
--gray-dark: #737373;
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
}
/* All other styles from your original code... */
* { margin: 0; padding: 0; box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
.app { max-width: 1200px; margin: 0 auto; padding: 16px; min-height: 100vh; position: relative; width: 100%; transition: all 0.3s ease; }
.toast-container { position: fixed; top: 20px; right: 20px; z-index: 10000; pointer-events: none; }
.toast { background: var(--black-soft); border: 1px solid var(--border); border-radius: 8px; padding: 12px 16px; margin-bottom: 8px; box-shadow: var(--shadow-lg); backdrop-filter: blur(8px); animation: toastSlideIn 0.3s ease-out; pointer-events: all; font-size: 14px; max-width: 300px; }
.toast.success { border-color: var(--success); background: rgba(34, 197, 94, 0.1); }
.toast.error { border-color: var(--accent); background: rgba(239, 68, 68, 0.1); }
@keyframes toastSlideIn { from { opacity: 0; transform: translateX(100%); } to { opacity: 1; transform: translateX(0); } }
.app.fullscreen { position: fixed; top: 0; left: 0; right: 0; bottom: 0; max-width: none; padding: 0; z-index: 1000; background: var(--black); }
.app.fullscreen .header, .app.fullscreen .explainer, .app.fullscreen .model-selection-container, .app.fullscreen .persona-selection-container { display: none; }
.app.fullscreen .chat-container { height: 100vh; border-radius: 0; border: none; }
.floating-panel { position: fixed; top: 60px; right: 16px; width: 250px; background: var(--black-soft); border: 1px solid var(--border); border-radius: 12px; padding: 16px; z-index: 10002; display: none; box-shadow: var(--shadow-xl); }
.floating-panel.active { display: block; }
.floating-panel h3 { font-size: 14px; font-weight: 600; margin-bottom: 12px; }
.floating-panel select { width: 100%; background: var(--black-card); border: 1px solid var(--border); border-radius: 8px; padding: 8px; color: var(--white); font-size: 12px; margin-bottom: 8px; }
.copy-button { position: absolute; top: 8px; right: 8px; background: var(--black-card); border: 1px solid var(--border); border-radius: 4px; padding: 4px 6px; font-size: 10px; cursor: pointer; opacity: 0; transition: all 0.2s ease; color: var(--gray); font-weight: 500; }
.message.bot:hover .copy-button { opacity: 1; }
.copy-button:hover { background: var(--brand); color: var(--white); border-color: var(--brand); }
.copy-button.copied { background: var(--success); color: var(--white); border-color: var(--success); }
.credits-container { background: var(--black-soft); border: 1px solid var(--border); border-radius: 12px; padding: 12px 16px; display: flex; align-items: center; gap: 12px; cursor: pointer; transition: all 0.2s ease; }
.credits-container:hover { border-color: var(--brand); transform: translateY(-1px); }
.credits-progress { flex: 1; min-width: 80px; }
.credits-bar { width: 100%; height: 4px; background: var(--border); border-radius: 2px; overflow: hidden; margin-top: 4px; }
.credits-fill { height: 100%; background: var(--gradient-brand); border-radius: 2px; transition: width 0.5s ease; }
.credits-text { font-size: 12px; color: var(--gray); }
.credits-number { font-weight: 700; color: var(--brand); }
.loading-placeholder { background: var(--black-card); border-radius: 8px; padding: 16px; text-align: center; color: var(--gray); font-size: 14px; }
.loading-animation { display: inline-block; width: 16px; height: 16px; border: 2px solid var(--border); border-radius: 50%; border-top-color: var(--brand); animation: spin 1s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
.model-section { margin-bottom: 16px; }
.model-section-title { font-size: 10px; font-weight: 600; color: var(--gray); text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 8px; padding-left: 8px; }
.model-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 8px; }
.model-option { background: var(--black-card); border: 1px solid var(--border); border-radius: 8px; padding: 8px 12px; cursor: pointer; transition: all 0.2s ease; font-size: 12px; text-align: center; position: relative; }
.model-option:hover { border-color: var(--brand); transform: translateY(-1px); }
.model-option.active { background: rgba(93, 92, 222, 0.1); border-color: var(--brand); box-shadow: var(--shadow-glow); }
.model-name { font-size: 16px; font-weight: 600; margin-bottom: 2px; }
.model-cost { font-size: 14px; text-transform: uppercase; opacity: 0.8; }
.model-cost.free { color: var(--success); }
.model-cost.paid { color: var(--warning); }
.persona-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 12px; }
.persona-card { background: var(--black-card); border: 2px solid var(--border); border-radius: 12px; padding: 16px 12px; cursor: pointer; transition: all 0.2s ease; text-align: center; position: relative; }
.persona-card:hover { border-color: var(--brand); transform: translateY(-2px); }
.persona-card.active { border-color: var(--brand); background: rgba(93, 92, 222, 0.05); box-shadow: var(--shadow-glow); }
.persona-avatar { width: 48px; height: 48px; border-radius: 50%; margin: 0 auto 12px; display: flex; align-items: center; justify-content: center; font-size: 20px; color: var(--white); position: relative; }
.persona-name { font-weight: 600; font-size: 18px; margin-bottom: 4px; }
.persona-desc { font-size: 13px; color: var(--gray); line-height: 1.3; }
.chat-container { background: var(--black-soft); border: 2px solid var(--border); border-radius: 20px; height: 500px; display: flex; flex-direction: column; overflow: hidden; position: relative; transition: all 0.3s ease; }
.chat-container.flexbox { height: 70vh; max-height: 800px; min-height: 400px; }
.chat-header { padding: 12px 16px; border-bottom: 1px solid var(--border); display: flex; justify-content: space-between; align-items: center; flex-shrink: 0; background: var(--black-card); gap: 16px; }
.chat-title { font-weight: 600; display: flex; align-items: center; gap: 8px; font-size: 14px; flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chat-controls { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.control-group { display: flex; gap: 0; align-items: center; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
.control-group .chat-control-btn { border: none; border-left: 1px solid var(--border); border-radius: 0; }
.control-group .chat-control-btn:first-child { border-left: none; }
.control-group .chat-control-btn:hover { background: var(--black); }
.menu-dropdown { position: relative; }
.menu-dropdown-content { position: absolute; top: calc(100% + 8px); right: 0; background: var(--black-soft); border: 1px solid var(--border); border-radius: 8px; min-width: 150px; box-shadow: var(--shadow-lg); z-index: 10000; opacity: 0; visibility: hidden; transform: translateY(-10px); transition: all 0.2s ease; pointer-events: none; }
.menu-dropdown.active .menu-dropdown-content { opacity: 1; visibility: visible; transform: translateY(0); pointer-events: all; }
.menu-item { display: flex; align-items: center; gap: 8px; width: 100%; padding: 8px 12px; background: none; border: none; color: var(--white); font-size: 13px; text-align: left; cursor: pointer; transition: background-color 0.2s ease; }
.menu-item:hover { background: var(--black-card); }
.chat-control-btn { background: transparent; border: 1px solid var(--border); padding: 6px 10px; border-radius: 8px; color: var(--gray); cursor: pointer; transition: all 0.2s ease; font-size: 13px; white-space: nowrap; display: flex; align-items: center; gap: 6px; }
.chat-control-btn:hover:not(:disabled) { border-color: var(--brand); color: var(--brand); }
.chat-control-btn.new-chat { background: var(--gradient-brand); color: var(--white); border: none; font-weight: 600; padding: 6px 12px; }
[data-theme="light"] .chat-control-btn.new-chat { color: var(--black); }
.chat-control-btn.new-chat:hover:not(:disabled) { transform: translateY(-1px); box-shadow: var(--shadow-glow); }
.chat-control-btn.menu-toggle { padding: 6px; font-size: 18px; line-height: 1; }
.chat-messages { flex: 1; overflow-y: auto; padding: 16px; scroll-behavior: smooth; }
.message { margin-bottom: 16px; animation: slideIn 0.3s ease-out; }
@keyframes slideIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
.message-header { display: flex; align-items: center; gap: 6px; margin-bottom: 6px; font-size: 12px; color: var(--gray); }
.message-avatar { width: 20px; height: 20px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 18px; font-weight: 600; }
.message.user .message-avatar { background: var(--gradient-brand); color: var(--white); }
[data-theme="light"] .message.user .message-avatar { color: var(--black); }
.message.bot .message-avatar { background: var(--gradient-success); color: var(--white); }
[data-theme="light"] .message.bot .message-avatar { color: var(--black); }
.message-bubble { padding: 12px 16px; border-radius: 18px; font-size: 14px; line-height: 1.5; max-width: 85%; word-wrap: break-word; }
.message.user .message-bubble { margin-left: auto; background: var(--gradient-brand); color: var(--white); border-radius: 18px 18px 4px 18px; }
[data-theme="light"] .message.user .message-bubble { color: var(--black); }
.message.bot .message-bubble { background: var(--black-card); color: var(--gray-light); border: 1px solid var(--border-light); padding-right: 40px; border-radius: 18px 18px 18px 4px; position: relative; }
.message.system .message-bubble { background: rgba(93, 92, 222, 0.1); border: 1px solid var(--brand); color: var(--brand); font-size: 12px; padding: 8px 12px; font-style: italic; text-align: center; max-width: 100%; border-radius: 8px; }
.message.system .message-avatar { background: var(--gradient-brand); font-size: 12px; }
.chat-input-area { padding: 16px; border-top: 1px solid var(--border); background: var(--black-card); flex-shrink: 0; }
.chat-input-container { display: flex; gap: 8px; align-items: flex-end; }
.chat-input { flex: 1; background: var(--black); border: 1px solid var(--border); border-radius: 12px; padding: 12px; font-size: 16px; color: var(--white); resize: none; min-height: 48px; max-height: 120px; transition: all 0.2s ease; font-family: inherit; }
.chat-input:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 1px var(--brand); }
.chat-input::placeholder { color: var(--gray-dark); }
.send-button { background: var(--gradient-brand); border: none; padding: 0 16px; border-radius: 12px; color: var(--white); font-weight: 600; cursor: pointer; transition: all 0.2s ease; display: flex; align-items: center; justify-content: center; height: 48px; width: 48px; }
[data-theme="light"] .send-button { color: var(--black); }
.send-button:hover:not(:disabled) { transform: translateY(-1px); }
.send-button:disabled { opacity: 0.5; cursor: not-allowed; }
.send-button .send-icon { font-size: 20px; }
.error-message { background: rgba(239, 68, 68, 0.1); border: 1px solid var(--accent); border-radius: 8px; padding: 12px; margin: 8px 0; color: var(--accent); font-size: 14px; display: none; }
.error-message.show { display: block; animation: errorSlide 0.3s ease-out; }
@keyframes errorSlide { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } }
.typing-indicator { display: inline-flex; align-items: center; gap: 2px; }
.typing-dot { width: 4px; height: 4px; border-radius: 50%; background: var(--brand); animation: typing 1.4s infinite; }
.typing-dot:nth-child(2) { animation-delay: 0.2s; }
.typing-dot:nth-child(3) { animation-delay: 0.4s; }
@keyframes typing { 0%, 60%, 100% { transform: translateY(0); opacity: 0.4; } 30% { transform: translateY(-10px); opacity: 1; } }
.modal { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.8); backdrop-filter: blur(4px); display: flex; align-items: center; justify-content: center; z-index: 9000; opacity: 0; visibility: hidden; transition: all 0.3s ease; padding: 16px; }
.modal.active { opacity: 1; visibility: visible; }
.modal-content { background: var(--black-soft); border: 1px solid var(--border); border-radius: 20px; padding: 24px; max-width: 500px; width: 100%; max-height: 80vh; overflow-y: auto; }
.modal-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }
.modal-title { font-size: 20px; font-weight: 700; margin: 0; }
.modal-close { background: none; border: none; color: var(--gray); font-size: 20px; cursor: pointer; padding: 4px; }
.modal-close:hover { color: var(--white); }
.pricing-option { background: var(--black-card); border: 2px solid var(--border); border-radius: 16px; padding: 20px; margin-bottom: 12px; cursor: pointer; transition: all 0.2s ease; text-align: center; }
.pricing-option:hover { border-color: var(--brand); transform: translateY(-2px); }
.pricing-option.recommended { border-color: var(--success); position: relative; }
.pricing-option.recommended::before { content: "RECOMMENDED"; position: absolute; top: -8px; left: 50%; transform: translateX(-50%); background: var(--success); color: var(--white); padding: 4px 8px; border-radius: 12px; font-size: 9px; font-weight: 700; }
.pricing-title { font-size: 16px; font-weight: 600; margin-bottom: 6px; }
.pricing-price { font-size: 24px; font-weight: 700; color: var(--success); margin-bottom: 8px; }
.pricing-features { list-style: none; text-align: left; color: var(--gray-light); margin-bottom: 12px; }
.pricing-features li { padding: 3px 0; display: flex; align-items: center; gap: 6px; font-size: 12px; }
.pricing-features li::before { content: "ā"; color: var(--success); font-weight: bold; }
.action-button { background: var(--gradient-brand); border: none; padding: 12px 12px; border-radius: 16px; color: var(--white); font-weight: 600; font-size: 16px; cursor: pointer; transition: all 0.2s ease; width: 70%; }
[data-theme="light"] .action-button { color: var(--black); }
.action-button:hover { transform: translateY(-2px); box-shadow: var(--shadow-glow); }
.header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 24px; flex-wrap: wrap; gap: 16px; }
.logo { font-size: 20px; font-weight: 700; background: var(--gradient-brand); -webkit-background-clip: text; -webkit-text-fill-color: transparent; flex-shrink: 0; }
.header-actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.theme-toggle { background: var(--black-card); border: 1px solid var(--border); border-radius: 50px; padding: 8px 12px; cursor: pointer; transition: all 0.2s ease; font-size: 14px; display: flex; align-items: center; gap: 8px; white-space: nowrap; flex-shrink: 0; }
.theme-toggle:hover { border-color: var(--brand); }
.explainer { background: var(--black-soft); border: 1px solid var(--border); border-radius: 12px; padding: 20px; margin-bottom: 24px; text-align: center; }
.explainer h3 { font-size: 20px; font-weight: 600; color: var(--brand); margin-bottom: 8px; }
.explainer p { font-size: 14px; color: var(--gray-light); line-height: 1.5; }
@media (max-width: 768px) {
.app { padding: 12px; }
.header { flex-direction: column; align-items: stretch; text-align: center; margin-bottom: 20px; }
.header-actions { justify-content: center; }
.chat-container { height: auto; flex-grow: 1; border-radius: 0; margin: 0 -12px; border-left: none; border-right: none; }
.app { display: flex; flex-direction: column; }
.chat-header { padding: 8px 12px; }
.chat-controls { gap: 6px; }
.chat-control-btn, .control-group .chat-control-btn { font-size: 11px; padding: 6px 8px; }
.chat-control-btn.new-chat .btn-text { display: none; }
.floating-panel { width: calc(100vw - 32px); right: 16px; }
.menu-dropdown-content { right: -10px; }
}
</style>
<!-- Corrected & Simplified JavaScript -->
<script>
(function() {
if (window.brutallyHonestInitialized) {
return;
}
window.brutallyHonestInitialized = true;
const AppState = { user: { credits: 10, maxCredits: 1000, userId: 'user_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9) }, chat: { currentModel: 'openai/gpt-4o-mini', currentPersona: null, currentPersonaData: null, conversationId: 'conv_' + Date.now(), messages: [], isTyping: false }, ui: { theme: 'light', isFullscreen: false, layoutToggleLocked: false }, personas: [], isInitialized: false };
const CONFIG = {
mainWebhookUrl: 'https://photobar.app.n8n.cloud/webhook/bha-main-mvp' // Paste your actual Production URL here
};
function showToast(message, type = 'success', duration = 3000) { const container = document.getElementById('toastContainer'); if (!container) return; const toast = document.createElement('div'); toast.className = 'toast ' + type; toast.textContent = message; container.appendChild(toast); setTimeout(() => { toast.style.opacity = '0'; setTimeout(() => toast.remove(), 300); }, duration); }
function showError(message) { const errorEl = document.getElementById('errorMessage'); if (errorEl) { errorEl.textContent = message; errorEl.classList.add('show'); setTimeout(() => errorEl.classList.remove('show'), 5000); } }
function escapeHtml(unsafe) { if (typeof unsafe !== 'string') { return ''; } return unsafe.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"); }
function updateCreditDisplay() { document.getElementById('creditsAmount').textContent = AppState.user.credits; document.getElementById('creditsFill').style.width = (AppState.user.credits / AppState.user.maxCredits * 100) + '%'; }
function showCreditsModal() { document.getElementById('creditsModal').classList.add('active'); }
function hideCreditsModal() { document.getElementById('creditsModal').classList.remove('active'); }
function addMessage(content, isUser = false) {
const messagesContainer = document.getElementById('chatMessages');
const messageDiv = document.createElement('div');
messageDiv.className = 'message ' + (isUser ? 'user' : 'bot');
const timestamp = new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
const sender = isUser ? 'You' : (AppState.chat.currentPersonaData?.name || 'AI');
const avatar = isUser ? 'š¤' : (AppState.chat.currentPersonaData?.emoji || 'š¤');
const processedContent = isUser ? escapeHtml(content) : (typeof marked !== 'undefined' ? marked.parse(content) : content);
const messageHTML = '<div class="message-header"><div class="message-avatar">' + avatar + '</div><span>' + sender + '</span><span>ā¢</span><span>' + timestamp + '</span></div><div class="message-bubble">' + processedContent + (isUser ? '' : '<button class="copy-button" onclick="copyMessage(this)" data-text="' + escapeHtml(content) + '">Copy</button>') + '</div>';
messageDiv.innerHTML = messageHTML;
messagesContainer.appendChild(messageDiv);
messagesContainer.scrollTop = messagesContainer.scrollHeight;
if (!isUser) AppState.chat.messages.push({ content, isUser, timestamp: Date.now() });
}
function addSystemMessage(text) {
const messagesContainer = document.getElementById('chatMessages');
if (!messagesContainer) return;
const messageDiv = document.createElement('div');
messageDiv.className = 'message system';
messageDiv.innerHTML = '<div class="message-bubble">' + text + '</div>';
messagesContainer.appendChild(messageDiv);
messagesContainer.scrollTop = messagesContainer.scrollHeight;
}
function addTypingIndicator() {
const messagesContainer = document.getElementById('chatMessages');
const typingDiv = document.createElement('div');
typingDiv.id = 'typingIndicator';
typingDiv.className = 'message bot';
const typingHTML = '<div class="message-header"><div class="message-avatar">' + (AppState.chat.currentPersonaData?.emoji || 'š¤') + '</div><span>' + (AppState.chat.currentPersonaData?.name || 'AI') + '</span><span>ā¢</span><span>typing...</span></div><div class="message-bubble"><div class="typing-indicator"><div class="typing-dot"></div><div class="typing-dot"></div><div class="typing-dot"></div></div></div>';
typingDiv.innerHTML = typingHTML;
messagesContainer.appendChild(typingDiv);
messagesContainer.scrollTop = messagesContainer.scrollHeight;
}
function removeTypingIndicator() { const indicator = document.getElementById('typingIndicator'); if (indicator) indicator.remove(); }
async function sendMessage() {
const input = document.getElementById('chatInput');
const message = input.value.trim();
if (!message || AppState.chat.isTyping) return;
if (!AppState.chat.currentPersonaData) {
showError('Please select a persona first');
return;
}
if (AppState.user.credits < 1) {
showError('Insufficient credits!');
showCreditsModal();
return;
}
AppState.chat.messages.push({ content: message, isUser: true, timestamp: Date.now() });
addMessage(message, true);
input.value = '';
input.style.height = 'auto';
AppState.chat.isTyping = true;
document.getElementById('sendButton').disabled = true;
addTypingIndicator();
try {
const payload = {
user_id: AppState.user.userId,
bot_to_call: AppState.chat.currentPersonaData.id,
full_prompt_for_llm: message,
raw_user_situation: message,
selected_model_for_openrouter: AppState.chat.currentModel,
conversation_id: AppState.chat.conversationId,
timestamp: new Date().toISOString()
};
const response = await fetch(CONFIG.mainWebhookUrl, {
method: 'POST',
body: JSON.stringify(payload)
});
// This line is improved to give a better error if the response is not ok
if (!response.ok) {
throw new Error(`Network response was not ok. Status: ${response.status} ${response.statusText}`);
}
const data = await response.json();
const aiResponse = data.response || data.bot_response?.analysis || "I'm having trouble responding right now.";
removeTypingIndicator();
addMessage(aiResponse, false);
AppState.user.credits = Math.max(0, AppState.user.credits - 1);
updateCreditDisplay();
} catch (error) {
console.error('Send error:', error);
removeTypingIndicator();
// THIS IS THE IMPORTANT CHANGE: We now display the REAL error in the chat.
const errorMessageText = `šØ DEBUG: An error occurred: ${error.message}`;
addSystemMessage(errorMessageText); // Using addSystemMessage to make it look different
} finally {
AppState.chat.isTyping = false;
document.getElementById('sendButton').disabled = false;
}
}
function loadPersonas() { const personas = [{ id: 'theREALrealtalk', name: 'Real Talk', emoji: 'š¬', description: 'Contrarian Know-it-all', color: 'linear-gradient(135deg, #8B5CF6, #A855F7)' }, { id: 'AHA-Igniter', name: 'Aha! Moments', emoji: 'š”', description: 'Lightbulb moments', color: 'linear-gradient(135deg, #FCD34D, #F59E0B)' }, { id: 'BrutallyHonestAI', name: 'BrutallyHonestAI', emoji: 'š„', description: 'Fiesty and honest', color: 'linear-gradient(135deg, #EC7576, #956DD5)' }, { id: 'BOUNCE-CONVERTER-V3', name: 'Reverse-Engineer', emoji: 'š', description: 'Analyze anything', color: 'linear-gradient(135deg, #5D5CDE, #7C7CE8)' }, { id: 'Content-evolved', name: 'Evolve Content', emoji: 'š¬', description: 'Content optimizer', color: 'linear-gradient(135deg, #10B981, #06D6A0)' }, { id: 'joey', name: 'joey', emoji: 'š', description: 'The creator', color: 'linear-gradient(135deg, #EF4444, #F59E0B)' }]; AppState.personas = personas; const container = document.getElementById('personaGrid'); document.getElementById('personasLoadingPlaceholder').style.display = 'none'; container.innerHTML = personas.map(function(p) { return '<div class="persona-card" data-id="' + p.id + '"><div class="persona-avatar" style="background: ' + p.color + ';">' + p.emoji + '</div><div class="persona-name">' + p.name + '</div><div class="persona-desc">' + p.description + '</div></div>'; }).join(''); container.querySelectorAll('.persona-card').forEach(card => { card.addEventListener('click', (event) => { event.preventDefault(); event.stopPropagation(); selectPersona(card.dataset.id); }); }); selectPersona(personas[0].id, true); }
function selectPersona(personaId, isInitial = false) {
const persona = AppState.personas.find(p => p.id === personaId);
if (!persona || (!isInitial && AppState.chat.currentPersona === personaId)) return;
AppState.chat.currentPersona = personaId;
AppState.chat.currentPersonaData = persona;
document.querySelectorAll('.persona-card').forEach(card => { card.classList.toggle('active', card.dataset.id === personaId); });
document.getElementById('currentPersonaEmoji').textContent = persona.emoji;
document.getElementById('currentPersonaName').textContent = persona.name;
if (isInitial) {
const welcomeMessages = { 'BrutallyHonestAI': "Let's hear it. I won't hold back so brace yourself...", 'AHA-Igniter': "Ready for a breakthrough insight? What's on your mind?", 'BOUNCE-CONVERTER-V3': "Send me anything and I'll show you how to recreate it.", 'Content-evolved': "What content needs to be taken to the next level?", 'joey': "Hey! I created this experience. What's on your mind?", 'theREALrealtalk': "Time for some unfiltered truth. What's the situation?" };
const welcomeText = welcomeMessages[personaId] || "How can I help you today?";
document.getElementById('chatMessages').innerHTML = '';
addMessage(welcomeText, false);
} else {
addSystemMessage('You are now chatting with ' + persona.name + '.');
}
}
function toggleTheme() { AppState.ui.theme = AppState.ui.theme === 'light' ? 'dark' : 'light'; document.getElementById('app').parentElement.dataset.theme = AppState.ui.theme; document.getElementById('themeIcon').textContent = AppState.ui.theme === 'light' ? 'āļø' : 'š'; document.getElementById('themeText').textContent = AppState.ui.theme === 'light' ? 'Light' : 'Dark'; }
function toggleLayout() { if (AppState.ui.layoutToggleLocked) return; AppState.ui.layoutToggleLocked = true; const container = document.querySelector('.chat-container'); const isFlexbox = container.classList.contains('flexbox'); container.classList.toggle('flexbox'); showToast('Layout: ' + (isFlexbox ? 'Fixed' : 'Flexible'), 'success', 1000); setTimeout(() => { AppState.ui.layoutToggleLocked = false; }, 500); }
function toggleFullscreen() { AppState.ui.isFullscreen = !AppState.ui.isFullscreen; document.getElementById('app').classList.toggle('fullscreen', AppState.ui.isFullscreen); document.getElementById('chatFullscreenBtn').textContent = AppState.ui.isFullscreen ? 'ā£' : 'ā¶'; }
function startNewChat() { if (confirm('Start a new conversation?')) { AppState.chat.conversationId = 'conv_' + Date.now(); AppState.chat.messages = []; selectPersona(AppState.chat.currentPersona, true); showToast('New chat started', 'success'); } }
function clearChat() { if (confirm('Clear all messages?')) { AppState.chat.messages = []; selectPersona(AppState.chat.currentPersona, true); showToast('Chat cleared', 'success'); } }
function exportChat() { const messages = AppState.chat.messages; if (!messages.length) { showToast('No messages to export', 'error'); return; } let content = 'BrutallyHonest.ai Chat Export\nDate: ' + new Date().toLocaleString() + '\nPersona: ' + AppState.chat.currentPersonaData?.name + '\n' + '='.repeat(50) + '\n\n'; messages.forEach(msg => { content += '[' + new Date(msg.timestamp).toLocaleTimeString() + '] ' + (msg.isUser ? 'You' : 'AI') + ': ' + msg.content + '\n\n'; }); const blob = new Blob([content], { type: 'text/plain' }); const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = 'BHA_Chat_' + new Date().toISOString().split('T')[0] + '.txt'; a.click(); showToast('Chat exported', 'success'); }
window.copyMessage = function (button) { const text = button.dataset.text; navigator.clipboard.writeText(text).then(() => { button.textContent = 'Copied!'; button.classList.add('copied'); setTimeout(() => { button.textContent = 'Copy'; button.classList.remove('copied'); }, 2000); showToast('Copied to clipboard', 'success', 1500); }).catch(() => { showToast('Failed to copy', 'error'); }); };
window.purchaseMonthly = function () { showToast('Redirecting to checkout...', 'success'); setTimeout(() => { window.open('https://buy.stripe.com/28E4gz9RM3vyd6r3gGcV20a?client_reference_id=' + AppState.user.userId, '_blank'); }, 500); };
window.purchaseCredits = function () { showToast('Redirecting to checkout...', 'success'); setTimeout(() => { window.open('https://buy.stripe.com/00wfZhfc6c243vR04ucV20c?client_reference_id=' + AppState.user.userId, '_blank'); }, 500); };
window.applyQuickSwitch = function () { const personaId = document.getElementById('quickPersonaSelect').value; if (personaId) { selectPersona(personaId); } document.getElementById('quickSwitchPanel').classList.remove('active'); showToast('Persona switched to ' + AppState.chat.currentPersonaData.name, 'success'); };
function init() {
console.log('š„ Initializing BrutallyHonest.ai embed...');
updateCreditDisplay();
setTimeout(loadPersonas, 500);
document.getElementById('themeToggle').addEventListener('click', toggleTheme);
document.getElementById('layoutToggle').addEventListener('click', toggleLayout);
document.getElementById('chatFullscreenBtn').addEventListener('click', toggleFullscreen);
document.getElementById('newChatBtn').addEventListener('click', startNewChat);
document.getElementById('sendButton').addEventListener('click', sendMessage);
document.getElementById('closeCreditsModal').addEventListener('click', hideCreditsModal);
document.getElementById('saveBtn').addEventListener('click', () => showToast('Save feature coming soon', 'warning'));
document.getElementById('clearBtn').addEventListener('click', clearChat);
document.getElementById('exportBtn').addEventListener('click', exportChat);
document.getElementById('menuToggle').addEventListener('click', (e) => { e.stopPropagation(); document.getElementById('quickSwitchPanel').classList.remove('active'); document.getElementById('menuDropdown').classList.toggle('active'); });
document.getElementById('quickSwitchBtn').addEventListener('click', (e) => {
e.stopPropagation();
document.getElementById('menuDropdown').classList.remove('active');
const panel = document.getElementById('quickSwitchPanel');
panel.classList.toggle('active');
if (panel.classList.contains('active')) {
const personaSelect = document.getElementById('quickPersonaSelect');
if (personaSelect.options.length === 0) {
personaSelect.innerHTML = AppState.personas.map(p => '<option value="' + p.id + '">' + p.emoji + ' ' + p.name + '</option>').join('');
}
personaSelect.value = AppState.chat.currentPersona;
}
});
document.addEventListener('click', (e) => {
const menuDropdown = document.getElementById('menuDropdown');
const quickSwitchPanel = document.getElementById('quickSwitchPanel');
if (menuDropdown && !menuDropdown.contains(e.target) && menuDropdown.classList.contains('active')) {
menuDropdown.classList.remove('active');
}
if (quickSwitchPanel && !quickSwitchPanel.contains(e.target) && quickSwitchPanel.classList.contains('active')) {
quickSwitchPanel.classList.remove('active');
}
});
const chatInput = document.getElementById('chatInput');
chatInput.addEventListener('keydown', (e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendMessage(); } });
chatInput.addEventListener('input', function() { this.style.height = 'auto'; this.style.height = Math.min(this.scrollHeight, 120) + 'px'; });
document.getElementById('creditsDisplay').addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); showCreditsModal(); });
document.getElementById('creditsModal').addEventListener('click', (e) => { if (e.target.id === 'creditsModal') hideCreditsModal(); });
document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && AppState.ui.isFullscreen) { toggleFullscreen(); } });
const parentBody = document.getElementById('app').closest('body');
if (parentBody) { parentBody.dataset.theme = AppState.ui.theme; }
console.log('ā
BrutallyHonest.ai embed initialization complete!');
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();
</script>