<?php
// ask-deepseek-coding.php
// Minimal coding-focused DeepSeek client that only sends:
// - a system rule
// - the saved "working code doc" (optional)
// - the current prompt
// No rolling conversation history.
session_start();
// === CONFIG ===
$DEEPSEEK_API_KEY = getenv('DEEPSEEK_API_KEY') ?: 'sk-b1d3560509194a4182ace023c083476a';
$API_URL = 'https://api.deepseek.com/chat/completions';
$DEFAULT_MODEL = 'deepseek-chat'; // or 'deepseek-reasoner'
$DEFAULT_TEMPERATURE = 0.4; // lower for coding determinism
$DEFAULT_MAXTOKENS = 800; // your cap
// Session bucket for working code, artifacts, and conversation history
if (!isset($_SESSION['working_code_doc'])) $_SESSION['working_code_doc'] = '';
if (!isset($_SESSION['artifacts'])) $_SESSION['artifacts'] = [];
if (!isset($_SESSION['conversation_history'])) $_SESSION['conversation_history'] = [];
// Helpers
function h($s){ return htmlspecialchars($s ?? '', ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); }
function render_markdown_with_code_separators($text) {
$text = str_replace(["\r\n", "\r"], "\n", $text);
$pat = '/```([a-zA-Z0-9_\-]+)?\s*\n([\s\S]*?)```/m';
$html=''; $pos=0;
while (preg_match($pat,$text,$m,PREG_OFFSET_CAPTURE,$pos)) {
$start=$m[0][1]; $len=strlen($m[0][0]); $lang=$m[1][0]??''; $code=$m[2][0]??'';
$before = substr($text,$pos,$start-$pos);
if ($before!=='') $html.='<div class="md-p">'.nl2br(h($before)).'</div>';
$html.='<div class="code-sep"></div>';
$html.='<div class="codeblock">'.($lang?'<div class="code-lang">'.h($lang).'</div>':'')
.'<pre><code>'.h($code).'</code></pre></div>';
$pos = $start+$len;
}
if ($pos < strlen($text)) {
$tail = substr($text,$pos);
if ($tail!=='') $html.='<div class="md-p">'.nl2br(h($tail)).'</div>';
}
if ($html==='') $html = '<div class="md-p">'.nl2br(h($text)).'</div>';
return $html;
}
// Handle actions
$error = null; $answer = null; $rawJson = null; $usage = null;
$action = $_POST['action'] ?? '';
if ($action === 'save_working') {
$_SESSION['working_code_doc'] = $_POST['working_code_doc'] ?? '';
}
if ($action === 'clear_working') {
$_SESSION['working_code_doc'] = '';
}
if ($action === 'clear_history') {
$_SESSION['conversation_history'] = [];
}
if ($action === 'save_artifact') {
$artifactCode = $_POST['artifact_code'] ?? '';
$artifactName = trim($_POST['artifact_name'] ?? '') ?: 'Artifact ' . (count($_SESSION['artifacts']) + 1);
if ($artifactCode !== '') {
$artifact = [
'id' => uniqid(),
'name' => $artifactName,
'code' => $artifactCode,
'timestamp' => time()
];
$_SESSION['artifacts'][] = $artifact;
$_SESSION['working_code_doc'] = $artifactCode; // Make it current
}
}
if ($action === 'make_current') {
$artifactId = $_POST['artifact_id'] ?? '';
foreach ($_SESSION['artifacts'] as $artifact) {
if ($artifact['id'] === $artifactId) {
$_SESSION['working_code_doc'] = $artifact['code'];
break;
}
}
}
if ($action === 'delete_artifact') {
$artifactId = $_POST['artifact_id'] ?? '';
$_SESSION['artifacts'] = array_filter($_SESSION['artifacts'], function($artifact) use ($artifactId) {
return $artifact['id'] !== $artifactId;
});
$_SESSION['artifacts'] = array_values($_SESSION['artifacts']); // Re-index
}
if ($action === 'ask') {
$question = trim($_POST['question'] ?? '');
$model = $_POST['model'] ?? $DEFAULT_MODEL;
$maxTokens = max(50, min(8000, (int)($_POST['max_tokens'] ?? $DEFAULT_MAXTOKENS)));
$temperature = max(0.0, min(2.0, (float)($_POST['temperature'] ?? $DEFAULT_TEMPERATURE)));
$includeCode = isset($_POST['include_working']) ? true : false;
$codeStyle = $_POST['code_response_style'] ?? 'complete';
if ($DEEPSEEK_API_KEY === 'REPLACE_WITH_YOUR_KEY' || $DEEPSEEK_API_KEY === '') {
$error = 'Missing API key. Set DEEPSEEK_API_KEY on the server.';
} elseif ($question === '') {
$error = 'Please enter a prompt.';
} else {
// Build minimal message list: system -> (optional code doc) -> user prompt
$systemPrompt = "You are a meticulous coding assistant. Only use the provided 'working code doc' as context. " .
"Do not invent prior history. ";
if ($codeStyle === 'changes_only') {
$systemPrompt .= "When modifying existing code, show ONLY the specific changes needed - use concise diffs, " .
"highlight the modified sections, or show just the functions/blocks that need updates. " .
"Avoid repeating unchanged code unless necessary for context.";
} else {
$systemPrompt .= "When modifying code, provide the complete updated file or function. " .
"Show the full code that the user can copy and use directly.";
}
$messages = [
['role'=>'system','content'=>$systemPrompt]
];
if ($includeCode && $_SESSION['working_code_doc'] !== '') {
// Keep it short by wrapping in a label + fenced code
$messages[] = [
'role' => 'system',
'content' => "CURRENT WORKING CODE DOC (single file):\n```text\n" .
$_SESSION['working_code_doc'] . "\n```"
];
}
$messages[] = ['role'=>'user','content'=>$question];
$payload = [
'model' => $model,
'messages' => $messages,
'temperature' => $temperature,
'max_tokens' => $maxTokens,
// 'stream' => false,
];
$ch = curl_init($API_URL);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Authorization: ' . 'Bearer ' . $DEEPSEEK_API_KEY,
],
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 120,
]);
$raw = curl_exec($ch);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$cerr = curl_error($ch);
curl_close($ch);
if ($cerr) {
$error = 'cURL error: ' . $cerr;
} elseif ($http < 200 || $http >= 300) {
$error = "HTTP $http: " . $raw;
} else {
$json = json_decode($raw, true);
$rawJson = $json;
$answer = $json['choices'][0]['message']['content'] ?? '(no content)';
$usage = $json['usage'] ?? null;
// Save to conversation history (but don't send history to AI)
$historyEntry = [
'timestamp' => time(),
'question' => $question,
'answer' => $answer,
'model' => $model,
'usage' => $usage,
'included_code' => $includeCode,
'code_style' => $codeStyle
];
$_SESSION['conversation_history'][] = $historyEntry;
// Keep only last 50 entries to prevent session bloat
if (count($_SESSION['conversation_history']) > 50) {
$_SESSION['conversation_history'] = array_slice($_SESSION['conversation_history'], -50);
}
}
}
}
// Sticky UI
$stickyQuestion = $_POST['question'] ?? '';
$stickyModel = $_POST['model'] ?? $DEFAULT_MODEL;
$stickyTemp = $_POST['temperature'] ?? $DEFAULT_TEMPERATURE;
$stickyMaxTokens = (int)($_POST['max_tokens'] ?? $DEFAULT_MAXTOKENS);
$workingDoc = $_SESSION['working_code_doc'];
$stickyInclude = isset($_POST['include_working']) ? 'checked' : 'checked'; // default ON
$stickyCodeStyle = $_POST['code_response_style'] ?? 'complete'; // 'complete' or 'changes_only'
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>DeepSeek Coding (prompt + working doc only)</title>
<style>
:root{--card:#fafafa;--br:#e6e6e6;--sep:#d0d7de;--ink:#111;--muted:#666;--overlay-bg:rgba(0,0,0,0.5)}
body{font-family:system-ui,Segoe UI,Roboto,Helvetica,Arial,sans-serif;margin:2rem;max-width:1000px;color:var(--ink);padding-bottom:120px}
h1{margin:0 0 .5rem}
.header{display:flex;justify-content:space-between;align-items:center;margin-bottom:1rem}
.nav-buttons{display:flex;gap:.5rem}
.nav-btn{padding:.5rem .75rem;border-radius:8px;border:1px solid var(--br);background:#fff;cursor:pointer;font-size:.9rem}
.nav-btn:hover{border-color:#2f6feb}
/* Fixed bottom question area */
.question-area{position:fixed;bottom:0;left:0;right:0;background:#fff;border-top:1px solid var(--br);padding:1rem;box-shadow:0 -2px 10px rgba(0,0,0,0.1)}
.question-form{display:flex;gap:.75rem;align-items:center;max-width:1000px;margin:0 auto}
.question-input{flex:1;padding:.75rem;border:1px solid var(--br);border-radius:8px;font-size:1rem}
.send-btn{padding:.75rem 1.5rem;border-radius:8px;border:1px solid var(--br);background:#2f6feb;color:#fff;cursor:pointer;font-weight:500}
.send-btn:hover{background:#1a5feb}
/* Overlay styles */
.overlay{position:fixed;top:0;left:0;right:0;bottom:0;background:var(--overlay-bg);display:none;align-items:center;justify-content:center;z-index:1000}
.overlay-content{background:#fff;border-radius:12px;padding:2rem;max-width:90vw;max-height:90vh;overflow:auto;box-shadow:0 10px 30px rgba(0,0,0,0.3)}
.code-overlay{width:95vw;height:90vh}
.code-layout{display:flex;flex-direction:column;gap:1rem;height:calc(90vh - 6rem)}
/* Artifacts panel - now stacked on top */
.artifacts-panel{border-bottom:1px solid var(--br);padding-bottom:1rem;max-height:35vh;overflow-y:auto;flex-shrink:0}
.artifacts-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:0.75rem}
.artifact-item{border:1px solid var(--br);border-radius:8px;padding:0.75rem;background:#f9f9f9;cursor:pointer}
.artifact-item:hover{background:#f0f0f0}
.artifact-item.current{background:#e3f2fd;border-color:#2196f3}
.artifact-name{font-weight:500;margin-bottom:0.25rem;font-size:0.9rem}
.artifact-meta{font-size:0.75rem;color:var(--muted)}
.artifact-actions{display:flex;gap:0.25rem;margin-top:0.5rem}
.artifact-btn{padding:0.25rem 0.5rem;font-size:0.75rem;border:1px solid var(--br);background:#fff;border-radius:4px;cursor:pointer}
.artifact-btn:hover{border-color:#2f6feb}
/* Code editor - now takes remaining space at bottom */
.code-editor{display:flex;flex-direction:column;flex:1;min-height:0}
.editor-header{margin-bottom:1rem;flex-shrink:0}
.editor-textarea{flex:1;min-height:300px;resize:vertical}
.overlay-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:1rem}
.close-btn{background:none;border:none;font-size:1.5rem;cursor:pointer;color:var(--muted)}
.close-btn:hover{color:var(--ink)}
textarea{min-height:120px;padding:.75rem;font-size:1rem;width:100%;box-sizing:border-box}
textarea.code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
select,input[type="number"]{padding:.5rem .6rem;font-size:1rem}
button{padding:.6rem .9rem;border-radius:10px;border:1px solid var(--br);background:#fff;cursor:pointer}
button:hover{border-color:#2f6feb}
.card{border:1px solid var(--br);border-radius:14px;padding:1rem;margin-top:1rem;background:var(--card)}
.meta{color:var(--muted);font-size:.9rem}
.md-p{margin:.4rem 0;line-height:1.45}
.code-sep{height:10px;border-top:3px double var(--sep);margin:.8rem 0}
.codeblock{border:1px solid var(--sep);border-radius:10px;background:#fff}
.code-lang{font-size:.8rem;color:var(--muted);padding:.4rem .6rem;border-bottom:1px solid var(--sep);background:#f6f8fa;border-top-left-radius:10px;border-top-right-radius:10px}
pre{margin:0;padding:.75rem;overflow:auto;white-space:pre}
code{font-size:.95rem}
.settings-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:1rem;margin-bottom:1rem}
.overlay-actions{display:flex;gap:.75rem;justify-content:flex-end;margin-top:1rem}
/* Responsive adjustments */
@media (max-width: 768px) {
.artifacts-grid{grid-template-columns:1fr}
.artifacts-panel{max-height:30vh}
}
</style>
</head>
<body>
<div class="header">
<div>
<h1>DeepSeek Coding</h1>
<p class="meta">Each request uses only the <strong>working code doc</strong> (optional) + your <strong>current prompt</strong>. No full chat memory.</p>
</div>
<div class="nav-buttons">
<button class="nav-btn" onclick="showHistoryOverlay()">History (<?= count($_SESSION['conversation_history']) ?>)</button>
<button class="nav-btn" onclick="showCodeOverlay()">Code Artifacts (<?= count($_SESSION['artifacts']) ?>)</button>
<button class="nav-btn" onclick="showSettingsOverlay()">Settings</button>
</div>
</div>
<!-- Main content area for responses -->
<?php if ($error): ?>
<div class="card" style="color:#b00020"><strong>Error:</strong> <?= h($error) ?></div>
<?php endif; ?>
<?php if ($answer): ?>
<div class="card">
<h3>Answer</h3>
<div><?= render_markdown_with_code_separators($answer) ?></div>
<?php if ($rawJson): ?>
<details><summary>Raw JSON</summary>
<pre><code><?= h(json_encode($rawJson, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES)) ?></code></pre>
</details>
<?php endif; ?>
<?php if ($usage): ?>
<div class="meta" style="margin-top:.5rem">
<strong>Usage:</strong>
prompt_tokens = <?= (int)($usage['prompt_tokens'] ?? 0) ?>,
completion_tokens = <?= (int)($usage['completion_tokens'] ?? 0) ?>,
total_tokens = <?= (int)($usage['total_tokens'] ?? 0) ?>
</div>
<?php endif; ?>
<div style="margin-top:1rem">
<button onclick="saveToArtifacts()" class="nav-btn">Add to Artifacts</button>
</div>
</div>
<?php endif; ?>
<!-- Show recent conversation history -->
<?php if (!empty($_SESSION['conversation_history'])): ?>
<div class="card">
<h3>Recent Conversation</h3>
<p class="meta">Showing last <?= min(3, count($_SESSION['conversation_history'])) ?> exchanges • <a href="#" onclick="showHistoryOverlay(); return false;">View full history</a></p>
<?php
$recentHistory = array_slice($_SESSION['conversation_history'], -3);
foreach ($recentHistory as $entry):
?>
<div style="border-left:3px solid #e6e6e6;padding-left:1rem;margin:1rem 0">
<div class="meta" style="margin-bottom:.5rem">
<?= date('M j, g:i A', $entry['timestamp']) ?> •
<?= h($entry['model']) ?> •
<?= $entry['included_code'] ? 'with code' : 'no code' ?> •
<?= ($entry['code_style'] ?? 'complete') === 'complete' ? 'full code' : 'changes only' ?>
<?php if ($entry['usage']): ?>
• <?= (int)($entry['usage']['total_tokens'] ?? 0) ?> tokens
<?php endif; ?>
</div>
<div style="font-weight:500;margin-bottom:.5rem">Q: <?= h($entry['question']) ?></div>
<div style="font-size:.9rem"><?= render_markdown_with_code_separators($entry['answer']) ?></div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
<div class="card">
<h3>How it works</h3>
<ul>
<li>We do <em>not</em> resend prior turns. Only the <strong>system rule</strong>, optional <strong>working code doc</strong>, and your <strong>current prompt</strong> are included.</li>
<li>Use a single-file "working doc." If you need multi-file context, paste the relevant parts or switch to a short summary of the non-active files to save tokens.</li>
<li>Lower <code>temperature</code> (e.g., 0.2–0.5) for more deterministic code.</li>
<li>Adjust <code>max_tokens</code> to cap output length (your real usage prints above).</li>
</ul>
</div>
<!-- Fixed bottom question area -->
<div class="question-area">
<form method="post" class="question-form" id="mainForm">
<input type="hidden" name="model" id="hiddenModel" value="<?= h($stickyModel) ?>">
<input type="hidden" name="max_tokens" id="hiddenMaxTokens" value="<?= (int)$stickyMaxTokens ?>">
<input type="hidden" name="temperature" id="hiddenTemperature" value="<?= h($stickyTemp) ?>">
<input type="hidden" name="include_working" id="hiddenIncludeWorking" value="<?= $stickyInclude ? '1' : '0' ?>">
<input type="hidden" name="code_response_style" id="hiddenCodeStyle" value="<?= h($stickyCodeStyle) ?>">
<input type="hidden" name="working_code_doc" id="hiddenWorkingDoc" value="<?= h($workingDoc) ?>">
<input type="text" name="question" class="question-input" placeholder="Describe the change, ask for a fix, or request a new function..." value="<?= $action === 'ask' ? '' : h($stickyQuestion) ?>" autofocus>
<button type="submit" name="action" value="ask" class="send-btn">Send</button>
</form>
</div>
<!-- History Overlay -->
<div class="overlay" id="historyOverlay">
<div class="overlay-content code-overlay">
<div class="overlay-header">
<h3>Conversation History</h3>
<button class="close-btn" onclick="hideHistoryOverlay()">×</button>
</div>
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:1rem">
<p class="meta">Total conversations: <?= count($_SESSION['conversation_history']) ?></p>
<form method="post" style="display:inline">
<button type="submit" name="action" value="clear_history" class="nav-btn" style="background:#dc3545;color:#fff" onclick="return confirm('Clear all conversation history?')">Clear History</button>
</form>
</div>
<div style="max-height:70vh;overflow-y:auto">
<?php if (empty($_SESSION['conversation_history'])): ?>
<p class="meta">No conversation history yet. Start by asking a question!</p>
<?php else: ?>
<?php foreach (array_reverse($_SESSION['conversation_history']) as $index => $entry): ?>
<div class="card" style="margin-bottom:1rem">
<div style="display:flex;justify-content:space-between;align-items:start;margin-bottom:.5rem">
<div class="meta">
<?= date('M j, Y g:i A', $entry['timestamp']) ?> •
<?= h($entry['model']) ?> •
<?= $entry['included_code'] ? 'with code context' : 'no code context' ?> •
<?= ($entry['code_style'] ?? 'complete') === 'complete' ? 'full code responses' : 'changes only' ?>
<?php if ($entry['usage']): ?>
• <?= (int)($entry['usage']['total_tokens'] ?? 0) ?> tokens
<?php endif; ?>
</div>
<button onclick="restoreQuestion('<?= h(addslashes($entry['question'])) ?>')" class="artifact-btn">Restore Question</button>
</div>
<div style="background:#f8f9fa;padding:.75rem;border-radius:6px;margin-bottom:.75rem">
<strong>Question:</strong> <?= h($entry['question']) ?>
</div>
<div style="border-left:3px solid #2f6feb;padding-left:1rem">
<strong>Answer:</strong>
<div style="margin-top:.5rem"><?= render_markdown_with_code_separators($entry['answer']) ?></div>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
</div>
</div>
<!-- Code Doc Overlay -->
<div class="overlay" id="codeOverlay">
<div class="overlay-content code-overlay">
<div class="overlay-header">
<h3>Code Artifacts</h3>
<button class="close-btn" onclick="hideCodeOverlay()">×</button>
</div>
<div class="code-layout">
<!-- Artifacts Panel (Top) -->
<div class="artifacts-panel">
<h4>Saved Artifacts (<?= count($_SESSION['artifacts']) ?>)</h4>
<div style="margin-bottom:1rem;font-size:0.8rem;color:var(--muted)">
Debug: Session has <?= count($_SESSION['artifacts']) ?> artifacts
<?php if (!empty($_SESSION['artifacts'])): ?>
- First artifact: "<?= h($_SESSION['artifacts'][0]['name'] ?? 'unknown') ?>"
<?php endif; ?>
</div>
<?php if (empty($_SESSION['artifacts'])): ?>
<p class="meta">No artifacts saved yet. Use "Add to Artifacts" button after getting code from DeepSeek.</p>
<?php else: ?>
<div class="artifacts-grid">
<?php foreach ($_SESSION['artifacts'] as $index => $artifact): ?>
<div class="artifact-item <?= $artifact['code'] === $workingDoc ? 'current' : '' ?>" data-id="<?= h($artifact['id']) ?>">
<div class="artifact-name"><?= h($artifact['name']) ?> (#<?= $index + 1 ?>)</div>
<div class="artifact-meta"><?= date('M j, g:i A', $artifact['timestamp']) ?></div>
<div class="artifact-meta" style="font-size:0.7rem">ID: <?= h(substr($artifact['id'], 0, 8)) ?>...</div>
<div class="artifact-actions">
<form method="post" style="display:inline">
<input type="hidden" name="artifact_id" value="<?= h($artifact['id']) ?>">
<button type="submit" name="action" value="make_current" class="artifact-btn">Make Current</button>
</form>
<form method="post" style="display:inline">
<input type="hidden" name="artifact_id" value="<?= h($artifact['id']) ?>">
<button type="submit" name="action" value="delete_artifact" class="artifact-btn" style="color:#d73502" onclick="return confirm('Delete this artifact?')">Delete</button>
</form>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
<!-- Code Editor (Bottom) -->
<div class="code-editor">
<div class="editor-header">
<h4>Current Working Code</h4>
<p class="meta">This code will be sent as context with your prompts</p>
</div>
<form method="post" style="height:100%;display:flex;flex-direction:column" id="codeForm">
<textarea class="code editor-textarea" name="working_code_doc" id="workingCodeDoc" placeholder="// Paste your current single-file code here..."><?= h($workingDoc) ?></textarea>
<div class="overlay-actions" style="margin-top:1rem">
<button type="submit" name="action" value="clear_working">Clear</button>
<button type="submit" name="action" value="save_working">Save Working Code</button>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- Settings Overlay -->
<div class="overlay" id="settingsOverlay">
<div class="overlay-content">
<div class="overlay-header">
<h3>Settings</h3>
<button class="close-btn" onclick="hideSettingsOverlay()">×</button>
</div>
<div class="settings-grid">
<label>Model
<select id="modelSelect">
<option value="deepseek-chat" <?= $stickyModel==='deepseek-chat'?'selected':''; ?>>deepseek-chat</option>
<option value="deepseek-reasoner" <?= $stickyModel==='deepseek-reasoner'?'selected':''; ?>>deepseek-reasoner (R1-style)</option>
</select>
</label>
<label>Max tokens
<select id="maxTokensSelect">
<?php foreach ([200,500,800,1000,1500,2000,4000,6000,8000] as $c): ?>
<option value="<?= (int)$c ?>" <?= $stickyMaxTokens==$c?'selected':''; ?>><?= (int)$c ?></option>
<?php endforeach; ?>
</select>
</label>
<label>Temperature
<input id="temperatureInput" type="number" step="0.1" min="0" max="2" value="<?= h($stickyTemp) ?>">
</label>
</div>
<label style="margin:1rem 0;display:block">
<input type="checkbox" id="includeWorkingCheck" <?= $stickyInclude ?>> Include working code doc
</label>
<div style="margin:1rem 0">
<label style="display:block;margin-bottom:.5rem;font-weight:500">Code Response Style</label>
<label style="display:block;margin-bottom:.5rem">
<input type="radio" name="code_style" id="codeStyleComplete" value="complete" <?= $stickyCodeStyle === 'complete' ? 'checked' : '' ?>>
<strong>Complete Code</strong> - Return full updated files/functions (easier to copy-paste)
</label>
<label style="display:block">
<input type="radio" name="code_style" id="codeStyleChanges" value="changes_only" <?= $stickyCodeStyle === 'changes_only' ? 'checked' : '' ?>>
<strong>Changes Only</strong> - Show only diffs/modifications (saves tokens, faster responses)
</label>
</div>
<div class="overlay-actions">
<button onclick="hideSettingsOverlay()">Close</button>
</div>
</div>
</div>
<script>
function restoreQuestion(question) {
hideHistoryOverlay();
document.querySelector('.question-input').value = question;
document.querySelector('.question-input').focus();
}
function showHistoryOverlay() {
document.getElementById('historyOverlay').style.display = 'flex';
}
function hideHistoryOverlay() {
document.getElementById('historyOverlay').style.display = 'none';
}
function saveToArtifacts() {
// Find the answer section
const answerElements = document.querySelectorAll('.card h3');
let answerSection = null;
answerElements.forEach(el => {
if (el.textContent.trim() === 'Answer') {
answerSection = el;
}
});
if (!answerSection) {
alert('No answer found to save.');
return;
}
// Extract code blocks from the answer
const codeBlocks = answerSection.parentElement.querySelectorAll('.codeblock pre code');
if (codeBlocks.length === 0) {
alert('No code blocks found in the answer to save.');
return;
}
// If multiple code blocks, take the largest one
let selectedCode = '';
let maxLength = 0;
codeBlocks.forEach(block => {
if (block.textContent.length > maxLength) {
maxLength = block.textContent.length;
selectedCode = block.textContent;
}
});
// Prompt for artifact name
const artifactName = prompt('Enter a name for this artifact:', 'Code ' + new Date().toLocaleTimeString());
if (!artifactName) return;
// Create form and submit
const form = document.createElement('form');
form.method = 'post';
form.style.display = 'none';
const actionInput = document.createElement('input');
actionInput.type = 'hidden';
actionInput.name = 'action';
actionInput.value = 'save_artifact';
const codeInput = document.createElement('input');
codeInput.type = 'hidden';
codeInput.name = 'artifact_code';
codeInput.value = selectedCode;
const nameInput = document.createElement('input');
nameInput.type = 'hidden';
nameInput.name = 'artifact_name';
nameInput.value = artifactName;
form.appendChild(actionInput);
form.appendChild(codeInput);
form.appendChild(nameInput);
document.body.appendChild(form);
form.submit();
}
function showCodeOverlay() {
document.getElementById('codeOverlay').style.display = 'flex';
}
function hideCodeOverlay() {
document.getElementById('codeOverlay').style.display = 'none';
// Sync the working doc to hidden field
document.getElementById('hiddenWorkingDoc').value = document.getElementById('workingCodeDoc').value;
}
function showSettingsOverlay() {
document.getElementById('settingsOverlay').style.display = 'flex';
}
function hideSettingsOverlay() {
document.getElementById('settingsOverlay').style.display = 'none';
// Sync all settings to hidden fields
document.getElementById('hiddenModel').value = document.getElementById('modelSelect').value;
document.getElementById('hiddenMaxTokens').value = document.getElementById('maxTokensSelect').value;
document.getElementById('hiddenTemperature').value = document.getElementById('temperatureInput').value;
document.getElementById('hiddenIncludeWorking').value = document.getElementById('includeWorkingCheck').checked ? '1' : '0';
document.getElementById('hiddenCodeStyle').value = document.querySelector('input[name="code_style"]:checked')?.value || 'complete';
// Save settings to localStorage
localStorage.setItem('deepseek_settings', JSON.stringify({
model: document.getElementById('modelSelect').value,
maxTokens: document.getElementById('maxTokensSelect').value,
temperature: document.getElementById('temperatureInput').value,
includeWorking: document.getElementById('includeWorkingCheck').checked,
codeStyle: document.querySelector('input[name="code_style"]:checked')?.value || 'complete'
}));
}
// Close overlays when clicking outside
document.getElementById('historyOverlay').addEventListener('click', function(e) {
if (e.target === this) hideHistoryOverlay();
});
document.getElementById('codeOverlay').addEventListener('click', function(e) {
if (e.target === this) hideCodeOverlay();
});
document.getElementById('settingsOverlay').addEventListener('click', function(e) {
if (e.target === this) hideSettingsOverlay();
});
// Close overlays with Escape key
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
hideHistoryOverlay();
hideCodeOverlay();
hideSettingsOverlay();
}
});
// Load saved settings on page load
document.addEventListener('DOMContentLoaded', function() {
const savedSettings = localStorage.getItem('deepseek_settings');
if (savedSettings) {
try {
const settings = JSON.parse(savedSettings);
if (document.getElementById('modelSelect')) {
document.getElementById('modelSelect').value = settings.model || '<?= h($stickyModel) ?>';
document.getElementById('maxTokensSelect').value = settings.maxTokens || '<?= (int)$stickyMaxTokens ?>';
document.getElementById('temperatureInput').value = settings.temperature || '<?= h($stickyTemp) ?>';
document.getElementById('includeWorkingCheck').checked = settings.includeWorking !== undefined ? settings.includeWorking : <?= $stickyInclude ? 'true' : 'false' ?>;
// Set code style radio buttons
const codeStyleRadios = document.querySelectorAll('input[name="code_style"]');
const savedCodeStyle = settings.codeStyle || '<?= h($stickyCodeStyle) ?>';
codeStyleRadios.forEach(radio => {
if (radio.value === savedCodeStyle) {
radio.checked = true;
}
});
// Update hidden fields too
document.getElementById('hiddenModel').value = settings.model || '<?= h($stickyModel) ?>';
document.getElementById('hiddenMaxTokens').value = settings.maxTokens || '<?= (int)$stickyMaxTokens ?>';
document.getElementById('hiddenTemperature').value = settings.temperature || '<?= h($stickyTemp) ?>';
document.getElementById('hiddenIncludeWorking').value = (settings.includeWorking !== undefined ? settings.includeWorking : <?= $stickyInclude ? 'true' : 'false' ?>) ? '1' : '0';
document.getElementById('hiddenCodeStyle').value = settings.codeStyle || '<?= h($stickyCodeStyle) ?>';
}
} catch(e) {
console.log('Error loading settings:', e);
}
}
});
// Update hidden fields when settings change
document.getElementById('modelSelect')?.addEventListener('change', function() {
document.getElementById('hiddenModel').value = this.value;
});
document.getElementById('maxTokensSelect')?.addEventListener('change', function() {
document.getElementById('hiddenMaxTokens').value = this.value;
});
document.getElementById('temperatureInput')?.addEventListener('change', function() {
document.getElementById('hiddenTemperature').value = this.value;
});
document.getElementById('includeWorkingCheck')?.addEventListener('change', function() {
document.getElementById('hiddenIncludeWorking').value = this.checked ? '1' : '0';
});
document.querySelectorAll('input[name="code_style"]').forEach(radio => {
radio.addEventListener('change', function() {
if (this.checked) {
document.getElementById('hiddenCodeStyle').value = this.value;
}
});
});
document.getElementById('workingCodeDoc')?.addEventListener('input', function() {
document.getElementById('hiddenWorkingDoc').value = this.value;
});
</script>
</body>
</html>