714 lines
34 KiB
HTML
714 lines
34 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Prompt Studio — Nexus One AI</title>
|
||
<link rel="stylesheet" href="style.css?v=4">
|
||
<style>
|
||
.ps-layout {
|
||
display: grid;
|
||
grid-template-columns: 300px 1fr 340px;
|
||
height: calc(100vh - 64px);
|
||
overflow: hidden;
|
||
}
|
||
@media(max-width:1100px){ .ps-layout { grid-template-columns: 260px 1fr; } .ps-history-panel { display:none; } }
|
||
@media(max-width:720px){ .ps-layout { grid-template-columns: 1fr; } .ps-editor-panel { display:none; } }
|
||
|
||
/* ── Left: Editor Panel ── */
|
||
.ps-editor-panel {
|
||
border-right: 1px solid var(--bdr);
|
||
background: var(--navy2);
|
||
display: flex; flex-direction: column;
|
||
overflow: hidden;
|
||
}
|
||
.ps-panel-header {
|
||
padding: 14px 16px 12px;
|
||
border-bottom: 1px solid var(--bdr);
|
||
display: flex; align-items: center; justify-content: space-between;
|
||
}
|
||
.ps-panel-title { font-size: 12px; font-weight: 700; color: var(--lt); text-transform: uppercase; letter-spacing: .5px; }
|
||
.ps-panel-body { flex: 1; overflow-y: auto; padding: 14px 14px 0; display: flex; flex-direction: column; gap: 14px; }
|
||
.ps-panel-footer { padding: 12px 14px; border-top: 1px solid var(--bdr); }
|
||
|
||
.ps-field label {
|
||
display: block; font-size: 11px; font-weight: 700; color: var(--lt);
|
||
text-transform: uppercase; letter-spacing: .4px; margin-bottom: 6px;
|
||
}
|
||
.ps-field textarea, .ps-field select, .ps-field input[type=range], .ps-field input[type=number] {
|
||
width: 100%; box-sizing: border-box; font-family: inherit;
|
||
border: 1.5px solid var(--bdr); border-radius: 9px;
|
||
background: var(--bg); color: var(--ink); font-size: 13px;
|
||
transition: border-color .15s;
|
||
}
|
||
.ps-field textarea { padding: 10px 12px; resize: vertical; min-height: 90px; line-height: 1.55; }
|
||
.ps-field textarea:focus, .ps-field select:focus { outline: none; border-color: var(--purple); }
|
||
.ps-field select { padding: 8px 10px; cursor: pointer; }
|
||
|
||
.ps-params-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
|
||
.ps-param { }
|
||
.ps-param label { display: block; font-size: 11px; font-weight: 700; color: var(--lt); text-transform: uppercase; letter-spacing: .4px; margin-bottom: 5px; }
|
||
.ps-param-row { display: flex; align-items: center; gap: 8px; }
|
||
.ps-param-row input[type=range] { flex: 1; accent-color: var(--purple); }
|
||
.ps-param-val { font-size: 12px; font-weight: 700; color: var(--purple); min-width: 30px; text-align: right; }
|
||
|
||
.ps-run-btn {
|
||
width: 100%; padding: 11px; border-radius: 10px;
|
||
background: var(--purple); color: white; border: none;
|
||
font-family: inherit; font-size: 14px; font-weight: 700;
|
||
cursor: pointer; transition: .15s; display: flex; align-items: center; justify-content: center; gap: 8px;
|
||
}
|
||
.ps-run-btn:hover { background: #6d28d9; }
|
||
.ps-run-btn:disabled { opacity: .5; cursor: not-allowed; }
|
||
.ps-run-btn .ps-spinner { display: none; width: 16px; height: 16px; border: 2px solid rgba(255,255,255,.3); border-top-color: white; border-radius: 50%; animation: spin .7s linear infinite; }
|
||
.ps-run-btn.running .ps-spinner { display: block; }
|
||
.ps-run-btn.running .ps-run-icon { display: none; }
|
||
@keyframes spin { to { transform: rotate(360deg); } }
|
||
|
||
.ps-save-btn {
|
||
width: 100%; padding: 8px; border-radius: 9px; margin-top: 8px;
|
||
background: none; border: 1.5px solid var(--bdr); color: var(--ink);
|
||
font-family: inherit; font-size: 13px; font-weight: 600;
|
||
cursor: pointer; transition: .15s;
|
||
}
|
||
.ps-save-btn:hover { border-color: var(--purple); color: var(--purple); }
|
||
|
||
/* ── Middle: Output Panel ── */
|
||
.ps-output-panel {
|
||
display: flex; flex-direction: column;
|
||
overflow: hidden; background: var(--bg);
|
||
}
|
||
.ps-output-header {
|
||
padding: 12px 18px;
|
||
border-bottom: 1px solid var(--bdr);
|
||
display: flex; align-items: center; gap: 12px;
|
||
background: var(--navy2);
|
||
}
|
||
.ps-output-title { font-size: 13px; font-weight: 700; color: var(--ink); flex: 1; }
|
||
.ps-stat-chips { display: flex; gap: 8px; }
|
||
.ps-stat-chip {
|
||
padding: 3px 10px; border-radius: 20px; font-size: 11px; font-weight: 700;
|
||
background: rgba(124,58,237,.1); color: var(--purple);
|
||
}
|
||
.ps-stat-chip.green { background: rgba(16,185,129,.1); color: #059669; }
|
||
.ps-output-actions { display: flex; gap: 6px; }
|
||
.ps-icon-btn {
|
||
background: none; border: 1.5px solid var(--bdr); border-radius: 8px;
|
||
padding: 5px 10px; cursor: pointer; font-size: 12px; color: var(--med);
|
||
transition: .15s; font-family: inherit;
|
||
}
|
||
.ps-icon-btn:hover { border-color: var(--purple); color: var(--purple); }
|
||
|
||
.ps-output-body { flex: 1; overflow-y: auto; padding: 24px; }
|
||
.ps-output-empty {
|
||
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
||
height: 100%; gap: 12px; color: var(--lt);
|
||
}
|
||
.ps-output-empty .ps-empty-icon { font-size: 40px; opacity: .4; }
|
||
.ps-output-empty p { font-size: 14px; }
|
||
|
||
.ps-response-block {
|
||
background: var(--navy2); border: 1.5px solid var(--bdr);
|
||
border-radius: 14px; padding: 20px 22px;
|
||
font-size: 14px; line-height: 1.7; color: var(--ink);
|
||
}
|
||
.ps-response-block h1,.ps-response-block h2,.ps-response-block h3 { margin:.8em 0 .4em; color:var(--ink); }
|
||
.ps-response-block h1 { font-size:1.3em; } .ps-response-block h2 { font-size:1.15em; } .ps-response-block h3 { font-size:1.05em; }
|
||
.ps-response-block p { margin:.5em 0; }
|
||
.ps-response-block ul,.ps-response-block ol { padding-left:1.5em; margin:.4em 0; }
|
||
.ps-response-block li { margin:.3em 0; }
|
||
.ps-response-block code { background:rgba(124,58,237,.1); color:var(--purple); padding:2px 6px; border-radius:5px; font-family:monospace; font-size:.9em; }
|
||
.ps-response-block pre { background:#160D35; color:#e2d9f3; border-radius:10px; padding:14px 16px; overflow-x:auto; margin:.8em 0; }
|
||
.ps-response-block pre code { background:none; color:inherit; padding:0; }
|
||
.ps-response-block blockquote { border-left:3px solid var(--purple); padding-left:14px; margin:.6em 0; color:var(--med); font-style:italic; }
|
||
.ps-response-block table { border-collapse:collapse; width:100%; margin:.6em 0; font-size:.9em; }
|
||
.ps-response-block th { background:rgba(124,58,237,.08); padding:8px 12px; text-align:left; font-weight:700; border-bottom:2px solid var(--bdr); }
|
||
.ps-response-block td { padding:7px 12px; border-bottom:1px solid var(--bdr); }
|
||
.ps-response-block strong { font-weight:700; }
|
||
.ps-response-block em { font-style:italic; }
|
||
|
||
.ps-streaming-cursor { display:inline-block; width:2px; height:1em; background:var(--purple); margin-left:2px; animation:blink .8s step-end infinite; vertical-align:text-bottom; }
|
||
@keyframes blink { 50%{ opacity:0; } }
|
||
|
||
/* ── Right: History Panel ── */
|
||
.ps-history-panel {
|
||
border-left: 1px solid var(--bdr);
|
||
background: var(--navy2);
|
||
display: flex; flex-direction: column;
|
||
overflow: hidden;
|
||
}
|
||
.ps-history-list { flex: 1; overflow-y: auto; padding: 8px; }
|
||
.ps-history-item {
|
||
padding: 10px 12px; border-radius: 10px; cursor: pointer;
|
||
transition: .1s; border: 1.5px solid transparent; margin-bottom: 4px;
|
||
}
|
||
.ps-history-item:hover { background: rgba(124,58,237,.06); border-color: var(--bdr); }
|
||
.ps-history-item.active { border-color: var(--purple); background: rgba(124,58,237,.08); }
|
||
.ps-history-item-header { display: flex; align-items: center; gap: 7px; margin-bottom: 5px; }
|
||
.ps-history-model { font-size: 11px; font-weight: 700; color: var(--purple); background: rgba(124,58,237,.1); padding: 2px 8px; border-radius: 20px; }
|
||
.ps-history-time { font-size: 11px; color: var(--lt); margin-left: auto; }
|
||
.ps-history-prompt { font-size: 12px; color: var(--med); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||
.ps-history-stats { display: flex; gap: 10px; margin-top: 5px; }
|
||
.ps-history-stat { font-size: 11px; color: var(--lt); }
|
||
.ps-history-empty { padding: 24px 16px; text-align: center; color: var(--lt); font-size: 13px; }
|
||
|
||
/* Toast */
|
||
#ps-toast {
|
||
position: fixed; bottom: 24px; right: 24px; z-index: 9999;
|
||
background: var(--ink); color: white; padding: 10px 18px;
|
||
border-radius: 10px; font-size: 13px; font-weight: 600;
|
||
opacity: 0; transform: translateY(8px); transition: .25s; pointer-events: none;
|
||
}
|
||
#ps-toast.show { opacity: 1; transform: translateY(0); }
|
||
|
||
/* Diff highlight */
|
||
.ps-diff-added { background: rgba(16,185,129,.15); border-radius: 3px; }
|
||
.ps-diff-removed { background: rgba(239,68,68,.12); text-decoration: line-through; border-radius: 3px; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<header class="topnav">
|
||
<a href="index.html" class="brand">Nexus One <span>AI</span></a>
|
||
<nav>
|
||
<a href="index.html">Home</a>
|
||
<a href="quickstart.html">Quick Start</a>
|
||
<a href="prompts.html">Prompt Library</a>
|
||
<a href="usecases.html">Use Cases</a>
|
||
<span class="nav-sep"></span>
|
||
<div class="nav-dropdown">
|
||
<button class="nav-drop-btn">Help ▾</button>
|
||
<div class="nav-drop-menu">
|
||
<span class="nav-drop-cat">LEARN /</span>
|
||
<a href="quickstart.html">Quick Start</a>
|
||
<a href="models.html">Models</a>
|
||
<span class="nav-drop-cat">SUPPORT /</span>
|
||
<a href="troubleshooting.html">Troubleshoot</a>
|
||
<a href="faq.html">FAQ</a>
|
||
<span class="nav-drop-cat">MORE /</span>
|
||
<a href="glossary.html">Glossary</a>
|
||
<a href="whats-new.html">What's New</a>
|
||
</div>
|
||
</div>
|
||
<div class="nav-dropdown">
|
||
<button class="nav-drop-btn">Admin ▾</button>
|
||
<div class="nav-drop-menu nav-drop-menu-wide">
|
||
<span class="nav-drop-cat">DOCS /</span>
|
||
<a href="security.html">Security & Privacy</a>
|
||
<a href="admin.html">Admin Guide</a>
|
||
<span class="nav-drop-cat">MONITOR /</span>
|
||
<a href="dashboard.html">Dashboard</a>
|
||
<a href="analytics.html">Usage Analytics</a>
|
||
<a href="audit.html">Audit Log</a>
|
||
<a href="feedback.html">Feedback & Ratings</a>
|
||
<span class="nav-drop-cat">MANAGE /</span>
|
||
<a href="users.html">Users</a>
|
||
<a href="teams.html">Teams</a>
|
||
<a href="models-admin.html">Model Manager</a>
|
||
<a href="training.html">Training</a>
|
||
<a href="knowledge.html">Knowledge Base</a>
|
||
<span class="nav-drop-cat">TOOLS /</span>
|
||
<a href="apikeys.html">API Keys</a>
|
||
<a href="benchmark.html">Benchmarking</a>
|
||
<a href="model-compare.html">Model Compare</a>
|
||
<a href="api-playground.html">API Playground</a>
|
||
<a href="guardrails.html">Guardrails</a>
|
||
<a href="rag-quality.html">RAG Quality</a>
|
||
<a href="router.html">Model Router</a>
|
||
<a href="connectors.html">Connectors</a>
|
||
<span class="nav-drop-cat">SYSTEM /</span>
|
||
<a href="console.html">Console</a>
|
||
<a href="settings.html">Settings</a>
|
||
</div>
|
||
</div>
|
||
<div class="nav-dropdown">
|
||
<button class="nav-drop-btn active">AI Tools ▾</button>
|
||
<div class="nav-drop-menu">
|
||
<span class="nav-drop-cat">INTELLIGENCE /</span>
|
||
<a href="documents.html">Document Intelligence</a>
|
||
<a href="chat-multi.html">Multimodal Chat</a>
|
||
<a href="prompt-studio.html" class="active">Prompt Studio</a>
|
||
<a href="meeting.html">Meeting Assistant</a>
|
||
<span class="nav-drop-cat">AUTOMATION /</span>
|
||
<a href="agents.html">Agent Builder</a>
|
||
<a href="schedules.html">Scheduled Jobs</a>
|
||
<a href="workflows.html">Workflow Automation</a>
|
||
<span class="nav-drop-cat">QUALITY /</span>
|
||
<a href="evals.html">AI Eval Suite</a>
|
||
<a href="chatrooms.html">Chat Rooms</a>
|
||
</div>
|
||
</div>
|
||
</nav>
|
||
<a href="notifications.html" style="position:relative">🔔</a>
|
||
<span class="badge" data-brand="tier">Basic Tier</span>
|
||
<div id="nav-org-logo" class="nav-org-logo"></div>
|
||
</header>
|
||
|
||
<div class="ps-layout">
|
||
|
||
<!-- ── Left: Editor ── -->
|
||
<div class="ps-editor-panel">
|
||
<div class="ps-panel-header">
|
||
<span class="ps-panel-title">⚗️ Prompt Studio</span>
|
||
<button class="ps-icon-btn" onclick="clearAll()" title="Clear all">✕ Clear</button>
|
||
</div>
|
||
<div class="ps-panel-body" id="ps-editor-body">
|
||
|
||
<div class="ps-field">
|
||
<label>Model</label>
|
||
<select id="ps-model">
|
||
<option value="llama3.1:8b">llama3.1:8b — General Purpose</option>
|
||
<option value="llama3.1:70b">llama3.1:70b — Complex Reasoning</option>
|
||
<option value="mistral:7b">mistral:7b — Structured Output</option>
|
||
<option value="codellama:34b">codellama:34b — Code</option>
|
||
<option value="llava:13b">llava:13b — Vision</option>
|
||
<option value="llama3.2:3b">llama3.2:3b — Fast / Lightweight</option>
|
||
<option value="gemma2:9b">gemma2:9b — Instruction Following</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="ps-field">
|
||
<label>System Prompt <span style="font-weight:400;text-transform:none;letter-spacing:0;color:var(--lt)">(sets AI role & behaviour)</span></label>
|
||
<textarea id="ps-system" rows="6" placeholder="You are a helpful AI assistant for [Organisation]. Answer questions clearly and concisely. Always cite your sources when referring to documents."></textarea>
|
||
</div>
|
||
|
||
<div class="ps-field">
|
||
<label>User Message</label>
|
||
<textarea id="ps-user" rows="5" placeholder="Type your test message here…" onkeydown="handleKey(event)"></textarea>
|
||
</div>
|
||
|
||
<div class="ps-params-grid">
|
||
<div class="ps-param">
|
||
<label>Temperature</label>
|
||
<div class="ps-param-row">
|
||
<input type="range" id="ps-temp" min="0" max="1" step="0.05" value="0.7" oninput="document.getElementById('ps-temp-val').textContent=this.value">
|
||
<span class="ps-param-val" id="ps-temp-val">0.7</span>
|
||
</div>
|
||
</div>
|
||
<div class="ps-param">
|
||
<label>Max Tokens</label>
|
||
<div class="ps-param-row">
|
||
<input type="range" id="ps-maxtok" min="128" max="4096" step="128" value="1024" oninput="document.getElementById('ps-maxtok-val').textContent=this.value">
|
||
<span class="ps-param-val" id="ps-maxtok-val">1024</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Quick templates -->
|
||
<div class="ps-field">
|
||
<label>Quick Templates</label>
|
||
<div style="display:flex;flex-wrap:wrap;gap:6px">
|
||
<button class="ps-icon-btn" onclick="loadTemplate('qa')">Q&A Bot</button>
|
||
<button class="ps-icon-btn" onclick="loadTemplate('summariser')">Summariser</button>
|
||
<button class="ps-icon-btn" onclick="loadTemplate('extractor')">Extractor</button>
|
||
<button class="ps-icon-btn" onclick="loadTemplate('classifier')">Classifier</button>
|
||
<button class="ps-icon-btn" onclick="loadTemplate('coder')">Code Reviewer</button>
|
||
<button class="ps-icon-btn" onclick="loadTemplate('drafter')">Email Drafter</button>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
<div class="ps-panel-footer">
|
||
<button class="ps-run-btn" id="ps-run-btn" onclick="runPrompt()">
|
||
<span class="ps-run-icon">▶ Run</span>
|
||
<div class="ps-spinner"></div>
|
||
</button>
|
||
<button class="ps-save-btn" onclick="saveToLibrary()">📚 Save to Prompt Library</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── Middle: Output ── -->
|
||
<div class="ps-output-panel">
|
||
<div class="ps-output-header">
|
||
<span class="ps-output-title" id="ps-output-label">Output</span>
|
||
<div class="ps-stat-chips" id="ps-stat-chips" style="display:none">
|
||
<span class="ps-stat-chip green" id="ps-stat-time">–</span>
|
||
<span class="ps-stat-chip" id="ps-stat-tokens">–</span>
|
||
</div>
|
||
<div class="ps-output-actions">
|
||
<button class="ps-icon-btn" onclick="copyOutput()" title="Copy response">📋 Copy</button>
|
||
<button class="ps-icon-btn" onclick="sendToEval()" title="Send to Eval Suite">🧪 Eval</button>
|
||
<button class="ps-icon-btn" onclick="openCompare()" title="Compare with another model">⚖️ Compare</button>
|
||
</div>
|
||
</div>
|
||
<div class="ps-output-body" id="ps-output-body">
|
||
<div class="ps-output-empty" id="ps-empty-state">
|
||
<div class="ps-empty-icon">⚗️</div>
|
||
<p>Write a system prompt and message, then hit <strong>Run</strong>.</p>
|
||
<p style="font-size:12px;color:var(--lt)">Results appear here with token count and latency.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── Right: History ── -->
|
||
<div class="ps-history-panel">
|
||
<div class="ps-panel-header">
|
||
<span class="ps-panel-title">Run History</span>
|
||
<button class="ps-icon-btn" onclick="clearHistory()" style="font-size:11px">Clear</button>
|
||
</div>
|
||
<div class="ps-history-list" id="ps-history-list">
|
||
<div class="ps-history-empty" id="ps-history-empty">No runs yet. Results will appear here after you click Run.</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<div id="ps-toast"></div>
|
||
|
||
<script>
|
||
// ── State ───────────────────────────────────────────────────────────────────
|
||
let runHistory = JSON.parse(localStorage.getItem('cezen_ps_history') || '[]');
|
||
let currentRunId = null;
|
||
|
||
// ── Templates ────────────────────────────────────────────────────────────────
|
||
const TEMPLATES = {
|
||
qa: {
|
||
system: `You are a knowledgeable assistant for [Organisation]. Answer questions clearly and accurately based on the information provided. If you are unsure, say so rather than guessing. Keep answers concise — use bullet points for lists.`,
|
||
user: `What are the key steps in our procurement approval process?`,
|
||
model: 'llama3.1:8b', temp: 0.3
|
||
},
|
||
summariser: {
|
||
system: `You are a document summarisation assistant. When given text, produce a structured summary with: 1) A one-sentence overview, 2) Key points (max 5 bullets), 3) Any action items or deadlines mentioned. Be concise.`,
|
||
user: `Summarise the following document:\n\n[Paste document text here]`,
|
||
model: 'llama3.1:8b', temp: 0.3
|
||
},
|
||
extractor: {
|
||
system: `You are a data extraction assistant. Extract structured information from documents and return it as a clean JSON object. Only include fields explicitly present in the document. If a field is not found, omit it.`,
|
||
user: `Extract the following fields from this contract: vendor_name, contract_value, start_date, end_date, payment_terms, penalty_clauses.\n\nDocument:\n[Paste contract text here]`,
|
||
model: 'mistral:7b', temp: 0.1
|
||
},
|
||
classifier: {
|
||
system: `You are a document classification assistant. Classify the input into exactly one of these categories: POLICY, CONTRACT, INVOICE, REPORT, CORRESPONDENCE, TENDER, OTHER. Respond with only the category name and a one-sentence justification. Format: CATEGORY: [name]\nReason: [one sentence]`,
|
||
user: `Classify this document:\n\n[Paste document text here]`,
|
||
model: 'mistral:7b', temp: 0.1
|
||
},
|
||
coder: {
|
||
system: `You are a senior code reviewer. Review the provided code for: bugs, security issues, performance problems, and style violations. Structure your review as: SUMMARY, CRITICAL ISSUES, WARNINGS, SUGGESTIONS. Be specific — include line references where possible.`,
|
||
user: `Please review this code:\n\n\`\`\`python\n# Paste your code here\n\`\`\``,
|
||
model: 'codellama:34b', temp: 0.2
|
||
},
|
||
drafter: {
|
||
system: `You are a professional email drafting assistant for a government or PSU organisation. Write formal, clear, concise emails. Use polite but direct language. Always include: subject line, greeting, body, and sign-off. Avoid jargon.`,
|
||
user: `Draft an email to decline a vendor's proposal for the IT infrastructure upgrade project. The proposal was technically sound but exceeded our budget by 40%. Be polite and leave the door open for future engagement.`,
|
||
model: 'llama3.1:8b', temp: 0.5
|
||
}
|
||
};
|
||
|
||
function loadTemplate(name) {
|
||
const t = TEMPLATES[name];
|
||
document.getElementById('ps-system').value = t.system;
|
||
document.getElementById('ps-user').value = t.user;
|
||
document.getElementById('ps-model').value = t.model;
|
||
document.getElementById('ps-temp').value = t.temp;
|
||
document.getElementById('ps-temp-val').textContent = t.temp;
|
||
showToast('Template loaded');
|
||
}
|
||
|
||
// ── Mock responses ────────────────────────────────────────────────────────────
|
||
const MOCK_RESPONSES = [
|
||
`## Response
|
||
|
||
Based on the system prompt and your query, here is a structured response:
|
||
|
||
**Key Points:**
|
||
- The AI model has processed your system prompt and understood the role definition
|
||
- Temperature setting of {{temp}} produces {{temp_desc}} output
|
||
- Model **{{model}}** is well-suited for this task type
|
||
|
||
**Analysis:**
|
||
This prompt structure follows best practices for instruction-following models. The system prompt clearly defines the role and constraints, while the user message provides a specific, actionable request.
|
||
|
||
**Recommendation:**
|
||
For production use, consider:
|
||
1. Adding examples (few-shot) to the system prompt for consistent formatting
|
||
2. Specifying the exact output format expected
|
||
3. Testing edge cases where the AI might hallucinate
|
||
|
||
\`\`\`json
|
||
{
|
||
"prompt_quality": "high",
|
||
"clarity": 9,
|
||
"specificity": 8,
|
||
"suggested_temp": {{temp}}
|
||
}
|
||
\`\`\``,
|
||
|
||
`## Extracted Information
|
||
|
||
| Field | Value |
|
||
|-------|-------|
|
||
| Model | {{model}} |
|
||
| Temperature | {{temp}} |
|
||
| Task type | Text Analysis |
|
||
| Response quality | High |
|
||
|
||
**Summary:**
|
||
The query has been processed successfully. The system prompt establishes clear boundaries for the assistant's behaviour, and the user message provides sufficient context for an accurate response.
|
||
|
||
**Action Items:**
|
||
- Review the output against your expected format
|
||
- Adjust temperature if output is too creative (increase specificity) or too rigid (increase creativity)
|
||
- Save this prompt to the library if it performs well`,
|
||
|
||
`Thank you for this query. Let me provide a thorough response.
|
||
|
||
**Overview:** This is a demonstration response from the Nexus One AI system running **{{model}}** locally on your hardware. No data has left your network.
|
||
|
||
The system prompt you've written establishes the AI as a specialised assistant with clear constraints. This is a well-structured prompt that should produce consistent, reliable outputs in production.
|
||
|
||
**Prompt Quality Assessment:**
|
||
|
||
*Strengths:*
|
||
- Clear role definition
|
||
- Specific task scope
|
||
- Appropriate tone guidance
|
||
|
||
*Areas to refine:*
|
||
- Consider adding 1-2 example interactions (few-shot prompting)
|
||
- Specify output format explicitly (JSON, bullet points, prose)
|
||
- Add a fallback instruction for out-of-scope queries
|
||
|
||
> **Tip:** A temperature of {{temp}} is {{temp_desc}} for this type of task. For factual extraction, try 0.1-0.2. For creative writing, 0.7-0.9.`
|
||
];
|
||
|
||
function getMockResponse(model, temp) {
|
||
const idx = Math.floor(Math.random() * MOCK_RESPONSES.length);
|
||
const tempDesc = temp < 0.3 ? 'precise and deterministic' : temp > 0.7 ? 'creative and varied' : 'balanced';
|
||
return MOCK_RESPONSES[idx]
|
||
.replace(/{{model}}/g, model)
|
||
.replace(/{{temp}}/g, temp)
|
||
.replace(/{{temp_desc}}/g, tempDesc);
|
||
}
|
||
|
||
// ── Markdown renderer ─────────────────────────────────────────────────────────
|
||
function renderMd(raw) {
|
||
if (!raw) return '';
|
||
let html = raw
|
||
.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>')
|
||
.replace(/```(\w*)\n([\s\S]*?)```/g, (_,lang,code) =>
|
||
`<pre><code class="lang-${lang}">${code.trimEnd()}</code></pre>`)
|
||
.replace(/`([^`]+)`/g,'<code>$1</code>')
|
||
.replace(/^#{3}\s+(.+)$/gm,'<h3>$1</h3>')
|
||
.replace(/^#{2}\s+(.+)$/gm,'<h2>$1</h2>')
|
||
.replace(/^#{1}\s+(.+)$/gm,'<h1>$1</h1>')
|
||
.replace(/\*\*(.+?)\*\*/g,'<strong>$1</strong>')
|
||
.replace(/\*(.+?)\*/g,'<em>$1</em>')
|
||
.replace(/^>\s(.+)$/gm,'<blockquote>$1</blockquote>')
|
||
.replace(/^\|(.+)\|$/gm, row => {
|
||
const cells = row.split('|').filter((_,i,a) => i>0 && i<a.length-1);
|
||
return '<tr>' + cells.map(c => c.trim().match(/^[-:]+$/) ? '' : `<td>${c.trim()}</td>`).join('') + '</tr>';
|
||
})
|
||
.replace(/(<tr>.*?<\/tr>\n?)+/gs, t => `<table>${t}</table>`)
|
||
.replace(/<table>(<tr><\/tr>\n?)/g,'<table>')
|
||
.replace(/^[-*]\s+(.+)$/gm,'<li>$1</li>')
|
||
.replace(/(<li>.*<\/li>\n?)+/g, l => `<ul>${l}</ul>`)
|
||
.replace(/^\d+\.\s+(.+)$/gm,'<li>$1</li>')
|
||
.replace(/\n{2,}/g,'</p><p>')
|
||
.replace(/\n/g,'<br>');
|
||
return `<p>${html}</p>`;
|
||
}
|
||
|
||
// ── Run ───────────────────────────────────────────────────────────────────────
|
||
async function runPrompt() {
|
||
const system = document.getElementById('ps-system').value.trim();
|
||
const user = document.getElementById('ps-user').value.trim();
|
||
const model = document.getElementById('ps-model').value;
|
||
const temp = parseFloat(document.getElementById('ps-temp').value);
|
||
const maxTok = parseInt(document.getElementById('ps-maxtok').value);
|
||
|
||
if (!user) { showToast('Enter a user message first'); return; }
|
||
|
||
const btn = document.getElementById('ps-run-btn');
|
||
btn.classList.add('running'); btn.disabled = true;
|
||
|
||
document.getElementById('ps-empty-state')?.remove();
|
||
document.getElementById('ps-stat-chips').style.display = 'none';
|
||
|
||
const block = document.createElement('div');
|
||
block.className = 'ps-response-block';
|
||
block.innerHTML = '<span class="ps-streaming-cursor"></span>';
|
||
const body = document.getElementById('ps-output-body');
|
||
body.innerHTML = '';
|
||
body.appendChild(block);
|
||
|
||
document.getElementById('ps-output-label').textContent = `${model} — running…`;
|
||
|
||
const startTime = Date.now();
|
||
|
||
try {
|
||
const res = await fetch('/api/chat', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ model, system_prompt: system, message: user, temperature: temp, max_tokens: maxTok })
|
||
});
|
||
if (!res.ok) throw new Error('API error');
|
||
const data = await res.json();
|
||
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
||
const tokens = data.usage?.total_tokens || Math.floor(data.response?.length / 4) || 0;
|
||
renderOutput(block, data.response || '', model, elapsed, tokens);
|
||
addToHistory({ system, user, model, temp, response: data.response, elapsed, tokens });
|
||
} catch {
|
||
// Mock fallback
|
||
const mockText = getMockResponse(model, temp);
|
||
let i = 0;
|
||
const interval = setInterval(() => {
|
||
i = Math.min(i + Math.floor(Math.random()*8)+4, mockText.length);
|
||
block.innerHTML = renderMd(mockText.slice(0, i)) + (i < mockText.length ? '<span class="ps-streaming-cursor"></span>' : '');
|
||
body.scrollTop = body.scrollHeight;
|
||
if (i >= mockText.length) {
|
||
clearInterval(interval);
|
||
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
||
const tokens = Math.floor(mockText.length / 3.5);
|
||
renderOutput(block, mockText, model, elapsed, tokens);
|
||
addToHistory({ system, user, model, temp, response: mockText, elapsed, tokens });
|
||
btn.classList.remove('running'); btn.disabled = false;
|
||
}
|
||
}, 18);
|
||
return;
|
||
}
|
||
btn.classList.remove('running'); btn.disabled = false;
|
||
}
|
||
|
||
function renderOutput(block, text, model, elapsed, tokens) {
|
||
block.innerHTML = renderMd(text);
|
||
document.getElementById('ps-output-label').textContent = `${model}`;
|
||
const chips = document.getElementById('ps-stat-chips');
|
||
chips.style.display = 'flex';
|
||
document.getElementById('ps-stat-time').textContent = `${elapsed}s`;
|
||
document.getElementById('ps-stat-tokens').textContent = `~${tokens} tokens`;
|
||
}
|
||
|
||
// ── History ───────────────────────────────────────────────────────────────────
|
||
function addToHistory(run) {
|
||
run.id = Date.now();
|
||
run.ts = new Date().toLocaleTimeString([], {hour:'2-digit',minute:'2-digit'});
|
||
runHistory.unshift(run);
|
||
if (runHistory.length > 50) runHistory.pop();
|
||
localStorage.setItem('cezen_ps_history', JSON.stringify(runHistory));
|
||
renderHistory();
|
||
}
|
||
|
||
function renderHistory() {
|
||
const list = document.getElementById('ps-history-list');
|
||
if (!runHistory.length) {
|
||
list.innerHTML = '<div class="ps-history-empty" id="ps-history-empty">No runs yet.</div>';
|
||
return;
|
||
}
|
||
list.innerHTML = runHistory.map(r => `
|
||
<div class="ps-history-item ${r.id === currentRunId ? 'active' : ''}" onclick="loadRun(${r.id})">
|
||
<div class="ps-history-item-header">
|
||
<span class="ps-history-model">${r.model.split(':')[0]}</span>
|
||
<span class="ps-history-time">${r.ts}</span>
|
||
</div>
|
||
<div class="ps-history-prompt">${r.user.slice(0,70)}${r.user.length>70?'…':''}</div>
|
||
<div class="ps-history-stats">
|
||
<span class="ps-history-stat">🕐 ${r.elapsed}s</span>
|
||
<span class="ps-history-stat">🔤 ~${r.tokens} tok</span>
|
||
<span class="ps-history-stat">🌡 ${r.temp}</span>
|
||
</div>
|
||
</div>
|
||
`).join('');
|
||
}
|
||
|
||
function loadRun(id) {
|
||
const run = runHistory.find(r => r.id === id);
|
||
if (!run) return;
|
||
currentRunId = id;
|
||
document.getElementById('ps-system').value = run.system;
|
||
document.getElementById('ps-user').value = run.user;
|
||
document.getElementById('ps-model').value = run.model;
|
||
document.getElementById('ps-temp').value = run.temp;
|
||
document.getElementById('ps-temp-val').textContent = run.temp;
|
||
const body = document.getElementById('ps-output-body');
|
||
const block = document.createElement('div');
|
||
block.className = 'ps-response-block';
|
||
block.innerHTML = renderMd(run.response);
|
||
body.innerHTML = '';
|
||
body.appendChild(block);
|
||
document.getElementById('ps-output-label').textContent = run.model;
|
||
document.getElementById('ps-stat-chips').style.display = 'flex';
|
||
document.getElementById('ps-stat-time').textContent = `${run.elapsed}s`;
|
||
document.getElementById('ps-stat-tokens').textContent = `~${run.tokens} tokens`;
|
||
renderHistory();
|
||
}
|
||
|
||
function clearHistory() {
|
||
runHistory = [];
|
||
localStorage.removeItem('cezen_ps_history');
|
||
renderHistory();
|
||
}
|
||
|
||
// ── Utilities ─────────────────────────────────────────────────────────────────
|
||
function clearAll() {
|
||
document.getElementById('ps-system').value = '';
|
||
document.getElementById('ps-user').value = '';
|
||
document.getElementById('ps-output-body').innerHTML = `
|
||
<div class="ps-output-empty" id="ps-empty-state">
|
||
<div class="ps-empty-icon">⚗️</div>
|
||
<p>Write a system prompt and message, then hit <strong>Run</strong>.</p>
|
||
<p style="font-size:12px;color:var(--lt)">Results appear here with token count and latency.</p>
|
||
</div>`;
|
||
document.getElementById('ps-stat-chips').style.display = 'none';
|
||
document.getElementById('ps-output-label').textContent = 'Output';
|
||
}
|
||
|
||
function copyOutput() {
|
||
const block = document.querySelector('.ps-response-block');
|
||
if (!block) { showToast('Nothing to copy'); return; }
|
||
navigator.clipboard.writeText(block.innerText).then(() => showToast('Copied to clipboard'));
|
||
}
|
||
|
||
function sendToEval() {
|
||
const user = document.getElementById('ps-user').value;
|
||
const model = document.getElementById('ps-model').value;
|
||
if (!user) { showToast('Run a prompt first'); return; }
|
||
localStorage.setItem('cezen_eval_import', JSON.stringify({ input: user, model }));
|
||
window.location.href = 'evals.html';
|
||
}
|
||
|
||
function openCompare() {
|
||
const system = document.getElementById('ps-system').value;
|
||
const user = document.getElementById('ps-user').value;
|
||
if (!user) { showToast('Enter a message first'); return; }
|
||
localStorage.setItem('cezen_compare_import', JSON.stringify({ system, user }));
|
||
window.location.href = 'model-compare.html';
|
||
}
|
||
|
||
function saveToLibrary() {
|
||
const system = document.getElementById('ps-system').value.trim();
|
||
const user = document.getElementById('ps-user').value.trim();
|
||
if (!system && !user) { showToast('Nothing to save'); return; }
|
||
const library = JSON.parse(localStorage.getItem('cezen_prompts_custom') || '[]');
|
||
library.push({ id: Date.now(), title: user.slice(0,50) || 'Untitled', system, content: user, saved_from: 'studio', ts: new Date().toISOString() });
|
||
localStorage.setItem('cezen_prompts_custom', JSON.stringify(library));
|
||
showToast('Saved to Prompt Library');
|
||
}
|
||
|
||
function handleKey(e) {
|
||
if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) runPrompt();
|
||
}
|
||
|
||
function showToast(msg) {
|
||
const t = document.getElementById('ps-toast');
|
||
t.textContent = msg; t.classList.add('show');
|
||
setTimeout(() => t.classList.remove('show'), 2200);
|
||
}
|
||
|
||
// ── Init ──────────────────────────────────────────────────────────────────────
|
||
renderHistory();
|
||
// Load compare import if arriving from model-compare
|
||
const compareImport = localStorage.getItem('cezen_studio_import');
|
||
if (compareImport) {
|
||
const d = JSON.parse(compareImport);
|
||
if (d.system) document.getElementById('ps-system').value = d.system;
|
||
if (d.user) document.getElementById('ps-user').value = d.user;
|
||
if (d.model) document.getElementById('ps-model').value = d.model;
|
||
localStorage.removeItem('cezen_studio_import');
|
||
}
|
||
</script>
|
||
|
||
<script src="auth.js"></script>
|
||
<script src="branding.js"></script>
|
||
</body>
|
||
</html>
|