AiAPP / index.html
micole66's picture
Upload 3 files
ef5496e verified
<!doctype html>
<html lang="en" class="dark">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>The Oracle | Decision Engine</title>
<script src="https://cdn.tailwindcss.com?plugins=forms"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;600;700;800&family=Inter:wght@400;500;600&family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet">
<script>
tailwind.config = {
darkMode: "class",
theme: {
extend: {
colors: {
primary: "#b4c5ff",
surface: "#031427",
tertiary: "#7bd0ff",
"surface-container-low": "#0b1c30",
"surface-container": "#102034",
"surface-container-high": "#1b2b3f",
"surface-container-highest": "#26364a",
"on-surface": "#d3e4fe",
"on-surface-variant": "#c2c6d9",
"outline-variant": "#424656",
"primary-container": "#0061ff"
},
fontFamily: {
headline: ["Manrope", "sans-serif"],
body: ["Inter", "sans-serif"]
}
}
}
};
</script>
<style>
body { font-family: "Inter", sans-serif; background: #031427; color: #d3e4fe; }
.material-symbols-outlined { font-variation-settings: "FILL" 0, "wght" 500, "GRAD" 0, "opsz" 24; }
.signature-gradient { background: linear-gradient(135deg, #b4c5ff 0%, #0061ff 100%); }
.glass-panel { background: rgba(42, 58, 79, 0.6); backdrop-filter: blur(20px); }
.view { display: none; }
.view.active { display: block; }
</style>
</head>
<body class="min-h-screen">
<header class="sticky top-0 z-50 px-6 py-4 bg-slate-950/80 backdrop-blur-xl border-b border-slate-800/30">
<div class="max-w-6xl mx-auto flex items-center justify-between">
<button data-nav="dashboard" class="flex items-center gap-2">
<span class="material-symbols-outlined text-indigo-200">blur_on</span>
<span class="font-headline font-bold tracking-wider text-indigo-200">The Oracle</span>
</button>
<nav class="flex items-center gap-3 text-xs uppercase tracking-widest">
<button data-nav="dashboard" class="nav-btn px-3 py-2 rounded-lg text-primary">Insights</button>
<button data-nav="dilemma" class="nav-btn px-3 py-2 rounded-lg text-slate-400">Resolve</button>
<button data-nav="recommendation" class="nav-btn px-3 py-2 rounded-lg text-slate-400">Log</button>
</nav>
</div>
</header>
<main class="max-w-6xl mx-auto px-6 py-8 pb-28">
<section id="dashboard" class="view active space-y-8">
<div class="flex flex-col md:flex-row md:items-end justify-between gap-4">
<div>
<p class="text-tertiary text-xs uppercase tracking-[0.2em] mb-2">System Status: Optimal</p>
<h1 class="font-headline text-4xl md:text-6xl font-extrabold">Welcome back, <span class="text-primary">Curator</span>.</h1>
</div>
<p class="text-on-surface-variant max-w-sm">The Oracle has synthesized 42 new variables for your pending evaluations.</p>
</div>
<div class="grid lg:grid-cols-12 gap-6">
<div class="lg:col-span-8 bg-surface-container-low rounded-xl p-8">
<p class="text-primary text-xs uppercase tracking-widest mb-4">Active Dilemma</p>
<h2 class="font-headline text-3xl font-bold mb-3">Project Phoenix: Market Entry Strategy</h2>
<p class="text-on-surface-variant mb-8">Southeast Asian expansion vs. European consolidation with Q3 geopolitical constraints.</p>
<button data-nav="recommendation" class="signature-gradient px-6 py-3 rounded-xl font-headline font-bold text-surface">View Full Analysis</button>
</div>
<aside class="lg:col-span-4">
<button data-nav="dilemma" class="w-full bg-primary-container rounded-xl p-8 text-center hover:shadow-[0_0_30px_rgba(0,97,255,0.35)] transition-shadow">
<span class="material-symbols-outlined text-4xl mb-2">add</span>
<h3 class="font-headline text-2xl font-bold">Initiate Resolution</h3>
<p class="text-sm opacity-85 mt-2">Input your variables and let The Oracle simulate all probable futures.</p>
</button>
</aside>
</div>
</section>
<section id="dilemma" class="view space-y-8">
<div class="flex justify-between items-end gap-4">
<div>
<p class="text-tertiary text-xs uppercase tracking-[0.2em] mb-2">New Resolution</p>
<h2 class="font-headline text-4xl md:text-5xl font-extrabold">Define your <span class="text-primary italic">dilemma</span>.</h2>
</div>
</div>
<label class="block text-sm uppercase tracking-widest text-on-surface-variant mb-2" for="dilemma-input">Core dilemma</label>
<textarea id="dilemma-input" class="w-full bg-surface-container-low border-none rounded-xl p-6 text-xl placeholder:text-slate-500 focus:ring-2 focus:ring-primary" rows="4" placeholder="Should we pivot strategy toward AI-integrated logistics by Q3?"></textarea>
<div class="grid md:grid-cols-2 gap-4">
<input id="option-a" class="bg-surface-container-low rounded-xl px-4 py-4 border-none focus:ring-2 focus:ring-primary" placeholder="Option Alpha (e.g. Immediate full pivot)">
<input id="option-b" class="bg-surface-container-low rounded-xl px-4 py-4 border-none focus:ring-2 focus:ring-primary" placeholder="Option Beta (e.g. Incremental integration)">
</div>
<div class="grid md:grid-cols-2 gap-4">
<input id="google-api-key" type="password" class="bg-surface-container-low rounded-xl px-4 py-4 border-none focus:ring-2 focus:ring-primary" placeholder="Google AI Studio API key (AIza...)">
<input id="google-model" class="bg-surface-container-low rounded-xl px-4 py-4 border-none focus:ring-2 focus:ring-primary" value="gemma-4-31b-it" placeholder="Model id (example: gemma-4-31b-it)">
</div>
<p class="text-xs text-on-surface-variant">
API key is used only in this browser session. If your model id is unavailable in your project (for example Gemma 4), the app will show the API error and you can switch to another available model id.
</p>
<button id="generate-btn" class="signature-gradient px-10 py-4 rounded-full font-headline font-bold text-surface">
Generate Analysis
</button>
</section>
<section id="thinking" class="view">
<div class="min-h-[60vh] flex flex-col items-center justify-center text-center">
<div class="w-56 h-56 rounded-full glass-panel border border-slate-700/30 flex items-center justify-center mb-8 shadow-[0_0_60px_rgba(0,97,255,0.25)]">
<span class="material-symbols-outlined text-7xl text-primary animate-pulse">psychology</span>
</div>
<h2 class="font-headline text-4xl md:text-5xl font-extrabold mb-2">Analyzing Data</h2>
<p class="text-on-surface-variant max-w-xl mb-8">The Oracle is synthesizing multi-dimensional variables to generate your strategic roadmap.</p>
<div class="w-full max-w-xl h-2 bg-surface-container-highest rounded-full overflow-hidden">
<div id="progress-bar" class="h-full bg-gradient-to-r from-tertiary to-primary transition-all duration-500" style="width: 8%"></div>
</div>
<p id="progress-label" class="text-xs uppercase tracking-[0.2em] text-tertiary mt-3">System Integrity 8%</p>
</div>
</section>
<section id="recommendation" class="view space-y-8">
<header>
<div class="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-sky-400/10 border border-sky-300/20 mb-4">
<span class="material-symbols-outlined text-tertiary text-base">auto_awesome</span>
<span class="text-xs uppercase tracking-widest text-tertiary">Analysis Complete</span>
</div>
<h2 class="font-headline text-4xl md:text-6xl font-extrabold">The Optimal Path.</h2>
</header>
<div class="signature-gradient rounded-full p-[2px]">
<div class="bg-surface-container-low rounded-full p-8 md:p-12 flex flex-col md:flex-row justify-between items-center gap-8">
<div>
<p class="text-xs uppercase tracking-widest text-primary mb-2">Recommended Choice</p>
<h3 id="final-choice" class="font-headline text-3xl md:text-4xl font-bold">Expand to Singapore Market</h3>
<p id="final-reason" class="text-on-surface-variant mt-2">High expected growth with favorable risk profile.</p>
</div>
<div class="text-center">
<p id="confidence-label" class="font-headline text-5xl font-black">85%</p>
<p class="text-xs uppercase tracking-widest text-on-surface-variant">Confidence</p>
</div>
</div>
</div>
<div class="flex flex-wrap gap-3">
<button data-nav="dashboard" class="signature-gradient px-6 py-3 rounded-full font-headline font-bold text-surface">Save Decision</button>
<button data-nav="dilemma" class="px-6 py-3 rounded-full border border-outline-variant text-on-surface">Run Another Analysis</button>
</div>
</section>
</main>
<script>
const views = document.querySelectorAll(".view");
const navButtons = document.querySelectorAll("[data-nav]");
const progressBar = document.getElementById("progress-bar");
const progressLabel = document.getElementById("progress-label");
const finalChoice = document.getElementById("final-choice");
const finalReason = document.getElementById("final-reason");
const confidenceLabel = document.getElementById("confidence-label");
const generateBtn = document.getElementById("generate-btn");
function extractTextFromResponse(data) {
const candidates = data && data.candidates;
if (!Array.isArray(candidates) || candidates.length === 0) return "";
const parts = candidates[0].content && candidates[0].content.parts;
if (!Array.isArray(parts)) return "";
return parts.map((p) => p.text || "").join("\n").trim();
}
function parseModelResponse(text, alpha, beta) {
const fallbackChoice = alpha || beta || "Expand to Singapore Market";
const fallbackReason = "High expected growth with favorable risk profile.";
const fallbackConfidence = "76%";
if (!text) {
return { choice: fallbackChoice, reason: fallbackReason, confidence: fallbackConfidence };
}
const lines = text.split("\n").map((l) => l.trim()).filter(Boolean);
let choice = "";
let reason = "";
let confidence = "";
lines.forEach((line) => {
const lower = line.toLowerCase();
if (!choice && lower.startsWith("choice:")) choice = line.slice(7).trim();
if (!reason && lower.startsWith("reason:")) reason = line.slice(7).trim();
if (!confidence && lower.startsWith("confidence:")) confidence = line.slice(11).trim();
});
return {
choice: choice || fallbackChoice,
reason: reason || lines.slice(0, 2).join(" ") || fallbackReason,
confidence: confidence || fallbackConfidence
};
}
async function callGoogleModel(apiKey, model, dilemma, alpha, beta) {
const endpoint = `https://generativelanguage.googleapis.com/v1beta/models/${encodeURIComponent(model)}:generateContent?key=${encodeURIComponent(apiKey)}`;
const prompt = [
"You are a strategic decision assistant.",
"Given a dilemma and two options, pick the best option.",
"Return exactly 3 lines in this strict format:",
"CHOICE: <best option text>",
"REASON: <single concise reason>",
"CONFIDENCE: <0-100%>",
"",
`DILEMMA: ${dilemma || "N/A"}`,
`OPTION_ALPHA: ${alpha || "N/A"}`,
`OPTION_BETA: ${beta || "N/A"}`
].join("\n");
const response = await fetch(endpoint, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
contents: [{ parts: [{ text: prompt }] }]
})
});
const data = await response.json();
if (!response.ok) {
const apiMessage = data && data.error && data.error.message ? data.error.message : "Google AI Studio request failed.";
throw new Error(apiMessage);
}
return extractTextFromResponse(data);
}
function normalizeModelId(modelInput) {
const cleaned = modelInput.trim().toLowerCase().replace(/\s+/g, "-");
if (cleaned === "gemma-4-31b-it") return cleaned;
if (cleaned === "gemma4-31b-it") return "gemma-4-31b-it";
if (cleaned === "gemma-4-31b-instruct") return "gemma-4-31b-it";
if (cleaned === "gemma-4-31b") return "gemma-4-31b-it";
return cleaned;
}
function showView(viewId) {
views.forEach((v) => v.classList.toggle("active", v.id === viewId));
navButtons.forEach((b) => {
if (!b.classList.contains("nav-btn")) return;
const active = b.dataset.nav === viewId;
b.classList.toggle("text-primary", active);
b.classList.toggle("text-slate-400", !active);
});
window.scrollTo({ top: 0, behavior: "smooth" });
}
navButtons.forEach((btn) => {
btn.addEventListener("click", () => showView(btn.dataset.nav));
});
generateBtn.addEventListener("click", async () => {
const apiKey = document.getElementById("google-api-key").value.trim();
const model = normalizeModelId(document.getElementById("google-model").value);
const dilemma = document.getElementById("dilemma-input").value.trim();
const alpha = document.getElementById("option-a").value.trim();
const beta = document.getElementById("option-b").value.trim();
if (!apiKey) {
alert("Please enter your Google AI Studio API key.");
return;
}
if (!model) {
alert("Please enter a model id.");
return;
}
finalChoice.textContent = alpha || beta || "Expand to Singapore Market";
finalReason.textContent = "Synthesizing model output...";
confidenceLabel.textContent = "--";
showView("thinking");
generateBtn.disabled = true;
let progress = 8;
progressBar.style.width = progress + "%";
progressLabel.textContent = `System Integrity ${progress}%`;
const timer = setInterval(() => {
progress = Math.min(90, progress + 7);
progressBar.style.width = progress + "%";
progressLabel.textContent = `System Integrity ${progress}%`;
}, 300);
try {
const raw = await callGoogleModel(apiKey, model, dilemma, alpha, beta);
const parsed = parseModelResponse(raw, alpha, beta);
finalChoice.textContent = parsed.choice;
finalReason.textContent = parsed.reason;
confidenceLabel.textContent = parsed.confidence;
} catch (error) {
finalChoice.textContent = alpha || beta || "Fallback Recommendation";
finalReason.textContent = `Model call failed: ${error.message}`;
confidenceLabel.textContent = "N/A";
} finally {
clearInterval(timer);
progress = 100;
progressBar.style.width = "100%";
progressLabel.textContent = "System Integrity 100%";
generateBtn.disabled = false;
setTimeout(() => showView("recommendation"), 450);
}
});
</script>
</body>
</html>