Abmacode12 commited on
Commit
fa7f49a
·
verified ·
1 Parent(s): 6f4b8e1

) Ce qui est possible “illimité”

Browse files

Micro (STT) + Voix (TTS) : possible “gratuit” via le navigateur (Chrome/Edge) ✅

IA qui répond vraiment intelligemment : il faut un modèle (local sur ton PC, ou via une API). Là, ce n’est jamais réellement illimité, il y aura soit une limite matérielle (local), soit des quotas (API). Je te propose les 2 options.

2) Option A (simple, rapide) : Rosalinda fonctionne en local avec “IA de base” + micro + voix

👉 Tu auras :

Tu parles → Rosalinda écrit ce qu’elle a entendu

Rosalinda répond en texte

Rosalinda lit sa réponse à voix haute

Crée ce fichier : rosalinda.html

(Ouvre-le dans Chrome/Edge)

<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Rosalinda — Espace Codage</title>
<style>
body{margin:0;font-family:system-ui;background:#0b0f16;color:#fff}
.wrap{max-width:980px;margin:0 auto;padding:18px}
.top{display:flex;gap:10px;align-items:center;justify-content:space-between}
.badge{padding:8px 12px;border:1px solid rgba(255,255,255,.12);border-radius:999px;background:rgba(255,255,255,.04)}
.chat{margin-top:14px;border:1px solid rgba(255,255,255,.12);border-radius:16px;overflow:hidden;background:rgba(255,255,255,.03)}
.msgs{height:55vh;overflow:auto;padding:14px;display:flex;flex-direction:column;gap:10px}
.msg{max-width:85%;padding:10px 12px;border-radius:14px;border:1px solid rgba(255,255,255,.10)}
.me{margin-left:auto;background:rgba(93,173,255,.10)}
.ai{background:rgba(255,255,255,.04)}
.row{display:flex;gap:10px;align-items:center;padding:12px;border-top:1px solid rgba(255,255,255,.10)}
input{flex:1;background:transparent;border:1px solid rgba(255,255,255,.12);border-radius:14px;padding:12px;color:#fff;outline:none}
button{border:1px solid rgba(255,255,255,.12);background:rgba(255,255,255,.05);color:#fff;border-radius:14px;padding:10px 12px;cursor:pointer}
button:disabled{opacity:.5;cursor:not-allowed}
.small{color:rgba(255,255,255,.65);font-size:12px;margin-top:10px;line-height:1.4}
</style>
</head>
<body>
<div class="wrap">
<div class="top">
<div class="badge"><b>Rosalinda</b> — Espace Codage</div>
<div class="badge" id="status">Micro: prêt</div>
</div>

<div class="chat">
<div class="msgs" id="msgs"></div>
<div class="row">
<button id="micBtn">🎤</button>
<input id="inp" placeholder="Écris à Rosalinda…" />
<button id="sendBtn">➤</button>
<button id="speakBtn" title="Lire la dernière réponse">🔊</button>
</div>
</div>

<div class="small">
✅ Micro & voix = API du navigateur (Chrome/Edge).<br>
⚠️ Cette version répond avec une “IA locale simple” (règles). Étape suivante : brancher un vrai modèle IA (local ou API).
</div>
</div>

<script>
const msgs = document.getElementById("msgs");
const inp = document.getElementById("inp");
const sendBtn = document.getElementById("sendBtn");
const micBtn = document.getElementById("micBtn");
const speakBtn = document.getElementById("speakBtn");
const statusEl = document.getElementById("status");

let lastAIText = "";

function addMsg(text, who){
const div = document.createElement("div");
div.className = "msg " + (who === "me" ? "me" : "ai");
div.textContent = text;
msgs.appendChild(div);
msgs.scrollTop = msgs.scrollHeight;
}

// IA simple (placeholder) : on remplace ça par un vrai modèle à l'étape suivante
function rosalindaBrain(userText){
const t = userText.toLowerCase();
if (t.includes("bonjour") || t.includes("salut")) return "Bonjour 😄 Je suis Rosalinda. Dis-moi ce que tu veux créer : site, thème, image, vidéo, plugin…";
if (t.includes("theme") || t.includes("thème")) return "Ok ✅ Dis-moi : (1) style (moderne, luxe, minimal, flashy), (2) couleurs, (3) 3 colonnes ou non, (4) Shopify/WooCommerce/autre.";
if (t.includes("image")) return "Je peux préparer une demande d’image. Dis-moi : sujet + style + format (1:1, 16:9, 9:16) + texte à afficher.";
if (t.includes("vidéo") || t.includes("video")) return "Je peux préparer une demande vidéo. Dis-moi : durée, style (réaliste/3D), texte à l’écran, musique oui/non.";
if (t.includes("micro")) return "Pour le micro : clique 🎤, autorise le micro dans ton navigateur, puis parle. Je transcris et je réponds.";
return "Compris ✅ Donne-moi plus de détails (objectif + plateforme + style), et je te génère une réponse claire.";
}

function speak(text){
if (!("speechSynthesis" in window)) {
alert("TTS non supporté sur ce navigateur.");
return;
}
const u = new SpeechSynthesisUtterance(text);
u.lang = "fr-FR";
window.speechSynthesis.cancel();
window.speechSynthesis.speak(u);
}

function handleSend(text){
const v = (text ?? inp.value).trim();
if (!v) return;
addMsg(v, "me");
inp.value = "";
const reply = rosalindaBrain(v);
lastAIText = reply;
addMsg(reply, "ai");
speak(reply); // réponse vocale automatique
}

sendBtn.onclick = () => handleSend();
inp.addEventListener("keydown", (e) => {
if (e.key === "Enter") handleSend();
});

speakBtn.onclick = () => lastAIText && speak(lastAIText);

// Micro (STT)
let rec = null;
let listening = false;

function setupSTT(){
const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
if (!SR) return null;
const r = new SR();
r.lang = "fr-FR";
r.interimResults = true;
r.continuous = false;
return r;
}

rec = setupSTT();

micBtn.onclick = async () => {
if (!rec){
alert("Reconnaissance vocale non disponible ici. Essaie Chrome/Edge.");
return;
}
if (listening) return;

listening = true;
statusEl.textContent = "Micro: écoute…";
let finalText = "";

rec.onresult = (e) => {
let transcript = "";
for (let i = e.resultIndex; i < e.results.length; i++){
transcript += e.results[i][0].transcript;
if (e.results[i].isFinal) finalText += e.results[i][0].transcript + " ";
}
inp.value = (finalText || transcript).trim();
};

rec.onerror = () => {
listening = false;
statusEl.textContent = "Micro: erreur";
};

rec.onend = () => {
listening = false;
statusEl.textContent = "Micro: prêt";
if (inp.value.trim()) handleSend(inp.value);
};

try { rec.start(); } catch (e) {
listening = false;
statusEl.textContent = "Micro: prêt";
}
};

// Message de démarrage
addMsg("Bonjour 👋 Je suis Rosalinda. Clique 🎤 pour parler ou écris-moi.", "ai");
</script>
</body>
</html>


✅ Là, tu as déjà Rosalinda qui parle + écoute + répond.

3) Étape suivante : brancher un “vrai cerveau” (LLM)

Pour que Rosalinda puisse vraiment générer du code, répondre comme une vraie IA, etc., tu as 2 chemins :

Option B — IA en local (pas de facturation, mais dépend de ton PC)

Installer un moteur LLM local (ex : Ollama)

Ton backend Node appelle http://localhost:11434/api/chat
Avantage : pas d’API payante. Inconvénient : dépend de la puissance.

Option C — IA via API (plus simple, souvent plus puissant)

Tu mets une clé API dans un .env

Ton backend Node appelle un modèle
Avantage : qualité + stabilité. Inconvénient : quotas.

Si tu me dis juste “local” ou “API”, je te donne le backend complet (Express + endpoint /api/chat) prêt à coller.

Files changed (3) hide show
  1. index.html +7 -1
  2. rosalinda.html +163 -0
  3. style.css +5 -0
index.html CHANGED
@@ -51,7 +51,13 @@
51
  </div>
52
  <span>Bibliothèque</span>
53
  </a>
54
- <a href="#" class="flex items-center gap-3 p-2 rounded-lg hover:bg-gray-700 mb-1">
 
 
 
 
 
 
55
  <div class="p-2 bg-gray-600 rounded-lg">
56
  <i data-feather="settings" class="w-4 h-4"></i>
57
  </div>
 
51
  </div>
52
  <span>Bibliothèque</span>
53
  </a>
54
+ <a href="rosalinda.html" class="flex items-center gap-3 p-2 rounded-lg hover:bg-gray-700 mb-1">
55
+ <div class="p-2 bg-gray-600 rounded-lg">
56
+ <i data-feather="message-circle" class="w-4 h-4"></i>
57
+ </div>
58
+ <span>Rosalinda</span>
59
+ </a>
60
+ <a href="#" class="flex items-center gap-3 p-2 rounded-lg hover:bg-gray-700 mb-1">
61
  <div class="p-2 bg-gray-600 rounded-lg">
62
  <i data-feather="settings" class="w-4 h-4"></i>
63
  </div>
rosalinda.html ADDED
@@ -0,0 +1,163 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="fr">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Rosalinda — Espace Codage</title>
7
+ <link rel="stylesheet" href="style.css">
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <script src="https://unpkg.com/feather-icons"></script>
10
+ </head>
11
+ <body class="bg-gray-900 text-gray-100 min-h-screen">
12
+ <div class="container mx-auto p-4 max-w-4xl">
13
+ <div class="flex justify-between items-center mb-4">
14
+ <div class="px-4 py-2 bg-gray-800 rounded-full border border-gray-700">
15
+ <span class="font-bold">Rosalinda</span> — Espace Codage
16
+ </div>
17
+ <div class="px-4 py-2 bg-gray-800 rounded-full border border-gray-700" id="status">
18
+ Micro: prêt
19
+ </div>
20
+ </div>
21
+
22
+ <div class="bg-gray-800 rounded-xl border border-gray-700 overflow-hidden">
23
+ <div class="h-[60vh] overflow-y-auto p-4 flex flex-col gap-3" id="msgs"></div>
24
+
25
+ <div class="p-3 border-t border-gray-700 bg-gray-900/50 flex items-center gap-2">
26
+ <button id="micBtn" class="p-2 rounded-lg hover:bg-gray-700">
27
+ <i data-feather="mic"></i>
28
+ </button>
29
+ <input id="inp" type="text" placeholder="Écris à Rosalinda…"
30
+ class="flex-1 bg-gray-700 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
31
+ <button id="sendBtn" class="p-2 rounded-lg bg-blue-600 hover:bg-blue-500 text-white">
32
+ <i data-feather="send"></i>
33
+ </button>
34
+ <button id="speakBtn" title="Lire la dernière réponse" class="p-2 rounded-lg hover:bg-gray-700">
35
+ <i data-feather="volume-2"></i>
36
+ </button>
37
+ </div>
38
+ </div>
39
+
40
+ <div class="text-sm text-gray-400 mt-4">
41
+ ✅ Micro & voix = API du navigateur (Chrome/Edge).<br>
42
+ ⚠️ Cette version répond avec une "IA locale simple". Prochaine étape : brancher un vrai modèle IA.
43
+ </div>
44
+ </div>
45
+
46
+ <script>
47
+ feather.replace();
48
+
49
+ const msgs = document.getElementById("msgs");
50
+ const inp = document.getElementById("inp");
51
+ const sendBtn = document.getElementById("sendBtn");
52
+ const micBtn = document.getElementById("micBtn");
53
+ const speakBtn = document.getElementById("speakBtn");
54
+ const statusEl = document.getElementById("status");
55
+
56
+ let lastAIText = "";
57
+
58
+ function addMsg(text, who) {
59
+ const msgDiv = document.createElement("div");
60
+ msgDiv.className = `p-3 rounded-lg max-w-[80%] ${who === "me" ? "ml-auto bg-blue-900/30" : "mr-auto bg-gray-700"}`;
61
+ msgDiv.textContent = text;
62
+ msgs.appendChild(msgDiv);
63
+ msgs.scrollTop = msgs.scrollHeight;
64
+ }
65
+
66
+ function rosalindaBrain(userText) {
67
+ const t = userText.toLowerCase();
68
+ if (t.includes("bonjour") || t.includes("salut")) return "Bonjour 😄 Je suis Rosalinda. Dis-moi ce que tu veux créer : site, thème, image, vidéo, plugin…";
69
+ if (t.includes("theme") || t.includes("thème")) return "Ok ✅ Dis-moi : (1) style (moderne, luxe, minimal, flashy), (2) couleurs, (3) 3 colonnes ou non, (4) Shopify/WooCommerce/autre.";
70
+ if (t.includes("image")) return "Je peux préparer une demande d'image. Dis-moi : sujet + style + format (1:1, 16:9, 9:16) + texte à afficher.";
71
+ if (t.includes("vidéo") || t.includes("video")) return "Je peux préparer une demande vidéo. Dis-moi : durée, style (réaliste/3D), texte à l'écran, musique oui/non.";
72
+ if (t.includes("micro")) return "Pour le micro : clique 🎤, autorise le micro dans ton navigateur, puis parle. Je transcris et je réponds.";
73
+ return "Compris ✅ Donne-moi plus de détails (objectif + plateforme + style), et je te génère une réponse claire.";
74
+ }
75
+
76
+ function speak(text) {
77
+ if (!("speechSynthesis" in window)) {
78
+ alert("TTS non supporté sur ce navigateur.");
79
+ return;
80
+ }
81
+ const utterance = new SpeechSynthesisUtterance(text);
82
+ utterance.lang = "fr-FR";
83
+ window.speechSynthesis.cancel();
84
+ window.speechSynthesis.speak(utterance);
85
+ }
86
+
87
+ function handleSend(text) {
88
+ const inputText = (text ?? inp.value).trim();
89
+ if (!inputText) return;
90
+ addMsg(inputText, "me");
91
+ inp.value = "";
92
+ const reply = rosalindaBrain(inputText);
93
+ lastAIText = reply;
94
+ addMsg(reply, "ai");
95
+ speak(reply);
96
+ }
97
+
98
+ sendBtn.addEventListener("click", () => handleSend());
99
+ inp.addEventListener("keydown", (e) => {
100
+ if (e.key === "Enter") handleSend();
101
+ });
102
+
103
+ speakBtn.addEventListener("click", () => lastAIText && speak(lastAIText));
104
+
105
+ let recognition = null;
106
+ let isListening = false;
107
+
108
+ function setupSpeechRecognition() {
109
+ const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
110
+ if (!SpeechRecognition) return null;
111
+ const recognizer = new SpeechRecognition();
112
+ recognizer.lang = "fr-FR";
113
+ recognizer.interimResults = true;
114
+ recognizer.continuous = false;
115
+ return recognizer;
116
+ }
117
+
118
+ recognition = setupSpeechRecognition();
119
+
120
+ micBtn.addEventListener("click", async () => {
121
+ if (!recognition) {
122
+ alert("Reconnaissance vocale non disponible ici. Essaie Chrome/Edge.");
123
+ return;
124
+ }
125
+ if (isListening) return;
126
+
127
+ isListening = true;
128
+ statusEl.textContent = "Micro: écoute…";
129
+ let finalText = "";
130
+
131
+ recognition.onresult = (e) => {
132
+ let transcript = "";
133
+ for (let i = e.resultIndex; i < e.results.length; i++) {
134
+ transcript += e.results[i][0].transcript;
135
+ if (e.results[i].isFinal) finalText += e.results[i][0].transcript + " ";
136
+ }
137
+ inp.value = (finalText || transcript).trim();
138
+ };
139
+
140
+ recognition.onerror = () => {
141
+ isListening = false;
142
+ statusEl.textContent = "Micro: erreur";
143
+ };
144
+
145
+ recognition.onend = () => {
146
+ isListening = false;
147
+ statusEl.textContent = "Micro: prêt";
148
+ if (inp.value.trim()) handleSend(inp.value);
149
+ };
150
+
151
+ try {
152
+ recognition.start();
153
+ } catch (e) {
154
+ isListening = false;
155
+ statusEl.textContent = "Micro: prêt";
156
+ }
157
+ });
158
+
159
+ // Initial message
160
+ addMsg("Bonjour 👋 Je suis Rosalinda. Clique sur le micro pour parler ou écris-moi.", "ai");
161
+ </script>
162
+ </body>
163
+ </html>
style.css CHANGED
@@ -17,6 +17,11 @@
17
  ::-webkit-scrollbar-thumb:hover {
18
  background: rgba(255, 255, 255, 0.2);
19
  }
 
 
 
 
 
20
 
21
  /* Animation for empty state icons */
22
  @keyframes pulse {
 
17
  ::-webkit-scrollbar-thumb:hover {
18
  background: rgba(255, 255, 255, 0.2);
19
  }
20
+ /* Chat message styles */
21
+ #msgs {
22
+ scrollbar-width: thin;
23
+ scrollbar-color: rgba(255,255,255,0.1) rgba(255,255,255,0.05);
24
+ }
25
 
26
  /* Animation for empty state icons */
27
  @keyframes pulse {