Spaces:
Running
Running
OPENAI_API_KEY=sk-votre_cle_api_ici
Browse files- index.html +9 -6
- script.js +44 -44
- styles.css +16 -38
index.html
CHANGED
|
@@ -31,11 +31,12 @@
|
|
| 31 |
<link rel="stylesheet" href="styles.css" />
|
| 32 |
</head>
|
| 33 |
<body class="h-full bg-slate-50 text-slate-900 dark:bg-slate-950 dark:text-slate-100 transition-colors">
|
|
|
|
| 34 |
<div class="container">
|
| 35 |
|
| 36 |
-
<!-- Colonne 1 :
|
| 37 |
<aside class="sidebar">
|
| 38 |
-
<div class="flex items-center justify-between mb-6">
|
| 39 |
<a href="#" class="logo">
|
| 40 |
<i class="fa-solid fa-code"></i>
|
| 41 |
<span>Espace Codage</span>
|
|
@@ -65,9 +66,10 @@
|
|
| 65 |
</ul>
|
| 66 |
</div>
|
| 67 |
</aside>
|
| 68 |
-
|
|
|
|
| 69 |
<main class="chat">
|
| 70 |
-
<div class="chat-header">
|
| 71 |
<h2>Espace Codage – Rosalinda</h2>
|
| 72 |
<div class="activity-monitor">
|
| 73 |
<span id="aiActivityDot" class="dot"></span>
|
|
@@ -100,9 +102,10 @@
|
|
| 100 |
</button>
|
| 101 |
</div>
|
| 102 |
</main>
|
| 103 |
-
|
|
|
|
| 104 |
<section class="output">
|
| 105 |
-
<div class="output-tabs">
|
| 106 |
<button class="tab-btn active" data-tab="code">
|
| 107 |
<i class="fas fa-code"></i> Code
|
| 108 |
</button>
|
|
|
|
| 31 |
<link rel="stylesheet" href="styles.css" />
|
| 32 |
</head>
|
| 33 |
<body class="h-full bg-slate-50 text-slate-900 dark:bg-slate-950 dark:text-slate-100 transition-colors">
|
| 34 |
+
|
| 35 |
<div class="container">
|
| 36 |
|
| 37 |
+
<!-- Colonne 1 : Navigation -->
|
| 38 |
<aside class="sidebar">
|
| 39 |
+
<div class="flex items-center justify-between mb-6">
|
| 40 |
<a href="#" class="logo">
|
| 41 |
<i class="fa-solid fa-code"></i>
|
| 42 |
<span>Espace Codage</span>
|
|
|
|
| 66 |
</ul>
|
| 67 |
</div>
|
| 68 |
</aside>
|
| 69 |
+
|
| 70 |
+
<!-- Colonne 2 : Chat IA Rosalinda -->
|
| 71 |
<main class="chat">
|
| 72 |
+
<div class="chat-header">
|
| 73 |
<h2>Espace Codage – Rosalinda</h2>
|
| 74 |
<div class="activity-monitor">
|
| 75 |
<span id="aiActivityDot" class="dot"></span>
|
|
|
|
| 102 |
</button>
|
| 103 |
</div>
|
| 104 |
</main>
|
| 105 |
+
|
| 106 |
+
<!-- Colonne 3 : Résultat & Code -->
|
| 107 |
<section class="output">
|
| 108 |
+
<div class="output-tabs">
|
| 109 |
<button class="tab-btn active" data-tab="code">
|
| 110 |
<i class="fas fa-code"></i> Code
|
| 111 |
</button>
|
script.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
|
|
| 1 |
console.log("Interface Espace Codage chargée.");
|
| 2 |
|
|
|
|
|
|
|
|
|
|
| 3 |
// ===== Thème (light/dark) =====
|
| 4 |
const themeToggle = document.getElementById('themeToggle');
|
| 5 |
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)');
|
|
@@ -112,6 +116,16 @@ function setAIActivity(text, active = true) {
|
|
| 112 |
aiActivityText.textContent = text;
|
| 113 |
aiActivityDot.style.background = active ? 'rgb(34,197,94)' : 'rgb(100,116,139)'; // emerald vs slate
|
| 114 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
function addMessage(role, content) {
|
| 116 |
const msg = document.createElement('div');
|
| 117 |
msg.className = 'msg ' + (role === 'user' ? 'msg-user' : 'msg-ai');
|
|
@@ -138,56 +152,42 @@ function escapeHTML(str) {
|
|
| 138 |
'&': '&', '<': '<', '>': '>', '"': '"', "'": '''
|
| 139 |
}[m]));
|
| 140 |
}
|
| 141 |
-
function sendMessage() {
|
| 142 |
const text = chatInput.value.trim();
|
| 143 |
if (!text) return;
|
| 144 |
addMessage('user', text);
|
| 145 |
chatInput.value = '';
|
| 146 |
-
|
| 147 |
setAIActivity('Rosalinda réfléchit...', true);
|
| 148 |
-
|
| 149 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
setAIActivity('IA en veille', false);
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
\
|
| 157 |
-
|
| 158 |
-
// Analyse syntaxique
|
| 159 |
-
const tokens = input.toLowerCase().split(' ');
|
| 160 |
-
|
| 161 |
-
// Génération de réponse contextuelle
|
| 162 |
-
return tokens.map(token =>
|
| 163 |
-
token.length > 3 ? token.charAt(0).toUpperCase() + token.slice(1)
|
| 164 |
-
: token
|
| 165 |
-
).join(' ');
|
| 166 |
-
}
|
| 167 |
-
|
| 168 |
-
console.log(processInput("${text}")); // ${text.split(' ').map(w =>
|
| 169 |
-
w.length > 3 ? w.charAt(0).toUpperCase() + w.slice(1) : w
|
| 170 |
-
).join(' ')}
|
| 171 |
-
\`\`\`
|
| 172 |
-
|
| 173 |
-
2. Suggestions:
|
| 174 |
-
- Implémenter cette logique dans votre projet
|
| 175 |
-
- Ajouter des tests unitaires
|
| 176 |
-
- Optimiser les performances`;
|
| 177 |
-
|
| 178 |
-
addMessage('ai', response);
|
| 179 |
-
|
| 180 |
-
// Update code output
|
| 181 |
-
codeOutput.textContent = `// Résultat pour: ${text}\n${response.split('```javascript')[1].split('```')[0]}`;
|
| 182 |
-
|
| 183 |
-
// Update result preview
|
| 184 |
-
document.querySelector('.result-output').innerHTML = `
|
| 185 |
-
<h3>Résultat</h3>
|
| 186 |
-
<p>${text.split(' ').map(w =>
|
| 187 |
-
w.length > 3 ? w.charAt(0).toUpperCase() + w.slice(1) : w
|
| 188 |
-
).join(' ')}</p>
|
| 189 |
-
`;
|
| 190 |
-
}, 1500);
|
| 191 |
}
|
| 192 |
sendBtn.addEventListener('click', sendMessage);
|
| 193 |
chatInput.addEventListener('keydown', (e) => {
|
|
|
|
| 1 |
+
|
| 2 |
console.log("Interface Espace Codage chargée.");
|
| 3 |
|
| 4 |
+
// ===== Configuration API OpenAI =====
|
| 5 |
+
const OPENAI_API_KEY = "sk-votre_cle_api_ici"; // Remplacez par votre clé API
|
| 6 |
+
|
| 7 |
// ===== Thème (light/dark) =====
|
| 8 |
const themeToggle = document.getElementById('themeToggle');
|
| 9 |
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)');
|
|
|
|
| 116 |
aiActivityText.textContent = text;
|
| 117 |
aiActivityDot.style.background = active ? 'rgb(34,197,94)' : 'rgb(100,116,139)'; // emerald vs slate
|
| 118 |
}
|
| 119 |
+
function getChatHistory() {
|
| 120 |
+
const messages = [];
|
| 121 |
+
const nodes = chatMessages.querySelectorAll('.msg');
|
| 122 |
+
nodes.forEach(node => {
|
| 123 |
+
const role = node.classList.contains('msg-user') ? 'user' : 'assistant';
|
| 124 |
+
const text = node.querySelector('.bubble').textContent.trim();
|
| 125 |
+
messages.push({ role, content: text });
|
| 126 |
+
});
|
| 127 |
+
return messages;
|
| 128 |
+
}
|
| 129 |
function addMessage(role, content) {
|
| 130 |
const msg = document.createElement('div');
|
| 131 |
msg.className = 'msg ' + (role === 'user' ? 'msg-user' : 'msg-ai');
|
|
|
|
| 152 |
'&': '&', '<': '<', '>': '>', '"': '"', "'": '''
|
| 153 |
}[m]));
|
| 154 |
}
|
| 155 |
+
async function sendMessage() {
|
| 156 |
const text = chatInput.value.trim();
|
| 157 |
if (!text) return;
|
| 158 |
addMessage('user', text);
|
| 159 |
chatInput.value = '';
|
|
|
|
| 160 |
setAIActivity('Rosalinda réfléchit...', true);
|
| 161 |
+
try {
|
| 162 |
+
const response = await fetch('https://api.openai.com/v1/chat/completions', {
|
| 163 |
+
method: 'POST',
|
| 164 |
+
headers: {
|
| 165 |
+
'Content-Type': 'application/json',
|
| 166 |
+
'Authorization': `Bearer ${OPENAI_API_KEY}`
|
| 167 |
+
},
|
| 168 |
+
body: JSON.stringify({
|
| 169 |
+
model: 'gpt-3.5-turbo',
|
| 170 |
+
messages: [
|
| 171 |
+
{ role: 'system', content: 'Tu es Rosalinda, une assistante IA utiles et concise.' },
|
| 172 |
+
...getChatHistory(),
|
| 173 |
+
{ role: 'user', content: text }
|
| 174 |
+
],
|
| 175 |
+
temperature: 0.7
|
| 176 |
+
})
|
| 177 |
+
});
|
| 178 |
+
if (!response.ok) {
|
| 179 |
+
throw new Error(`Erreur API: ${response.status} ${response.statusText}`);
|
| 180 |
+
}
|
| 181 |
+
const data = await response.json();
|
| 182 |
+
const assistantMessage = data.choices?.[0]?.message?.content ?? 'Désolé, aucune réponse.';
|
| 183 |
setAIActivity('IA en veille', false);
|
| 184 |
+
addMessage('ai', assistantMessage);
|
| 185 |
+
codeOutput.textContent = assistantMessage;
|
| 186 |
+
} catch (error) {
|
| 187 |
+
console.error(error);
|
| 188 |
+
setAIActivity('IA en veille', false);
|
| 189 |
+
addMessage('ai', 'Une erreur est survenue lors de la communication avec l\'IA.');
|
| 190 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 191 |
}
|
| 192 |
sendBtn.addEventListener('click', sendMessage);
|
| 193 |
chatInput.addEventListener('keydown', (e) => {
|
styles.css
CHANGED
|
@@ -11,20 +11,16 @@ body { margin: 0; font-family: Inter, ui-sans-serif, system-ui, -apple-system, S
|
|
| 11 |
|
| 12 |
/* Container principal en 3 colonnes */
|
| 13 |
.container {
|
| 14 |
-
display:
|
| 15 |
-
grid-template-columns: 20% 30% 50%;
|
| 16 |
height: 100vh;
|
| 17 |
-
gap: 1px;
|
| 18 |
-
background: rgb(226 232 240);
|
| 19 |
-
}
|
| 20 |
-
.dark .container {
|
| 21 |
-
background: rgb(30 41 59);
|
| 22 |
}
|
|
|
|
| 23 |
/* Colonne 1 : Sidebar */
|
| 24 |
.sidebar {
|
| 25 |
-
width:
|
|
|
|
| 26 |
background: rgb(248 250 252); /* slate-50 */
|
| 27 |
-
border-right: 1px solid rgb(226 232 240); /* slate-200 */
|
| 28 |
padding: 16px;
|
| 29 |
display: flex;
|
| 30 |
flex-direction: column;
|
|
@@ -92,7 +88,9 @@ border-right: 1px solid rgb(226 232 240); /* slate-200 */
|
|
| 92 |
|
| 93 |
/* Colonne 2 : Chat */
|
| 94 |
.chat {
|
| 95 |
-
|
|
|
|
|
|
|
| 96 |
flex-direction: column;
|
| 97 |
padding: 16px;
|
| 98 |
gap: 12px;
|
|
@@ -185,9 +183,10 @@ display: flex;
|
|
| 185 |
|
| 186 |
/* Colonne 3 : Output */
|
| 187 |
.output {
|
| 188 |
-
width:
|
|
|
|
| 189 |
background: rgb(252 252 252);
|
| 190 |
-
border-left: 1px solid rgb(226 232 240);
|
| 191 |
display: flex;
|
| 192 |
flex-direction: column;
|
| 193 |
padding: 16px;
|
|
@@ -276,29 +275,8 @@ border-left: 1px solid rgb(226 232 240);
|
|
| 276 |
|
| 277 |
/* Responsive */
|
| 278 |
@media (max-width: 1100px) {
|
| 279 |
-
.container {
|
| 280 |
-
|
| 281 |
-
|
| 282 |
-
}
|
| 283 |
-
|
| 284 |
-
width: 100%;
|
| 285 |
-
border-right: none;
|
| 286 |
-
border-bottom: 1px solid rgb(226 232 240);
|
| 287 |
-
}
|
| 288 |
-
.output {
|
| 289 |
-
width: 100%;
|
| 290 |
-
border-left: none;
|
| 291 |
-
border-top: 1px solid rgb(226 232 240);
|
| 292 |
-
}
|
| 293 |
-
}
|
| 294 |
-
|
| 295 |
-
/* Ensure minimum widths for columns */
|
| 296 |
-
.sidebar {
|
| 297 |
-
min-width: 200px;
|
| 298 |
-
}
|
| 299 |
-
.chat {
|
| 300 |
-
min-width: 300px;
|
| 301 |
-
}
|
| 302 |
-
.output {
|
| 303 |
-
min-width: 400px;
|
| 304 |
-
}
|
|
|
|
| 11 |
|
| 12 |
/* Container principal en 3 colonnes */
|
| 13 |
.container {
|
| 14 |
+
display: flex;
|
|
|
|
| 15 |
height: 100vh;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
}
|
| 17 |
+
|
| 18 |
/* Colonne 1 : Sidebar */
|
| 19 |
.sidebar {
|
| 20 |
+
width: 20%;
|
| 21 |
+
min-width: 240px;
|
| 22 |
background: rgb(248 250 252); /* slate-50 */
|
| 23 |
+
border-right: 1px solid rgb(226 232 240); /* slate-200 */
|
| 24 |
padding: 16px;
|
| 25 |
display: flex;
|
| 26 |
flex-direction: column;
|
|
|
|
| 88 |
|
| 89 |
/* Colonne 2 : Chat */
|
| 90 |
.chat {
|
| 91 |
+
width: 45%;
|
| 92 |
+
min-width: 320px;
|
| 93 |
+
display: flex;
|
| 94 |
flex-direction: column;
|
| 95 |
padding: 16px;
|
| 96 |
gap: 12px;
|
|
|
|
| 183 |
|
| 184 |
/* Colonne 3 : Output */
|
| 185 |
.output {
|
| 186 |
+
width: 35%;
|
| 187 |
+
min-width: 300px;
|
| 188 |
background: rgb(252 252 252);
|
| 189 |
+
border-left: 1px solid rgb(226 232 240);
|
| 190 |
display: flex;
|
| 191 |
flex-direction: column;
|
| 192 |
padding: 16px;
|
|
|
|
| 275 |
|
| 276 |
/* Responsive */
|
| 277 |
@media (max-width: 1100px) {
|
| 278 |
+
.container { flex-direction: column; }
|
| 279 |
+
.sidebar { width: 100%; border-right: none; border-bottom: 1px solid rgb(226 232 240); }
|
| 280 |
+
.chat { width: 100%; }
|
| 281 |
+
.output { width: 100%; }
|
| 282 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|