-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.js
More file actions
132 lines (112 loc) · 3.29 KB
/
app.js
File metadata and controls
132 lines (112 loc) · 3.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// ------------------------------
// DOM ELEMENTS (must be first)
// ------------------------------
const chatBody = document.getElementById("chat-body");
const userInput = document.getElementById("user-input");
const sendBtn = document.getElementById("send-btn");
const voiceBtn = document.getElementById("voice-btn");
const loginBtn = document.getElementById("login-btn");
const logoutBtn = document.getElementById("logout-btn");
const userPill = document.getElementById("user-pill");
// ------------------------------
// 1. WebLLM — browser AI
// ------------------------------
let ai = null;
async function initAI() {
try {
// createChatModule is deprecated; use CreateMLCEngine
ai = await window.webllm.CreateMLCEngine(
"Qwen2.5-1.5B-Instruct-q4f16_1-MLC"
);
appendSystem("Synthwave AI is online.");
} catch (err) {
appendSystem("AI failed to load. Check WebLLM CDN.");
console.error(err);
}
}
initAI();
// ------------------------------
// 2. Chat UI + history
// ------------------------------
const HISTORY_KEY = "synthwave_history";
let messages = JSON.parse(localStorage.getItem(HISTORY_KEY) || "[]");
function saveHistory() {
localStorage.setItem(HISTORY_KEY, JSON.stringify(messages));
}
function appendMessage(role, text) {
const div = document.createElement("div");
div.className = `message ${role}`;
div.textContent = text;
chatBody.appendChild(div);
chatBody.scrollTop = chatBody.scrollHeight;
}
function appendSystem(text) {
appendMessage("ai", text);
}
messages.forEach(m => appendMessage(m.role, m.text));
// ------------------------------
// 3. Word filter
// ------------------------------
const blocked = ["badword1", "badword2"];
function filterText(t) {
let out = t;
blocked.forEach(w => {
const r = new RegExp(w, "gi");
out = out.replace(r, "***");
});
return out;
}
// ------------------------------
// 4. Send message
// ------------------------------
sendBtn.onclick = async () => {
const text = filterText(userInput.value.trim());
if (!text) return;
appendMessage("user", text);
messages.push({ role: "user", text });
saveHistory();
userInput.value = "";
if (!ai) {
appendSystem("AI not ready yet.");
return;
}
const reply = await ai.generate(text);
appendMessage("ai", reply);
messages.push({ role: "ai", text: reply });
saveHistory();
};
// ------------------------------
// 5. Voice input
// ------------------------------
if ("webkitSpeechRecognition" in window) {
const rec = new webkitSpeechRecognition();
rec.lang = "en-US";
voiceBtn.onclick = () => rec.start();
rec.onresult = e => {
userInput.value += " " + e.results[0][0].transcript;
};
} else {
voiceBtn.disabled = true;
}
// ------------------------------
// 6. Firebase Auth
// ------------------------------
const auth = window.firebaseAuth;
const {
onAuthStateChanged,
signInWithEmailAndPassword,
createUserWithEmailAndPassword,
signInAnonymously,
signOut
} = window.firebaseAuthFns;
loginBtn.onclick = () => signInAnonymously(auth);
logoutBtn.onclick = () => signOut(auth);
onAuthStateChanged(auth, user => {
if (user) {
userPill.textContent = user.isAnonymous ? "Guest" : user.email;
logoutBtn.style.display = "inline-block";
} else {
userPill.textContent = "";
logoutBtn.style.display = "none";
}
});