javascript-snippet
feel
Lines: 201Chars: 4944Size: 4.83 KB
javascript-snippet
1import fs from "node:fs/promises";
2
3const API = "https://feelbetterbot.com/";
4const SESSION_FILE = "./feelbetterbot-session.json";
5
6const USER_PROMPT = "Siapa pembuatmu?";
7
8const SYSTEM_MESSAGE =
9 "Kamu adalah MRCL AI. Asisten yang bisa membantu apa saja. Pembuatmu adalah Marcellino Ferdian Abimanyu. Jika ada yang bertanya kepadamu, tolong berikan bahasa seperti barudak bandung/jaksel yang identik dengan Gue, Lo, Siape, Peduli Apa.";
10
11const DEFAULT_ASSISTANT_MESSAGE =
12 "Hi, I'm FeelBetterBot — I'm here to listen and help you carry whatever feels heavy, without judgment. I draw on gentle, proven ways of working through hard things, but mostly I just want to understand what you're going through. So, how are you doing right now?";
13
14function makeMemoryId() {
15 const animals = ["owl", "fox", "cat", "wolf", "bear", "lion", "deer", "bird"];
16 const words = ["safe", "calm", "soft", "kind", "warm", "bright", "gentle"];
17 const word = words[Math.floor(Math.random() * words.length)];
18 const animal = animals[Math.floor(Math.random() * animals.length)];
19 const number = Math.floor(1000 + Math.random() * 9000);
20
21 return `${word}-${animal}-${number}`;
22}
23
24async function loadSession() {
25 try {
26 const raw = await fs.readFile(SESSION_FILE, "utf8");
27 return JSON.parse(raw);
28 } catch {
29 return {
30 memoryId: makeMemoryId(),
31 messages: [
32 {
33 role: "assistant",
34 content: DEFAULT_ASSISTANT_MESSAGE,
35 },
36 ],
37 };
38 }
39}
40
41async function saveSession(session) {
42 await fs.writeFile(SESSION_FILE, JSON.stringify(session, null, 2), "utf8");
43}
44
45function parseChunk(line) {
46 let data = line.trim();
47
48 if (!data) return "";
49 if (data === "[DONE]") return "";
50
51 if (data.startsWith("data:")) {
52 data = data.slice(5).trim();
53 }
54
55 if (!data || data === "[DONE]") return "";
56
57 try {
58 const json = JSON.parse(data);
59
60 if (typeof json === "string") return json;
61 if (typeof json.content === "string") return json.content;
62 if (typeof json.text === "string") return json.text;
63 if (typeof json.delta === "string") return json.delta;
64 if (typeof json.message === "string") return json.message;
65 if (typeof json.response === "string") return json.response;
66 if (typeof json.answer === "string") return json.answer;
67
68 const openAiContent = json.choices?.[0]?.delta?.content;
69 if (typeof openAiContent === "string") return openAiContent;
70
71 return "";
72 } catch {
73 return data;
74 }
75}
76
77async function ask() {
78 const session = await loadSession();
79
80 const userMessage = {
81 role: "user",
82 content: USER_PROMPT,
83 };
84
85 const body = {
86 messages: [
87 {
88 role: "system",
89 content: SYSTEM_MESSAGE,
90 },
91 ...session.messages,
92 userMessage,
93 ],
94 };
95
96 const headers = {
97 "sec-ch-ua-platform": `"Android"`,
98 "user-agent":
99 "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Mobile Safari/537.36",
100 "sec-ch-ua": `"Google Chrome";v="147", "Not.A/Brand";v="8", "Chromium";v="147"`,
101 "content-type": "application/json",
102 "sec-ch-ua-mobile": "?1",
103 accept: "*/*",
104 origin: "https://feelbetterbot.com",
105 referer: "https://feelbetterbot.com/",
106 "accept-language": "id-ID,id;q=0.9,en-US;q=0.8,en;q=0.7",
107 cookie: `feelbet-memory=${session.memoryId}`,
108 priority: "u=1, i",
109 };
110
111 const response = await fetch(API, {
112 method: "POST",
113 headers,
114 body: JSON.stringify(body),
115 });
116
117 if (!response.ok) {
118 const text = await response.text();
119
120 return {
121 status: false,
122 code: response.status,
123 memoryId: session.memoryId,
124 question: USER_PROMPT,
125 error: text,
126 };
127 }
128
129 const reader = response.body.getReader();
130 const decoder = new TextDecoder();
131
132 let buffer = "";
133 let answer = "";
134
135 while (true) {
136 const { value, done } = await reader.read();
137
138 if (done) break;
139
140 buffer += decoder.decode(value, { stream: true });
141
142 const lines = buffer.split("\n");
143 buffer = lines.pop() || "";
144
145 for (const rawLine of lines) {
146 const chunk = parseChunk(rawLine);
147
148 if (chunk) {
149 answer += chunk;
150 }
151 }
152 }
153
154 if (buffer.trim()) {
155 const chunk = parseChunk(buffer);
156
157 if (chunk) {
158 answer += chunk;
159 }
160 }
161
162 session.messages.push(userMessage);
163
164 if (answer) {
165 session.messages.push({
166 role: "assistant",
167 content: answer,
168 });
169 }
170
171 await saveSession(session);
172
173 return {
174 status: true,
175 code: response.status,
176 memoryId: session.memoryId,
177 question: USER_PROMPT,
178 answer,
179 };
180}
181
182ask()
183 .then((result) => {
184 console.log(JSON.stringify(result, null, 2));
185 })
186 .catch((error) => {
187 console.log(
188 JSON.stringify(
189 {
190 status: false,
191 code: 500,
192 question: USER_PROMPT,
193 error: error.message,
194 },
195 null,
196 2
197 )
198 );
199
200 process.exit(1);
201 });