323 lines
21 KiB
PHP
Executable File
323 lines
21 KiB
PHP
Executable File
<?php require_once dirname(__DIR__) . '/hamid-providers-config.php'; ?>
|
||
<?php session_start(); ?>
|
||
<!DOCTYPE html>
|
||
<html lang="fr">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>WEVAL MIND® Code</title>
|
||
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
|
||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
|
||
<style>
|
||
:root { --bg: #1e1e1e; --sidebar: #252526; --editor: #1e1e1e; --border: #3c3c3c; --text: #cccccc; --text-muted: #858585; --accent: #0078d4; --green: #4ec9b0; --cyan: #06b6d4; }
|
||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||
body { font-family: 'Inter', sans-serif; background: var(--bg); color: var(--text); height: 100vh; display: flex; flex-direction: column; overflow: hidden; }
|
||
.header { background: #323233; padding: 0.4rem 1rem; display: flex; align-items: center; justify-content: space-between; border-bottom: 1px solid var(--border); height: 42px; }
|
||
.header-left { display: flex; align-items: center; gap: 0.75rem; }
|
||
.logo { display: flex; align-items: center; gap: 0.4rem; font-weight: 600; color: var(--accent); font-size: 0.9rem; }
|
||
.logo img { width: 22px; height: 22px; }
|
||
.server-badge { background: var(--bg); padding: 0.2rem 0.5rem; border-radius: 4px; font-size: 0.7rem; color: var(--text-muted); display: flex; align-items: center; gap: 0.3rem; }
|
||
.status-dot { width: 5px; height: 5px; background: #4ec9b0; border-radius: 50%; }
|
||
.header-center { display: flex; align-items: center; gap: 0.5rem; }
|
||
.provider-select { background: var(--bg); border: 1px solid var(--border); border-radius: 4px; padding: 0.3rem 0.5rem; color: var(--text); font-size: 0.7rem; cursor: pointer; }
|
||
.provider-status { font-size: 0.65rem; color: var(--green); }
|
||
.header-right { display: flex; gap: 0.4rem; }
|
||
.header-btn { padding: 0.3rem 0.6rem; background: transparent; border: 1px solid var(--border); border-radius: 4px; color: var(--text); font-size: 0.7rem; cursor: pointer; display: flex; align-items: center; gap: 0.25rem; text-decoration: none; }
|
||
.header-btn:hover { background: var(--sidebar); }
|
||
.main { flex: 1; display: flex; overflow: hidden; }
|
||
.activity-bar { width: 44px; background: #333333; display: flex; flex-direction: column; align-items: center; padding: 0.4rem 0; border-right: 1px solid var(--border); }
|
||
.activity-btn { width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; color: var(--text-muted); cursor: pointer; border-radius: 4px; margin-bottom: 0.2rem; border: none; background: transparent; font-size: 1rem; }
|
||
.activity-btn:hover { color: var(--text); }
|
||
.activity-btn.active { color: var(--text); border-left: 2px solid var(--accent); }
|
||
.sidebar { width: 220px; background: var(--sidebar); border-right: 1px solid var(--border); display: flex; flex-direction: column; }
|
||
.sidebar-header { padding: 0.6rem; font-size: 0.65rem; text-transform: uppercase; color: var(--text-muted); display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid var(--border); }
|
||
.sidebar-actions button { background: transparent; border: none; color: var(--text-muted); cursor: pointer; padding: 0.2rem; font-size: 0.8rem; }
|
||
.sidebar-actions button:hover { color: var(--text); }
|
||
.file-tree { flex: 1; overflow-y: auto; padding: 0.4rem 0; font-size: 0.75rem; }
|
||
.tree-item { display: flex; align-items: center; padding: 0.3rem 0.6rem; cursor: pointer; gap: 0.4rem; }
|
||
.tree-item:hover { background: rgba(255,255,255,0.05); }
|
||
.tree-item i { font-size: 0.8rem; width: 14px; }
|
||
.tree-item .folder-icon { color: #dcb67a; }
|
||
.tree-item .file-icon { color: var(--text-muted); }
|
||
.tree-item .name { flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||
.loading { text-align: center; padding: 1.5rem; color: var(--text-muted); font-size: 0.8rem; }
|
||
.error-msg { color: #f85149; padding: 0.75rem; font-size: 0.75rem; }
|
||
.editor-area { flex: 1; display: flex; flex-direction: column; }
|
||
.tabs { display: flex; background: #2d2d2d; border-bottom: 1px solid var(--border); height: 32px; }
|
||
.tab { padding: 0 0.75rem; height: 100%; display: flex; align-items: center; gap: 0.4rem; font-size: 0.75rem; color: var(--text-muted); cursor: pointer; border-right: 1px solid var(--border); }
|
||
.tab.active { background: var(--editor); color: var(--text); }
|
||
.editor-content { flex: 1; display: flex; flex-direction: column; }
|
||
.editor-welcome { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; color: var(--text-muted); }
|
||
.editor-welcome img { width: 80px; margin-bottom: 1rem; opacity: 0.6; }
|
||
.editor-welcome h2 { font-size: 1.1rem; margin-bottom: 0.4rem; color: var(--text); }
|
||
.code-editor { flex: 1; display: none; flex-direction: column; }
|
||
.code-editor.active { display: flex; }
|
||
.code-editor textarea { flex: 1; background: var(--editor); color: var(--text); border: none; padding: 0.75rem; font-family: 'JetBrains Mono', monospace; font-size: 0.85rem; line-height: 1.5; resize: none; outline: none; }
|
||
.editor-status { display: flex; justify-content: space-between; padding: 0.4rem 0.75rem; background: var(--sidebar); border-top: 1px solid var(--border); font-size: 0.7rem; color: var(--text-muted); }
|
||
.terminal-panel { height: 220px; background: #1e1e1e; border-top: 1px solid var(--border); display: flex; flex-direction: column; }
|
||
.terminal-tabs { display: flex; background: #252526; border-bottom: 1px solid var(--border); height: 30px; }
|
||
.terminal-tab { padding: 0 0.75rem; font-size: 0.75rem; color: var(--text-muted); cursor: pointer; display: flex; align-items: center; }
|
||
.terminal-tab.active { color: var(--text); border-bottom: 2px solid var(--accent); }
|
||
.terminal-actions { margin-left: auto; display: flex; padding: 0.2rem; }
|
||
.terminal-actions button { background: transparent; border: none; color: var(--text-muted); padding: 0.2rem 0.4rem; cursor: pointer; font-size: 0.8rem; }
|
||
.terminal-content { flex: 1; padding: 0.5rem; font-family: 'JetBrains Mono', monospace; font-size: 0.75rem; overflow-y: auto; }
|
||
.terminal-line { margin-bottom: 0.3rem; line-height: 1.5; }
|
||
.terminal-line.info { color: #4ec9b0; }
|
||
.terminal-line.error { color: #f85149; }
|
||
.terminal-line.user { color: #dcdcaa; }
|
||
.terminal-line.user::before { content: '❯ '; color: #06b6d4; }
|
||
.terminal-line.hamid { color: #9cdcfe; padding-left: 0.5rem; border-left: 2px solid #06b6d4; }
|
||
.terminal-line.shell::before { content: '$ '; color: #ce9178; }
|
||
.terminal-input { display: flex; align-items: center; padding: 0.35rem 0.5rem; border-top: 1px solid var(--border); background: #252526; }
|
||
.terminal-input span { color: #06b6d4; margin-right: 0.4rem; font-size: 0.85rem; }
|
||
.terminal-input input { flex: 1; background: transparent; border: none; color: var(--text); font-family: 'JetBrains Mono', monospace; font-size: 0.75rem; outline: none; }
|
||
.status-bar { display: flex; justify-content: space-between; padding: 0 0.6rem; background: #007acc; color: white; font-size: 0.65rem; height: 20px; align-items: center; }
|
||
</style>
|
||
|
||
</head>
|
||
<body>
|
||
<header class="header">
|
||
<div class="header-left">
|
||
<div class="logo"><span style="font-size:1.2rem">🧞</span><span>WEVAL MIND® Code</span></div>
|
||
<div class="server-badge"><span class="status-dot"></span><span id="currentPathDisplay">89.167.40.150 - /opt/wevads</span></div>
|
||
</div>
|
||
<div class="header-center">
|
||
<?php echo hamid_providers_dropdown("groq", "providerSelect", "provider-select"); ?>
|
||
<span class="provider-status">● Online</span>
|
||
</div>
|
||
<div class="header-right">
|
||
<a href="/hamid-fullscreen.php" class="header-btn"><i class="fas fa-comments"></i> Chat</a>
|
||
<button class="header-btn" onclick="showHelp()"><i class="fas fa-question-circle"></i> Aide</button>
|
||
<a href="/ia-index.php" class="header-btn"><i class="fas fa-th"></i> Index</a>
|
||
</div>
|
||
</header>
|
||
|
||
<div class="main">
|
||
<div class="activity-bar">
|
||
<button class="activity-btn active"><i class="fas fa-copy"></i></button>
|
||
<button class="activity-btn"><i class="fas fa-search"></i></button>
|
||
<button class="activity-btn"><i class="fas fa-code-branch"></i></button>
|
||
</div>
|
||
|
||
<div class="sidebar">
|
||
<div class="sidebar-header">
|
||
<span>Explorateur</span>
|
||
<div class="sidebar-actions"><button onclick="loadFiles()" title="Rafraîchir"><i class="fas fa-sync-alt"></i></button></div>
|
||
</div>
|
||
<div class="file-tree" id="fileTree"><div class="loading"><i class="fas fa-spinner fa-spin"></i> Chargement...</div></div>
|
||
</div>
|
||
|
||
<div class="editor-area">
|
||
<div class="tabs" id="tabs"></div>
|
||
<div class="editor-content">
|
||
<div class="editor-welcome" id="welcome">
|
||
<span style="font-size:4rem;opacity:0.5">🧞</span>
|
||
<h2>WEVAL MIND® Code</h2>
|
||
<p>Sélectionnez un fichier</p>
|
||
</div>
|
||
<div class="code-editor" id="codeEditor">
|
||
<textarea id="editorTextarea" spellcheck="false"></textarea>
|
||
<div class="editor-status"><span id="fileInfo">Aucun fichier</span><span id="cursorPos">Ln 1, Col 1</span></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="terminal-panel">
|
||
<div class="terminal-tabs">
|
||
<div class="terminal-tab active">🧞 WEVAL MIND</div>
|
||
<div class="terminal-tab">Output</div>
|
||
<div class="terminal-actions">
|
||
<button onclick="clearTerminal()" title="Effacer"><i class="fas fa-trash"></i></button>
|
||
</div>
|
||
</div>
|
||
<div class="terminal-content" id="terminalOutput">
|
||
<div class="terminal-line info">🧞 WEVAL MIND Terminal - Assistant IA</div>
|
||
<div class="terminal-line info">Posez une question ou tapez !commande pour exécuter du shell</div>
|
||
</div>
|
||
<div class="terminal-input">
|
||
<span>🧞</span>
|
||
<input type="text" id="terminalInput" placeholder="Posez une question à WEVAL MIND... (!cmd pour shell)" onkeydown="if(event.key==='Enter')runCommand()">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="status-bar">
|
||
<div><i class="fas fa-code-branch"></i> main • <i class="fas fa-circle" style="font-size:5px;"></i> Connecté</div>
|
||
<div>UTF-8 • WEVAL MIND v2 • <span id="providerName">Groq</span></div>
|
||
</div>
|
||
|
||
<script>
|
||
let currentPath = '/opt/wevads';
|
||
let currentFile = null;
|
||
let openFiles = [];
|
||
let currentProvider = localStorage.getItem('hamid_provider') || 'groq';
|
||
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
document.getElementById('providerSelect').value = currentProvider;
|
||
document.getElementById('providerName').textContent = currentProvider.toUpperCase();
|
||
loadFiles();
|
||
});
|
||
|
||
function changeProvider() {
|
||
currentProvider = document.getElementById('providerSelect').value;
|
||
localStorage.setItem('hamid_provider', currentProvider);
|
||
document.getElementById('providerName').textContent = currentProvider.toUpperCase();
|
||
addTerminalLine('Provider changé: ' + currentProvider.toUpperCase(), 'info');
|
||
}
|
||
|
||
async function loadFiles(path) {
|
||
if (path) currentPath = path;
|
||
const tree = document.getElementById('fileTree');
|
||
tree.innerHTML = '<div class="loading"><i class="fas fa-spinner fa-spin"></i></div>';
|
||
try {
|
||
const res = await fetch('/hamid-code/api.php?action=list&path=' + encodeURIComponent(currentPath));
|
||
const data = await res.json();
|
||
if (!data.success) { tree.innerHTML = '<div class="error-msg">' + (data.error || 'Erreur') + '</div>'; return; }
|
||
currentPath = data.path;
|
||
document.getElementById('currentPathDisplay').textContent = '89.167.40.150 - ' + currentPath;
|
||
let html = '';
|
||
if (data.parent && data.parent !== data.path) {
|
||
html += '<div class="tree-item" onclick="loadFiles(\'' + data.parent.replace(/'/g, "\\'") + '\')"><i class="fas fa-level-up-alt folder-icon"></i><span class="name">..</span></div>';
|
||
}
|
||
(data.items || []).forEach(item => {
|
||
if (item.type === 'directory') {
|
||
html += '<div class="tree-item" onclick="loadFiles(\'' + item.path.replace(/'/g, "\\'") + '\')"><i class="fas fa-folder folder-icon"></i><span class="name">' + item.name + '</span></div>';
|
||
} else {
|
||
html += '<div class="tree-item" onclick="openFile(\'' + item.path.replace(/'/g, "\\'") + '\', \'' + item.name.replace(/'/g, "\\'") + '\')"><i class="fas fa-file file-icon"></i><span class="name">' + item.name + '</span></div>';
|
||
}
|
||
});
|
||
tree.innerHTML = html || '<div class="loading">Dossier vide</div>';
|
||
} catch (e) { tree.innerHTML = '<div class="error-msg">Erreur: ' + e.message + '</div>'; }
|
||
}
|
||
|
||
async function openFile(path, name) {
|
||
try {
|
||
const res = await fetch('/hamid-code/api.php?action=read&file=' + encodeURIComponent(path));
|
||
const data = await res.json();
|
||
if (!data.success) { alert(data.error); return; }
|
||
currentFile = path;
|
||
document.getElementById('welcome').style.display = 'none';
|
||
document.getElementById('codeEditor').classList.add('active');
|
||
document.getElementById('editorTextarea').value = data.content;
|
||
document.getElementById('fileInfo').textContent = name + ' - ' + formatSize(data.size);
|
||
if (!openFiles.find(f => f.path === path)) openFiles.push({ path, name });
|
||
updateTabs();
|
||
} catch (e) { alert('Erreur: ' + e.message); }
|
||
}
|
||
|
||
function updateTabs() {
|
||
document.getElementById('tabs').innerHTML = openFiles.map(f =>
|
||
'<div class="tab ' + (f.path === currentFile ? 'active' : '') + '" onclick="openFile(\'' + f.path.replace(/'/g, "\\'") + '\', \'' + f.name.replace(/'/g, "\\'") + '\')">' + f.name + '</div>'
|
||
).join('');
|
||
}
|
||
|
||
async function runCommand() {
|
||
const input = document.getElementById('terminalInput');
|
||
const cmd = input.value.trim();
|
||
if (!cmd) return;
|
||
input.value = '';
|
||
|
||
// Commande shell avec !
|
||
if (cmd.startsWith('!')) {
|
||
const shellCmd = cmd.substring(1).trim();
|
||
addTerminalLine(shellCmd, 'shell');
|
||
try {
|
||
const res = await fetch('/hamid-code/api.php', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||
body: 'action=terminal&command=' + encodeURIComponent(shellCmd) + '&cwd=' + encodeURIComponent(currentPath)
|
||
});
|
||
const data = await res.json();
|
||
if (data.stdout) addTerminalLine(data.stdout);
|
||
if (data.stderr) addTerminalLine(data.stderr, 'error');
|
||
} catch (e) { addTerminalLine('Erreur: ' + e.message, 'error'); }
|
||
return;
|
||
}
|
||
|
||
// Commandes spéciales
|
||
if (cmd === '/help') {
|
||
addTerminalLine('Commandes:', 'info');
|
||
addTerminalLine(' !commande - Exécuter une commande shell');
|
||
addTerminalLine(' /explain - Expliquer le code ouvert');
|
||
addTerminalLine(' /fix - Corriger le code ouvert');
|
||
addTerminalLine(' /clear - Effacer le terminal');
|
||
return;
|
||
}
|
||
if (cmd === '/clear') { clearTerminal(); return; }
|
||
if (cmd === '/explain' && currentFile) {
|
||
const code = document.getElementById('editorTextarea').value;
|
||
await askHamid('Explique ce code en détail:\n```\n' + code.substring(0, 3000) + '\n```');
|
||
return;
|
||
}
|
||
if (cmd === '/fix' && currentFile) {
|
||
const code = document.getElementById('editorTextarea').value;
|
||
await askHamid('Corrige et améliore ce code:\n```\n' + code.substring(0, 3000) + '\n```');
|
||
return;
|
||
}
|
||
|
||
// Question à WEVAL MIND
|
||
await askHamid(cmd);
|
||
}
|
||
|
||
async function askHamid(question) {
|
||
addTerminalLine(question.substring(0, 100) + (question.length > 100 ? '...' : ''), 'user');
|
||
addTerminalLine('🧞 Réflexion...', 'info');
|
||
|
||
try {
|
||
const fd = new FormData();
|
||
fd.append('message', question);
|
||
fd.append('provider', currentProvider);
|
||
|
||
const res = await fetch('/hamid-api.php', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({message: question, provider: currentProvider, session_id: 'code_' + Date.now()}) });
|
||
const data = await res.json();
|
||
|
||
// Supprimer "Réflexion..."
|
||
const output = document.getElementById('terminalOutput');
|
||
if (output.lastChild) output.removeChild(output.lastChild);
|
||
|
||
if (data.success) {
|
||
addTerminalLine(data.response, 'hamid');
|
||
let tags = data.provider + ' • ' + data.duration_ms + 'ms'; if(data.kb_used) tags += ' • 📚 KB'; addTerminalLine('[' + tags + ']', 'info');
|
||
} else {
|
||
addTerminalLine('❌ ' + (data.error || 'Erreur'), 'error');
|
||
}
|
||
} catch (e) {
|
||
addTerminalLine('❌ Erreur: ' + e.message, 'error');
|
||
}
|
||
}
|
||
|
||
function addTerminalLine(text, type = '') {
|
||
const output = document.getElementById('terminalOutput');
|
||
const line = document.createElement('div');
|
||
line.className = 'terminal-line' + (type ? ' ' + type : '');
|
||
line.innerHTML = text.replace(/\n/g, '<br>').replace(/`([^`]+)`/g, '<code style="background:#333;padding:2px 4px;border-radius:3px">$1</code>');
|
||
output.appendChild(line);
|
||
output.scrollTop = output.scrollHeight;
|
||
}
|
||
|
||
function clearTerminal() {
|
||
document.getElementById('terminalOutput').innerHTML = '<div class="terminal-line info">🧞 Terminal effacé</div>';
|
||
}
|
||
|
||
function formatSize(b) { return b < 1024 ? b + ' B' : (b / 1024).toFixed(1) + ' KB'; }
|
||
|
||
document.addEventListener('keydown', e => { if (e.ctrlKey && e.key === 's') { e.preventDefault(); saveFile(); } });
|
||
|
||
async function saveFile() {
|
||
if (!currentFile) return;
|
||
try {
|
||
const res = await fetch('/hamid-code/api.php', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||
body: 'action=save&file=' + encodeURIComponent(currentFile) + '&content=' + encodeURIComponent(document.getElementById('editorTextarea').value)
|
||
});
|
||
const data = await res.json();
|
||
addTerminalLine(data.success ? '✅ Fichier sauvegardé!' : '❌ ' + data.error, data.success ? 'info' : 'error');
|
||
} catch (e) { addTerminalLine('❌ Erreur: ' + e.message, 'error'); }
|
||
}
|
||
</script>
|
||
<div id="helpModal" style="display:none;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.85);z-index:1000;padding:2rem;overflow-y:auto"><div style="max-width:800px;margin:0 auto;background:#1e1e1e;border:1px solid #3c3c3c;border-radius:12px;padding:1.5rem"><div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:1rem"><h2 style="color:#4fc3f7;margin:0">🧞 Guide des Providers IA</h2><button onclick="document.getElementById('helpModal').style.display='none'" style="background:none;border:none;color:#888;font-size:1.5rem;cursor:pointer">×</button></div><div style="color:#d4d4d4"><h3 style="color:#4caf50">✅ RECOMMANDÉS POUR LE CODE</h3><p>🔮 <b>DeepSeek</b> - Excellent pour analyse et génération de code</p><p>🧠 <b>Cerebras</b> - Ultra rapide pour corrections rapides</p><p>🧠 <b>Claude</b> - Le plus intelligent pour refactoring complexe</p><h3 style="color:#ff9800;margin-top:1rem">⚡ RAPIDES</h3><p>🚀 Groq, 🧠 Cerebras, ⚡ Ollama Mini</p><h3 style="color:#2196f3;margin-top:1rem">🎯 POUR WEVAL MIND CODE</h3><p>Utilisez <b>DeepSeek</b> ou <b>Claude</b> pour expliquer du code</p><p>Utilisez <b>Cerebras</b> pour des corrections rapides</p><p>Commandes: <code>/explain</code> <code>/fix</code> <code>!shell</code></p></div></div></div><script>function showHelp(){document.getElementById("helpModal").style.display="block"}</script>
|
||
|
||
</body>
|
||
</html>
|