Update gpt/index.html

This commit is contained in:
2026-05-10 17:51:53 +02:00
parent 2fe636fc90
commit efa7906ea3
+259 -318
View File
@@ -379,345 +379,286 @@
</div> </div>
</div> </div>
<script> <script>
/* ============================================ /* ============================================
AI CONFIGURATION AI CONFIGURATION
============================================ */ ============================================ */
let aiConfig = { let aiConfig = {
enabled: false, enabled: false,
endpoint: '', endpoint: '',
model: '', model: '',
apiKey: '', apiKey: '',
type: 'ollama' // ollama, openai, lmstudio, gpt4all type: 'openai'
}; };
// Load saved config // Load saved config
const savedConfig = localStorage.getItem('neuralTerminalConfig'); const savedConfig = localStorage.getItem('neuralTerminalConfig');
if (savedConfig) { if (savedConfig) {
aiConfig = JSON.parse(savedConfig); aiConfig = JSON.parse(savedConfig);
} }
/* ============================================ /* ============================================
TERMINAL STATE TERMINAL STATE
============================================ */ ============================================ */
const output = document.getElementById('output'); const output = document.getElementById('output');
const inputField = document.getElementById('inputField'); const inputField = document.getElementById('inputField');
const statusDot = document.getElementById('statusDot'); const statusDot = document.getElementById('statusDot');
const statusText = document.getElementById('statusText'); const statusText = document.getElementById('statusText');
const timeDisplay = document.getElementById('timeDisplay'); const timeDisplay = document.getElementById('timeDisplay');
const configPanel = document.getElementById('configPanel'); const configPanel = document.getElementById('configPanel');
let commandHistory = []; let commandHistory = [];
let historyIndex = -1; let historyIndex = -1;
let isProcessing = false; let isProcessing = false;
/* ============================================ /* ============================================
UI FUNCTIONS UI
============================================ */ ============================================ */
function updateStatus() { function updateStatus() {
if (aiConfig.enabled) { if (aiConfig.enabled) {
statusDot.className = 'status-dot online'; statusDot.className = 'status-dot online';
statusText.textContent = 'ONLINE'; statusText.textContent = 'ONLINE';
} else { } else {
statusDot.className = 'status-dot offline'; statusDot.className = 'status-dot offline';
statusText.textContent = 'OFFLINE'; statusText.textContent = 'OFFLINE';
} }
} }
function updateTime() { function updateTime() {
const now = new Date(); const now = new Date();
timeDisplay.textContent = now.toLocaleTimeString('en-US', { hour12: false }); timeDisplay.textContent = now.toLocaleTimeString('en-US', { hour12: false });
} }
function addLine(text, type = '') { function addLine(text, type = '') {
const line = document.createElement('div'); const line = document.createElement('div');
line.className = 'output-line' + (type ? ' ' + type : ''); line.className = 'output-line' + (type ? ' ' + type : '');
line.textContent = text; line.textContent = text;
output.appendChild(line); output.appendChild(line);
output.scrollTop = output.scrollHeight; output.scrollTop = output.scrollHeight;
} }
function clearOutput() { function clearOutput() {
output.innerHTML = ''; output.innerHTML = '';
addLine('Screen cleared', 'system'); addLine('Screen cleared', 'system');
} }
/* ============================================ /* ============================================
CONFIG PANEL CONFIG PANEL
============================================ */ ============================================ */
function openConfig() { function openConfig() {
document.getElementById('endpointInput').value = aiConfig.endpoint; document.getElementById('endpointInput').value = aiConfig.endpoint;
document.getElementById('modelInput').value = aiConfig.model; document.getElementById('modelInput').value = aiConfig.model;
document.getElementById('apiKeyInput').value = aiConfig.apiKey; document.getElementById('apiKeyInput').value = aiConfig.apiKey;
configPanel.classList.add('visible'); configPanel.classList.add('visible');
} }
function closeConfig() { function closeConfig() {
configPanel.classList.remove('visible'); configPanel.classList.remove('visible');
inputField.focus(); inputField.focus();
} }
function saveConfig() { function saveConfig() {
aiConfig.endpoint = document.getElementById('endpointInput').value.trim(); aiConfig.endpoint = document.getElementById('endpointInput').value.trim();
aiConfig.model = document.getElementById('modelInput').value.trim(); aiConfig.model = document.getElementById('modelInput').value.trim();
aiConfig.apiKey = document.getElementById('apiKeyInput').value.trim(); aiConfig.apiKey = document.getElementById('apiKeyInput').value.trim();
aiConfig.enabled = aiConfig.endpoint !== '' && aiConfig.model !== ''; aiConfig.enabled = aiConfig.endpoint !== '' && aiConfig.model !== '';
localStorage.setItem('neuralTerminalConfig', JSON.stringify(aiConfig)); localStorage.setItem('neuralTerminalConfig', JSON.stringify(aiConfig));
updateStatus(); updateStatus();
closeConfig(); closeConfig();
addLine('Configuration saved', 'system'); addLine('Configuration saved', 'system');
} }
async function testConnection() { /* ============================================
const endpoint = document.getElementById('endpointInput').value.trim(); TEST CONNECTION (FIXED)
const model = document.getElementById('modelInput').value.trim(); ============================================ */
async function testConnection() {
const endpoint = document.getElementById('endpointInput').value.trim();
if (!endpoint || !model) { if (!endpoint) {
alert('Please enter endpoint and model name'); alert('Please enter endpoint');
return; return;
} }
try { try {
// Try a simple request based on detected type // ONLY OpenAI-style test
const testEndpoint = endpoint.replace('/chat', '/tags').replace('/completions', '/models'); const testUrl = endpoint.replace('/chat/completions', '/models');
const response = await fetch(testEndpoint, {
method: 'GET',
headers: aiConfig.apiKey ? { 'Authorization': 'Bearer ' + aiConfig.apiKey } : {}
});
if (response.ok) { const response = await fetch(testUrl, {
alert('Connection successful!'); method: 'GET',
} else { headers: aiConfig.apiKey
alert('Connection failed: ' + response.status); ? { 'Authorization': 'Bearer ' + aiConfig.apiKey }
} : {}
} catch (e) {
alert('Connection error: ' + e.message);
}
}
// Preset handling
document.getElementById('presetSelect').addEventListener('change', function() {
const presets = {
ollama: { endpoint: 'http://localhost:11434/api/chat', model: 'llama2', type: 'ollama' },
lmstudio: { endpoint: 'http://localhost:1234/v1/chat/completions', model: 'local-model', type: 'openai' },
gpt4all: { endpoint: 'http://localhost:4891/v1/chat/completions', model: 'gpt4all-model', type: 'openai' },
openai: { endpoint: 'https://api.openai.com/v1/chat/completions', model: 'gpt-4o-mini', type: 'openai' },
claude: { endpoint: 'https://api.anthropic.com/v1/messages', model: 'claude-sonnet-4-20250514', type: 'claude' }
};
const preset = presets[this.value];
if (preset) {
document.getElementById('endpointInput').value = preset.endpoint;
document.getElementById('modelInput').value = preset.model;
aiConfig.type = preset.type;
}
}); });
/* ============================================ if (response.ok) {
HELPER FUNCTIONS alert('Connection successful!');
============================================ */ } else {
function getFormattedDate() { alert('Connection failed: ' + response.status);
const now = new Date(); }
const dd = String(now.getDate()).padStart(2, '0'); } catch (e) {
const mm = String(now.getMonth() + 1).padStart(2, '0'); alert('Connection error: ' + e.message);
const yyyy = now.getFullYear(); }
const HH = String(now.getHours()).padStart(2, '0'); }
const MM = String(now.getMinutes()).padStart(2, '0');
const SS = String(now.getSeconds()).padStart(2, '0'); /* ============================================
return `${dd}/${mm}/${yyyy}:${HH}/${MM}/${SS}`; PRESETS (CLEAN)
============================================ */
document.getElementById('presetSelect').addEventListener('change', function () {
const presets = {
local: {
endpoint: 'http://localhost:4891/v1/chat/completions',
model: 'local-model',
type: 'openai'
},
openai: {
endpoint: 'https://api.openai.com/v1/chat/completions',
model: 'gpt-4o-mini',
type: 'openai'
},
claude: {
endpoint: 'https://api.anthropic.com/v1/messages',
model: 'claude-sonnet-4-20250514',
type: 'claude'
}
};
const preset = presets[this.value];
if (preset) {
document.getElementById('endpointInput').value = preset.endpoint;
document.getElementById('modelInput').value = preset.model;
aiConfig.type = preset.type;
}
});
/* ============================================
HELPERS
============================================ */
function getFormattedDate() {
const now = new Date();
return `${String(now.getDate()).padStart(2, '0')}/${
String(now.getMonth() + 1).padStart(2, '0')
}/${now.getFullYear()}:${String(now.getHours()).padStart(2, '0')}/${
String(now.getMinutes()).padStart(2, '0')
}/${String(now.getSeconds()).padStart(2, '0')}`;
}
function getStatusInfo() {
return `[Connection: ${aiConfig.enabled ? 'ONLINE' : 'OFFLINE'}, Endpoint: ${aiConfig.endpoint || 'none'}, Model: ${aiConfig.model || 'none'}]`;
}
function preprocessMessage(message) {
return message
.replace(/\bdate\b/gi, `date (${getFormattedDate()})`)
.replace(/\bstatus\b/gi, `status ${getStatusInfo()}`);
}
/* ============================================
AI CALL (OPENAI ONLY)
============================================ */
async function queryAI(message) {
if (!aiConfig.enabled) {
addLine('AI is offline. Use config to connect.', 'error');
return;
}
isProcessing = true;
const processedMessage = preprocessMessage(message);
try {
const headers = { 'Content-Type': 'application/json' };
if (aiConfig.apiKey) {
headers['Authorization'] = 'Bearer ' + aiConfig.apiKey;
} }
function getStatusInfo() { const response = await fetch(aiConfig.endpoint, {
return `[Connection: ${aiConfig.enabled ? 'ONLINE' : 'OFFLINE'}, Endpoint: ${aiConfig.endpoint || 'none'}, Model: ${aiConfig.model || 'none'}]`; method: 'POST',
} headers,
body: JSON.stringify({
function preprocessMessage(message) { model: aiConfig.model,
// Replace "date" keyword with actual date (case insensitive, whole word) messages: [{ role: 'user', content: processedMessage }],
let processed = message.replace(/\bdate\b/gi, `date (${getFormattedDate()})`); stream: false
// Replace "status" keyword with actual status info (case insensitive, whole word) })
processed = processed.replace(/\bstatus\b/gi, `status ${getStatusInfo()}`);
return processed;
}
/* ============================================
AI COMMUNICATION
============================================ */
async function queryAI(message) {
if (!aiConfig.enabled) {
addLine('', '');
addLine('The AI you are trying to reach is not online at the moment.', 'error');
addLine('', '');
addLine('To connect an AI backend:', 'system');
addLine(' 1. Type "config" to open settings', 'system');
addLine(' 2. Choose a preset or enter custom endpoint', 'system');
addLine(' 3. Supported: Ollama, LM Studio, GPT4All, OpenAI, Claude', 'system');
return;
}
isProcessing = true;
// Preprocess message to replace date/status keywords
const processedMessage = preprocessMessage(message);
try {
let response;
if (aiConfig.type === 'ollama') {
response = await fetch(aiConfig.endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
model: aiConfig.model,
messages: [{ role: 'user', content: processedMessage }],
stream: false
})
});
const data = await response.json();
if (data.message && data.message.content) {
addLine(data.message.content, 'ai');
} else if (data.error) {
addLine('Error: ' + data.error, 'error');
}
} else if (aiConfig.type === 'claude') {
// Claude/Anthropic API
response = await fetch(aiConfig.endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': aiConfig.apiKey,
'anthropic-version': '2023-06-01',
'anthropic-dangerous-direct-browser-access': 'true'
},
body: JSON.stringify({
model: aiConfig.model,
max_tokens: 1024,
messages: [{ role: 'user', content: processedMessage }]
})
});
const data = await response.json();
if (data.content && data.content[0]) {
addLine(data.content[0].text, 'ai');
} else if (data.error) {
addLine('Error: ' + (data.error.message || data.error), 'error');
}
} else {
// OpenAI-compatible API (LM Studio, GPT4All, OpenAI, etc.)
const headers = { 'Content-Type': 'application/json' };
if (aiConfig.apiKey) {
headers['Authorization'] = 'Bearer ' + aiConfig.apiKey;
}
response = await fetch(aiConfig.endpoint, {
method: 'POST',
headers: headers,
body: JSON.stringify({
model: aiConfig.model,
messages: [{ role: 'user', content: processedMessage }],
stream: false
})
});
const data = await response.json();
if (data.choices && data.choices[0]) {
addLine(data.choices[0].message.content, 'ai');
} else if (data.error) {
addLine('Error: ' + (data.error.message || data.error), 'error');
}
}
} catch (e) {
addLine('Connection error: ' + e.message, 'error');
addLine('Make sure your AI backend is running', 'system');
}
isProcessing = false;
}
/* ============================================
COMMAND PROCESSING
============================================ */
function processCommand(input) {
const trimmed = input.trim();
if (!trimmed) return;
addLine(trimmed, 'user');
commandHistory.unshift(trimmed);
historyIndex = -1;
const cmd = trimmed.toLowerCase();
switch (cmd) {
case 'help':
addLine('', '');
addLine('Available commands:', 'system');
addLine(' help - Show this help', 'system');
addLine(' config - Configure AI backend', 'system');
addLine(' clear - Clear screen', 'system');
addLine('', '');
addLine('Keywords (replaced in messages to AI):', 'system');
addLine(' date - Replaced with current date/time', 'system');
addLine(' status - Replaced with connection info', 'system');
addLine('', '');
addLine('Any other input is sent to the AI', 'system');
break;
case 'config':
openConfig();
break;
case 'clear':
clearOutput();
break;
default:
queryAI(trimmed);
}
}
/* ============================================
INPUT HANDLING
============================================ */
inputField.addEventListener('keydown', function(e) {
if (e.key === 'Enter' && !isProcessing) {
processCommand(this.value);
this.value = '';
} else if (e.key === 'ArrowUp') {
e.preventDefault();
if (historyIndex < commandHistory.length - 1) {
historyIndex++;
this.value = commandHistory[historyIndex];
}
} else if (e.key === 'ArrowDown') {
e.preventDefault();
if (historyIndex > 0) {
historyIndex--;
this.value = commandHistory[historyIndex];
} else {
historyIndex = -1;
this.value = '';
}
}
}); });
/* ============================================ const data = await response.json();
INITIALIZATION
============================================ */ if (data.choices && data.choices[0]) {
updateStatus(); addLine(data.choices[0].message.content, 'ai');
updateTime(); } else if (data.error) {
setInterval(updateTime, 1000); addLine('Error: ' + (data.error.message || data.error), 'error');
} else {
addLine('Invalid response from server', 'error');
}
} catch (e) {
addLine('Connection error: ' + e.message, 'error');
}
isProcessing = false;
}
/* ============================================
COMMANDS
============================================ */
function processCommand(input) {
const trimmed = input.trim();
if (!trimmed) return;
addLine(trimmed, 'user');
commandHistory.unshift(trimmed);
historyIndex = -1;
switch (trimmed.toLowerCase()) {
case 'help':
addLine('help | config | clear | date | status', 'system');
break;
case 'config':
openConfig();
break;
case 'clear':
clearOutput();
break;
case 'date':
addLine(getFormattedDate(), 'system');
break;
case 'status':
addLine(getStatusInfo(), 'system');
break;
default:
queryAI(trimmed);
}
}
/* ============================================
INPUT
============================================ */
inputField.addEventListener('keydown', (e) => {
if (e.key === 'Enter' && !isProcessing) {
processCommand(inputField.value);
inputField.value = '';
}
});
/* ============================================
INIT
============================================ */
updateStatus();
updateTime();
setInterval(updateTime, 1000);
inputField.focus();
document.addEventListener('click', (e) => {
if (!configPanel.contains(e.target)) {
inputField.focus(); inputField.focus();
}
// Click anywhere to focus input });
document.addEventListener('click', function(e) { </script>
if (!configPanel.contains(e.target)) {
inputField.focus();
}
});
</script>
</body> </body>
</html> </html>