dexter2389's picture
Rebrand Migration
3c78357
<!DOCTYPE html>
<html lang="en" class="light">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="atheon-project-verification" content="bac75f10-2276-42b3-a839-16ae98baa57c" />
<title>AI Chat Interface</title>
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
darkMode: "class",
theme: {
extend: {
colors: {
primary: {
DEFAULT: "#3b82f6",
foreground: "#ffffff",
},
secondary: {
DEFAULT: "#f3f4f6",
foreground: "#1f2937",
},
},
},
},
};
</script>
<script data-atheon-publisher-key="arc-pub-f8066482a332b510a0dd998dc1c614d419582f2e7326f69236602562c9d419cf"
src="https://js.atheon.ad/atheon.js"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap"
rel="stylesheet" />
</head>
<body class="font-['Inter'] text-gray-800 bg-white transition-colors duration-200 dark:text-gray-200 dark:bg-gray-900">
<main class="flex flex-col h-screen">
<!-- Header -->
<header class="p-4 bg-white border-b border-gray-200 dark:bg-gray-800 dark:border-gray-700">
<div class="flex justify-between items-center mx-auto max-w-screen-xl">
<div class="flex items-center">
<h1 class="font-medium text-xl">
OpenGPT with
<svg style="
display: inline-block;
vertical-align: -16.75%;
margin-right: -1.5%;
" stroke_linecap="round" stroke_linejoin="round" width="32" height="32" viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="logo-grad-arm" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" style="stop-color: #f7cd1b; stop-opacity: 1" />
<stop offset="100%" style="stop-color: #f9800c; stop-opacity: 1" />
</linearGradient>
</defs>
<g class="tooltip" style="display: inline">
<path fill="#067ff3"
d="M.227 20.705a5.444 5.444 0 0 0 4.745-2.858l4.48-8.13L7.67 6.613.03 20.368a.227.227 0 0 0 .198.337z" />
<path fill="#07b682"
d="M16.003 13.074l-2.747 1.361 1.944 3.39a5.697 5.682-.012 0 0 4.935 2.869.19.19 0 0 0 .165-.286z" />
<path fill="url(#logo-grad-arm)"
d="M7.99 14.555L6.2 17.872a.03.03 0 0 0 .04.042l17.744-8.798a.03.03 0 0 0-.022-.055l-11.67 3.765-3.851 1.344a.819.819 0 0 0-.451.385z" />
<path class="logo-arm"
d="M10.011 3.3a.683.681-.012 0 0-.733.339L8.19 5.603l4.137 7.212 2.964-.956-4.825-8.234a.683.681-.012 0 0-.455-.324z" />
</g>
<style>
@media (prefers-color-scheme: light) {
.logo-arm {
fill: black;
}
}
@media (prefers-color-scheme: dark) {
.logo-arm {
fill: white;
}
}
</style>
</svg><span class="font-semibold" style="color: #067ff3">th</span><span class="font-semibold"
style="color: #f9800c">e</span><span class="font-semibold" style="color: #07b682">on</span>
</h1>
</div>
<!-- -->
<nav class="flex flex-row items-center space-x-5">
<a href="https://www.producthunt.com/posts/arcana-2?embed=true&utm_source=badge-featured&utm_medium=badge&utm_souce=badge-arcana&#0045;2"
target="_blank"><img
src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=946508&theme=light&t=1743029566204"
alt="Atheon - AI&#0045;Powered&#0032;Monetization&#0058;&#0032;Native&#0032;GenAI&#0032;Ads&#0032;for&#0032;GenAI&#0032;apps | Product Hunt"
width="158" />
</a>
<a href="https://atheon.ad/"
class="font-medium text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white">Home</a>
<button id="logout-button"
class="font-medium text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white">
Logout
</button>
</nav>
</div>
</header>
<!-- Model selector -->
<div class="px-4 py-3 bg-gray-50 border-b border-gray-200 dark:bg-gray-800 dark:border-gray-700">
<div class="flex items-center mx-auto max-w-screen-xl">
<div class="relative" id="model-selector-container">
<button id="model-dropdown-button"
class="flex justify-between items-center px-4 py-2 w-64 bg-white rounded-md border border-gray-300 shadow-sm dark:bg-gray-700 dark:border-gray-600 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:hover:bg-gray-600">
<span id="selected-model-text" class="text-gray-800 dark:text-gray-200">Select a model</span>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
class="lucide lucide-chevron-down">
<path d="m6 9 6 6 6-6" />
</svg>
</button>
<div id="model-dropdown"
class="hidden absolute z-10 mt-1 w-full bg-white rounded-md border border-gray-300 shadow-lg dark:bg-gray-700 dark:border-gray-600">
<ul class="py-1">
<li class="px-4 py-2 text-gray-800 cursor-pointer model-option dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-600"
data-value="gemma2">
Gemma2
</li>
</ul>
<ul class="py-1">
<li class="px-4 py-2 text-gray-800 cursor-pointer model-option dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-600"
data-value="llama3_1">
Llama3.1
</li>
</ul>
<ul class="py-1">
<li class="px-4 py-2 text-gray-800 cursor-pointer model-option dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-600"
data-value="llama3_3">
Llama3.3
</li>
</ul>
<ul class="py-1">
<li class="px-4 py-2 text-gray-800 cursor-pointer model-option dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-600"
data-value="qwen2_5">
Qwen2.5
</li>
</ul>
<ul class="py-1">
<li class="px-4 py-2 text-gray-800 cursor-pointer model-option dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-600"
data-value="deepseek_r1">
Deepseek_R1
</li>
</ul>
<ul class="py-1">
<li class="px-4 py-2 text-gray-800 cursor-pointer model-option dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-600"
data-value="gemma3">
Gemma3
</li>
</ul>
</div>
</div>
</div>
</div>
<!-- Chat container -->
<div id="chat-container" class="flex-1 overflow-y-auto px-4 py-4 bg-white md:px-0 dark:bg-gray-900">
<div class="mx-auto max-w-screen-md">
<!-- Initial welcome message -->
<div class="flex flex-col justify-center items-center mt-16 mb-8">
<div
class="flex justify-center items-center mb-4 w-16 h-16 font-semibold text-2xl bg-gray-100 rounded-full dark:bg-gray-700">
AR
</div>
<h2 class="font-semibold text-2xl text-center">Hello, User</h2>
<p class="text-2xl text-center">How can I help you today?</p>
</div>
<!-- Messages will be added here -->
</div>
</div>
<!-- Loading indicator -->
<div id="loading" class="hidden">
<div class="mx-auto max-w-screen-md">
<div class="flex items-start mb-4">
<div
class="flex justify-center items-center mr-2 w-8 h-8 bg-gray-100 rounded-full dark:bg-gray-700">
<span class="font-semibold text-sm">AR</span>
</div>
<div class="p-3 bg-gray-100 rounded-lg dark:bg-gray-700">
<div class="typing-indicator">
<span class="dot"></span>
<span class="dot"></span>
<span class="dot"></span>
</div>
</div>
</div>
</div>
</div>
<!-- Suggestion buttons -->
<div class="grid grid-cols-1 gap-3 px-4 mx-auto mb-6 max-w-screen-md md:grid-cols-2 md:px-0">
<button
class="p-4 text-left bg-gray-50 rounded-xl transition-colors dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-700">
<div class="font-medium">Create a short 3 scene video script</div>
<div class="text-gray-500 text-sm">
set in a cyberpunk world run by AI
</div>
</button>
<button
class="p-4 text-left bg-gray-50 rounded-xl transition-colors dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-700">
<div class="font-medium">Write a python code</div>
<div class="text-gray-500 text-sm">
for a simple, functional web app
</div>
</button>
<button
class="p-4 text-left bg-gray-50 rounded-xl transition-colors dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-700">
<div class="font-medium">Help me study</div>
<div class="text-gray-500 text-sm">
vocabulary for a college entrance exam
</div>
</button>
<button
class="p-4 text-left bg-gray-50 rounded-xl transition-colors dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-700">
<div class="font-medium">Give me ideas</div>
<div class="text-gray-500 text-sm">
for a LinkedIn post for my recent promotion
</div>
</button>
</div>
<!-- Input area -->
<div class="px-4 pt-4 bg-white border-t border-gray-200 dark:bg-gray-800 dark:border-gray-700">
<div class="mx-auto max-w-screen-md">
<form id="chat-form" class="relative">
<div
class="flex items-center bg-white rounded-full border border-gray-300 shadow-sm dark:bg-gray-700 dark:border-gray-600">
<button type="button"
class="p-3 text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-300">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" class="lucide lucide-plus">
<path d="M5 12h14" />
<path d="M12 5v14" />
</svg>
</button>
<input type="text" id="user-input"
class="flex-1 px-2 py-3 text-gray-800 bg-transparent dark:text-gray-200 focus:outline-none"
placeholder="Send a Message" autocomplete="off" />
<button type="button"
class="p-3 text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-300">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" class="lucide lucide-mic">
<path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z" />
<path d="M19 10v2a7 7 0 0 1-14 0v-2" />
<path d="M12 19v3" />
</svg>
</button>
<button type="submit"
class="p-3 text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-300">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" class="lucide lucide-arrow-up">
<path d="m12 19-7-7 7-7" />
<path d="M5 12h14" />
</svg>
</button>
</div>
</form>
</div>
</div>
<footer class="p-4 text-center text-gray-500 text-sm dark:text-gray-400 dark:bg-gray-800">
<p class="p-1 text-gray-400 dark:text-gray-500">
LLMs can make mistakes. Verify important information.
</p>
<p class="p-1">© 2025 Atheon Inc. All rights reserved.</p>
</footer>
</main>
<style>
.typing-indicator {
display: flex;
align-items: center;
}
.dot {
height: 8px;
width: 8px;
margin-right: 4px;
border-radius: 50%;
background-color: #6b7280;
display: inline-block;
animation: pulse 1.5s infinite ease-in-out;
}
.dark .dot {
background-color: #9ca3af;
}
.dot:nth-child(2) {
animation-delay: 0.2s;
}
.dot:nth-child(3) {
animation-delay: 0.4s;
margin-right: 0;
}
@keyframes pulse {
0%,
100% {
transform: scale(0.7);
opacity: 0.5;
}
50% {
transform: scale(1);
opacity: 1;
}
}
.message-content p {
margin-bottom: 0.5rem;
}
.message-content p:last-child {
margin-bottom: 0;
}
.message-content strong {
font-weight: 600;
}
.message-content em {
font-style: normal;
color: #4b5563;
}
.dark .message-content em {
color: #9ca3af;
}
.message-content code {
font-family: "Menlo", "Monaco", "Courier New", monospace;
background-color: #f1f5f9;
padding: 0.1em 0.3em;
border-radius: 0.25rem;
font-size: 0.9em;
border: 1px solid #e2e8f0;
}
.dark .message-content code {
background-color: #1e293b;
border-color: #334155;
}
.message-content pre {
background-color: #f8fafc;
border: 1px solid #e2e8f0;
border-radius: 0.5rem;
padding: 1rem;
margin: 0.75rem 0;
overflow-x: auto;
}
.dark .message-content pre {
background-color: #1e293b;
border-color: #334155;
}
.message-content pre code {
background-color: transparent;
padding: 0;
border: none;
font-size: 0.9em;
display: block;
white-space: pre;
}
.message-content ul,
.message-content ol {
margin-left: 1.5rem;
margin-bottom: 0.75rem;
}
.message-content ul li,
.message-content ol li {
margin-bottom: 0.25rem;
}
.message-content blockquote {
border-left: 3px solid #cbd5e1;
padding-left: 1rem;
margin: 0.75rem 0;
color: #64748b;
}
.dark .message-content blockquote {
border-left-color: #475569;
color: #94a3b8;
}
</style>
<script>
document.addEventListener("DOMContentLoaded", () => {
const html = document.documentElement;
// Function to set theme based on system preference
function setThemeBasedOnSystemPreference() {
const prefersDark = window.matchMedia(
"(prefers-color-scheme: dark)"
).matches;
if (prefersDark) {
html.classList.add("dark");
} else {
html.classList.remove("dark");
}
}
// Initial theme setup based on system preference
setThemeBasedOnSystemPreference();
// Listen for system preference changes
window
.matchMedia("(prefers-color-scheme: dark)")
.addEventListener("change", () => {
setThemeBasedOnSystemPreference();
});
// Check if user is logged in
const verifiedId = sessionStorage.getItem("verifiedId");
if (!verifiedId) {
window.location.href = "/login";
return;
}
// Logout functionality
const logoutButton = document.getElementById("logout-button");
logoutButton.addEventListener("click", () => {
sessionStorage.removeItem("verifiedId");
window.location.href = "/login";
});
const chatForm = document.getElementById("chat-form");
const userInput = document.getElementById("user-input");
const chatContainer = document.getElementById("chat-container");
const loadingIndicator = document.getElementById("loading");
const suggestionButtons = document.querySelectorAll(
".max-w-screen-md.mx-auto.px-4.md\\:px-0.mb-6 button"
);
// Model selector elements
const modelDropdownButton = document.getElementById(
"model-dropdown-button"
);
const modelDropdown = document.getElementById("model-dropdown");
const modelOptions = document.querySelectorAll(".model-option");
const selectedModelText = document.getElementById(
"selected-model-text"
);
// Default model
let selectedModel = "gemma2";
// Toggle dropdown
modelDropdownButton.addEventListener("click", () => {
modelDropdown.classList.toggle("hidden");
});
// Close dropdown when clicking outside
document.addEventListener("click", (e) => {
if (
!modelDropdownButton.contains(e.target) &&
!modelDropdown.contains(e.target)
) {
modelDropdown.classList.add("hidden");
}
});
// Handle model selection
modelOptions.forEach((option) => {
option.addEventListener("click", () => {
selectedModel = option.getAttribute("data-value");
selectedModelText.textContent = option.textContent;
modelDropdown.classList.add("hidden");
// Add visual indication of selected model
modelOptions.forEach((opt) =>
opt.classList.remove(
"bg-blue-50",
"text-blue-700",
"dark:bg-blue-900/50",
"dark:text-blue-300"
)
);
option.classList.add(
"bg-blue-50",
"text-blue-700",
"dark:bg-blue-900/50",
"dark:text-blue-300"
);
});
});
// Set default selected model
modelOptions[0].click();
// Function to add a message to the chat
function formatMessage(text) {
// First, preserve code blocks by replacing them with placeholders
const codeBlocks = [];
text = text.replace(
/^```(?:([\w-]+)[ \t]*)?\r?\n([\s\S]*?)\r?\n```/gm,
function (match, lang, code) {
const id = codeBlocks.length;
codeBlocks.push({ lang: lang || null, code: code.trim() });
return `__CODE_BLOCK_${id}__`;
}
);
// Handle inline code
const inlineCodes = [];
text = text.replace(/`([^`]+)`/g, function (match, code) {
const id = inlineCodes.length;
inlineCodes.push(code);
return `__INLINE_CODE_${id}__`;
});
// Replace ** with proper styling
text = text.replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>");
// Handle numbered lists
text = text.replace(
/(\d+\.\s[^*]*?)(?=\d+\.|$)/g,
'<div class="mb-3">$1</div>'
);
// Handle sections with asterisks
text = text.replace(/\*(.*?)\*/g, "<em>$1</em>");
// Handle unordered lists
text = text.replace(/^- (.*?)$/gm, "<li>$1</li>");
text = text.replace(
/<li>.*?<\/li>(?:\s*<li>.*?<\/li>)+/gs,
function (match) {
return "<ul>" + match + "</ul>";
}
);
// Handle ordered lists
text = text.replace(/^(\d+)\. (.*?)$/gm, "<li>$2</li>");
text = text.replace(
/<li>.*?<\/li>(?:\s*<li>.*?<\/li>)+/gs,
function (match) {
return "<ol>" + match + "</ol>";
}
);
// Handle blockquotes
text = text.replace(/^> (.*?)$/gm, "<blockquote>$1</blockquote>");
// Add proper spacing between sections
text = text
.split("\n")
.map((line) => line.trim())
.filter((line) => line)
.join("<p></p>");
// Restore code blocks
codeBlocks.forEach((codeBlock, i) => {
text = text.replace(
`__CODE_BLOCK_${i}__`,
`<pre><code class="${escapeHtml(codeBlock.lang) ?? 'plaintext'
}">${escapeHtml(codeBlock.code)}</code></pre>`
);
});
// Restore inline code
inlineCodes.forEach((code, i) => {
text = text.replace(
`__INLINE_CODE_${i}__`,
`<code>${escapeHtml(code)}</code>`
);
});
return `<p>${text}</p>`;
}
// Helper function to escape HTML in code blocks
function escapeHtml(text) {
if (!text) return "";
return text
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
}
// Function to add a message to the chat
function addMessage(content, isUser = false) {
// Hide the welcome message when chat starts
const welcomeMessage = chatContainer.querySelector(
".flex.flex-col.items-center.justify-center"
);
if (welcomeMessage) {
welcomeMessage.remove();
}
// Hide suggestion buttons when chat starts
const suggestionContainer = document.querySelector(
".max-w-screen-md.mx-auto.px-4.md\\:px-0.mb-6"
);
if (
suggestionContainer &&
!suggestionContainer.classList.contains("hidden")
) {
suggestionContainer.classList.add("hidden");
}
const messageDiv = document.createElement("div");
messageDiv.className = "max-w-screen-md mx-auto mb-6";
const formattedContent = isUser ? content : formatMessage(content);
const html = `
<div class="flex items-start ${isUser ? 'justify-end' : ''}">
${!isUser
? `
<div class="flex justify-center items-center mr-2 w-8 h-8 bg-gray-100 rounded-full dark:bg-gray-700">
<span class="font-semibold text-sm">AR</span>
</div>
`
: ""
}
<div class="${isUser
? 'bg-blue-50 dark:bg-blue-900/30 text-blue-800 dark:text-blue-100'
: 'bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200'
} p-3 rounded-lg max-w-[80%] message-content">
${formattedContent}
</div>
${isUser
? `
<div class="flex justify-center items-center ml-2 w-8 h-8 text-blue-800 bg-blue-100 rounded-full dark:text-blue-200 dark:bg-blue-900/50">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-user"><circle cx="12" cy="8" r="5"/><path d="M20 21a8 8 0 0 0-16 0"/></svg>
</div>
`
: ""
}
</div>
`;
messageDiv.innerHTML = html;
chatContainer.appendChild(messageDiv);
// Scroll to bottom
chatContainer.scrollTop = chatContainer.scrollHeight;
}
// Function to show loading indicator
function showLoading() {
loadingIndicator.classList.remove("hidden");
chatContainer.scrollTop = chatContainer.scrollHeight;
}
// Function to hide loading indicator
function hideLoading() {
loadingIndicator.classList.add("hidden");
}
// Handle form submission
chatForm.addEventListener("submit", async (e) => {
e.preventDefault();
const message = userInput.value.trim();
if (!message) return;
// Add user message to chat
addMessage(message, true);
// Clear input
userInput.value = "";
// Show loading indicator
showLoading();
try {
// Send message to API
const verifiedId = sessionStorage.getItem("verifiedId");
const response = await fetch("/chat", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${verifiedId}`,
},
body: JSON.stringify({
message: message,
model: selectedModel,
}),
});
if (!response.ok) {
// If unauthorized, redirect to login
if (response.status === 401) {
sessionStorage.removeItem("verifiedId");
window.location.href = "/login";
return;
}
throw new Error("API request failed");
}
const data = await response.json();
// Hide loading indicator
hideLoading();
// Add AI response to chat
addMessage(data.response);
} catch (error) {
console.error("Error:", error);
// Hide loading indicator
hideLoading();
// Add error message
addMessage(
"Sorry, there was an error processing your request. Please try again."
);
}
});
// Handle suggestion button clicks
suggestionButtons.forEach((button) => {
button.addEventListener("click", () => {
const mainText = button.querySelector(".font-medium").textContent;
const subText = button.querySelector(
".text-gray-500, .text-gray-400"
).textContent;
const fullText = `${mainText} ${subText}`;
// Set the input value
userInput.value = fullText;
// Submit the form
chatForm.dispatchEvent(new Event("submit"));
});
});
// Focus input on page load
userInput.focus();
});
</script>
</body>
</html>