<?php
// settings.php - Settings Modal & Management
// Handle initial prompt setting
if (isset($_POST['action']) && $_POST['action'] === 'save_initial_prompt') {
$_SESSION['initial_prompt'] = $_POST['initial_prompt'] ?? 'none';
// Save custom prompt text if provided
$customText = trim($_POST['custom_prompt_text'] ?? '');
if ($customText !== '') {
$_SESSION['custom_prompts'][$_SESSION['initial_prompt']] = $customText;
}
header('Location: ' . $_SERVER['PHP_SELF']);
exit;
}
// Get the current prompt text (custom or default)
function getCurrentPromptText($promptKey, $promptOptions, $customPrompts) {
if (isset($customPrompts[$promptKey]) && trim($customPrompts[$promptKey]) !== '') {
return $customPrompts[$promptKey];
}
return $promptOptions[$promptKey]['content'] ?? '';
}
?>
<style>
/* Settings modal styles */
.overlay{position:fixed;inset:0;display:none;align-items:center;justify-content:center;z-index:1000;background:rgba(0,0,0,.5);backdrop-filter:blur(5px);}
.dialog{width:min(92vw,860px);max-height:90vh;overflow:hidden;background:#0c1018;border:1px solid var(--br);border-radius:16px;box-shadow:0 10px 40px rgba(0,0,0,.5);display:flex;flex-direction:column}
.dialog-bd{padding:16px;overflow-y:auto;}
.dialog-hd{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;border-bottom:1px solid var(--br)}
.dialog-ft{padding:12px 16px;border-top:1px solid var(--br);display:flex;gap:8px;justify-content:flex-end}
.close-x{background:none;border:none;color:var(--muted);font-size:20px;cursor:pointer}
.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px}
label{font-size:.9rem;color:#cbd5e1;display:flex;flex-direction:column;gap:6px}
select,input,textarea{background:#0d111a;color:#e5e7eb;border:1px solid var(--br);border-radius:10px;padding:10px 12px;font-size:.95rem;font-family:inherit}
.small-note{color:var(--muted);font-size:.85rem}
/* Initial Prompt Styles */
.prompt-section {
margin-top: 20px;
padding: 16px;
background: rgba(255, 255, 255, 0.02);
border: 1px solid var(--br);
border-radius: 12px;
}
.prompt-section h3 {
margin: 0 0 16px 0;
color: var(--accent);
font-size: 1rem;
font-weight: 600;
}
.radio-group {
display: flex;
flex-direction: column;
gap: 12px;
}
.radio-option {
display: flex;
align-items: flex-start;
gap: 10px;
padding: 12px;
border: 1px solid var(--br);
border-radius: 8px;
cursor: pointer;
transition: all 0.2s ease;
}
.radio-option:hover {
border-color: var(--accent);
background: rgba(47, 111, 235, 0.05);
}
.radio-option.selected {
border-color: var(--accent);
background: rgba(47, 111, 235, 0.1);
}
.radio-option input[type="radio"] {
margin: 0;
width: 18px;
height: 18px;
accent-color: var(--accent);
}
.radio-content {
flex: 1;
}
.radio-label {
font-weight: 600;
color: var(--ink);
margin-bottom: 4px;
}
.radio-preview {
font-size: 0.85rem;
color: var(--muted);
line-height: 1.4;
max-height: 60px;
overflow: hidden;
text-overflow: ellipsis;
}
</style>
<div class="overlay" id="settings">
<div class="dialog">
<div class="dialog-hd">
<strong>Settings</strong>
<button class="close-x" onclick="hideSettings()">×</button>
</div>
<div class="dialog-bd">
<div class="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 (deliberation)</option>
<option value="gpt-5-nano" <?= $stickyModel==='gpt-5-nano'?'selected':''; ?>>gpt-5-nano (OpenAI)</option>
<option value="gpt-5-mini" <?= $stickyModel==='gpt-5-mini'?'selected':''; ?>>gpt-5-mini (OpenAI)</option>
<option value="gpt-5" <?= $stickyModel==='gpt-5'?'selected':''; ?>>gpt-5 (OpenAI)</option>
<option value="gpt-4o" <?= $stickyModel==='gpt-4o'?'selected':''; ?>>gpt-4o (OpenAI)</option>
<option value="gpt-4o-mini" <?= $stickyModel==='gpt-4o-mini'?'selected':''; ?>>gpt-4o-mini (OpenAI)</option>
<option value="grok-3" <?= $stickyModel==='grok-3'?'selected':''; ?>>grok-3 (xAI - flagship reasoning)</option>
<option value="grok-3-mini" <?= $stickyModel==='grok-3-mini'?'selected':''; ?>>grok-3-mini (xAI - lightweight reasoning)</option>
<option value="grok-code-fast-1" <?= $stickyModel==='grok-code-fast-1'?'selected':''; ?>>grok-code-fast-1 (xAI - speedy coding)</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>
<!-- Initial Prompt Section -->
<div class="prompt-section">
<h3>Initial Prompt</h3>
<form method="post" id="promptForm">
<input type="hidden" name="action" value="save_initial_prompt">
<div class="radio-group">
<?php foreach ($promptOptions as $key => $option): ?>
<div class="radio-option <?= $initialPrompt === $key ? 'selected' : '' ?>" onclick="selectPrompt('<?= $key ?>')">
<input type="radio" name="initial_prompt" value="<?= $key ?>" <?= $initialPrompt === $key ? 'checked' : '' ?> id="prompt_<?= $key ?>">
<div class="radio-content">
<div class="radio-label"><?= h($option['label']) ?></div>
<?php if ($option['content']): ?>
<div class="radio-preview"><?= h($option['content']) ?></div>
<?php else: ?>
<div class="radio-preview">No initial prompt will be used</div>
<?php endif; ?>
</div>
</div>
<?php endforeach; ?>
</div>
<label style="margin-top: 16px;">Prompt Text (editable)
<textarea id="promptPreview" name="custom_prompt_text" rows="4" placeholder="Enter your custom prompt text here..."><?= h(getCurrentPromptText($initialPrompt, $promptOptions, $_SESSION['custom_prompts'])) ?></textarea>
</label>
<button type="submit" class="btn" style="width:100%; margin-top: 12px;">Save Initial Prompt</button>
</form>
</div>
<label style="margin-top: 20px;">Flashcard Q&A JSON URL
<input id="flashcardUrlInput" type="text" value="flashcards.json" placeholder="Enter URL to a JSON file">
</label>
<button class="btn" style="width:100%; margin-top: 10px;" onclick="loadFlashcards()">Load Flashcards</button>
<div class="small-note">
Chat memory is <strong>ON</strong> (last <?= (int)$MAX_HISTORY_MESSAGES ?> messages are sent with your next question).
<?php if ($initialPrompt !== 'none'): ?>
<br><strong>Initial prompt is active:</strong> "<?= h($promptOptions[$initialPrompt]['label']) ?>" will be prepended to conversations.
<?php endif; ?>
</div>
</div>
<div class="dialog-ft">
<button class="btn" onclick="hideSettings()">Close</button>
</div>
</div>
</div>
<script>
// Settings functionality
function showSettings(){
document.getElementById('settings').style.display='flex';
}
function hideSettings(){
document.getElementById('settings').style.display='none';
}
// Close modal when clicking outside
document.getElementById('settings').addEventListener('click', function(e){
if(e.target===this) hideSettings();
});
// Close modal with Escape key
document.addEventListener('keydown', function(e){
if(e.key==='Escape') hideSettings();
});
// Prompt selection functionality
function selectPrompt(promptKey) {
// Update radio button
document.getElementById('prompt_' + promptKey).checked = true;
// Update visual selection
document.querySelectorAll('.radio-option').forEach(option => {
option.classList.remove('selected');
});
event.currentTarget.classList.add('selected');
// Update textarea with predefined content (user can then edit)
const promptOptions = {
'none': { content: '' },
'helpful': { content: 'You are a helpful, knowledgeable, and friendly AI assistant. Provide clear, accurate, and detailed responses. Always be respectful and aim to be as useful as possible.' },
'creative': { content: 'You are a creative and imaginative AI assistant. Help with brainstorming, creative writing, artistic ideas, and innovative solutions. Be inspiring and think outside the box while remaining practical.' },
'technical': { content: 'You are a technical expert and programming assistant. Provide precise, well-structured code examples, explain technical concepts clearly, and offer best practices. Focus on accuracy and efficiency.' }
};
const previewElement = document.getElementById('promptPreview');
// Load default content when switching options (user can edit from there)
previewElement.value = promptOptions[promptKey].content || '';
}
// Flashcard management
async function loadFlashcards() {
const url = document.getElementById('flashcardUrlInput').value;
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Failed to fetch flashcards. Status: ${response.status}`);
}
flashcardsData = await response.json();
alert('Flashcards loaded successfully!');
} catch (e) {
console.error("Error loading flashcards:", e);
alert(`Error loading flashcards: ${e.message}. Please check the URL.`);
flashcardsData = [];
}
}
</script>