-
Notifications
You must be signed in to change notification settings - Fork 0
/
background.js
558 lines (461 loc) · 21.2 KB
/
background.js
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
function clearTabStorage(tabId){
let tabIdKey = `store_tab_${tabId}`;
var obj = {};
obj[tabIdKey] = [];
chrome.storage.local.set(obj);
}
function setTabItems(tabId, items, cb){
let tabIdKey = `store_tab_${tabId}`;
chrome.storage.local.get([tabIdKey]).then(result => {
const tabObject = result[tabIdKey] || {};
Object.keys(items).forEach(itemName => {
tabObject[itemName] = items[itemName];
});
let setObj = {};
setObj[tabIdKey] = tabObject;
chrome.storage.local.set(setObj).then(() =>{
cb && cb();
});
});
}
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.type === 'getTabItems') {
let tabIdKey = `store_tab_${sender.tab.id}`;
chrome.storage.local.get([tabIdKey]).then(result => {
const items = {};
(request.itemNames || []).forEach(itemName => {
items[itemName] = result[tabIdKey] && result[tabIdKey][itemName];
});
sendResponse(items);
})
return true;
} else if (request.type === 'setTabItems') {
let tabIdKey = `store_tab_${sender.tab.id}`;
chrome.storage.local.get(tabIdKey).then(result => {
const tabObject = result[tabIdKey] || {};
Object.keys(request.itemNames).forEach(itemName => {
tabObject[itemName] = request.itemNames[itemName];
});
let setObj = {};
setObj[tabIdKey] = tabObject;
chrome.storage.local.set(setObj).then(()=>{
sendResponse({ result: 'success' });
});
});
return true;
} else if (request.type === 'removeTabItems') {
let tabIdKey = `store_tab_${sender.tab.id}`;
chrome.storage.local.get(tabIdKey).then(result => {
const tabObject = result[tabIdKey];
if (tabObject) {
request.itemNames.forEach(itemName => {
delete tabObject[itemName];
});
let setObj = {};
setObj[tabIdKey] = tabObject;
chrome.storage.local.set(setObj).then(()=>{
sendResponse({ result: 'success' });
});
}
});
return true;
}
else if (request.type === 'summarize' || request.type === 'translate'|| request.type === 'correct-english' || request.type === 'teach-me' || request.type === 'simple-chat')
{
/*
request: {
type: command type, e.g summarize, translate, correct-english
selectionText: selection text (text that selected on page)
messages: list all current messages of all roles, include system, user, assistant
}
*/
chrome.storage.sync.get([
'completionProvider',
'groqApiUrl', 'groqApiKey', 'groqModelName', 'groqTemperature', 'groqMaxToken',
'openAiApiUrl', 'openAiApiKey', 'openAiModelName', 'openAiTemperature', 'openAiMaxToken'
], (items) => {
const completionProvider = items.completionProvider || 'groq';
const apiUrl = completionProvider == "groq" ? items.groqApiUrl : items.openAiApiUrl;
const apiKey = completionProvider == "groq" ? items.groqApiKey :items.openAiApiKey;
const modelName = completionProvider == "groq" ? items.groqModelName : items.openAiModelName;
const temperature = completionProvider == "groq" ? (items.groqTemperature || 0) : (items.openAiTemperature || 0);
const maxToken = completionProvider == "groq" ? (items.groqMaxToken || 8192) : (items.openAiMaxToken || 4096);
if (!apiUrl || !apiKey || !modelName) {
//console.error("API URL or API Key or Model Name not configured.");
sendResponse({ error: "API not configured" });
return;
}
const myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
myHeaders.append("Authorization", `Bearer ${apiKey}`);
let requestBody;
let requestObj = {};
switch(request.type){
case "simple-chat":
requestObj = {
messages: [],
model: modelName, // Replace with your actual model
temperature: temperature,
max_tokens: maxToken, //8192,
top_p: 1,
stream: false,
stop: null
};
requestObj.messages = request.messages;
break;
case "summarize":
requestObj = {
messages: [],
model: modelName, // Replace with your actual model
temperature: temperature,
max_tokens: maxToken, //8192,
top_p: 1,
stream: false,
stop: null
};
if (request.selectionText){
requestObj.messages.push({
role: "system",
content: `You are a helpful AI assistant`
});
requestObj.messages.push({
role: "user",
content: `Bạn có thể vui lòng cung cấp một bản tóm tắt ngắn gọn và đầy đủ về văn bản đã cho không?
- Phần tóm tắt phải nắm bắt được những điểm chính, chi tiết chính của văn bản đồng thời truyền tải chính xác ý muốn của tác giả.
- Hãy đảm bảo rằng phần tóm tắt được tổ chức tốt và dễ đọc, có tiêu đề các điểm chính và tiêu đề phụ chi tiết bổ sung rõ ràng để hướng dẫn người đọc qua từng phần.
- Bao gồm một hoặc hai trích dẫn quan trọng từ tài liệu để minh họa các điểm chính hoặc làm nổi bật thông tin quan trọng.
- Độ dài của phần tóm tắt phải phù hợp để nắm bắt được những điểm chính và chi tiết chính của văn bản, không đưa vào những thông tin không thật sự cần thiết.
- Chỉ tóm tắt theo nội dung được cung cấp, không bịa đặt.
- Nếu không có yêu cầu đặc biệt, hãy trả lời bằng ngôn ngữ của câu hỏi mà bạn nhận được
- Câu trả lời phải là định dạng Markdown, có tiêu đề lớn mô tả nội dung, được đặt vào thẻ h2`
});
requestObj.messages.push({
role: "user",
content: `Dưới đây là nội dung cần tóm tắt (You must always answer in Vietnamese (unless otherwise requested)):\n
${request.selectionText}`
});
}
else{
requestObj.messages = request.messages;
}
break;
case "translate":
requestObj = {
messages: [],
model: modelName, //"llama3-70b-8192", // Replace with your actual model
temperature: temperature,
max_tokens: maxToken,
top_p: 1,
stream: false,
stop: null
};
if (request.selectionText){
requestObj.messages.push({
role: "system",
content: `You are a helpful AI assistant`
});
requestObj.messages.push({
role: "user",
content: `Bạn sẽ được đưa 1 câu văn hoặc đoạn văn bên dưới, hãy dịch nội dung sang tiếng Việt, ngược lại, nếu nội dung được cho là tiếng Việt thì dịch sang tiếng Anh.
YÊU CẦU KHI DỊCH:
- Nếu là code hoặc chứa code thì giữ nguyên phần code - không dịch phần code.
- Phát hiện chủ đề, chuyên ngành của nội dung cần dịch và dịch theo đúng chuyên ngành, ví dụ chuyên ngành công nghệ thông tin, lập trình, trí tuệ nhân tạo, AI, machine learning, LLM (ngôn ngữ lớn), thời trang, kiến trúc...
- Những từ hoặc cụm từ thuộc chuyên ngành thì không cần dịch, vì nếu dịch có thể rất tối nghĩa (nên cố gắng giải thích ý nghĩa ngắn gọn trong ngoặc đơn), ví dụ "fine-tuning" (tinh chỉnh)
- Văn phong tốt, diễn đạt trôi chảy, liền mạch, thể hiện sự thông thạo ngôn ngữ của người bản địa, dựa dựa ngôn ngữ và văn hóa của người Việt Nam, tôn trọng sự giàu đẹp của tiếng Việt
- Bản dịch phải rõ ràng các từ, cụm từ viết tắt của bản gốc.
- Nếu không có yêu cầu đặc biệt, hãy trả lời bằng ngôn ngữ của câu hỏi mà bạn nhận được
- Câu trả lời phải là định dạng Markdown
- Chỉ trả lời kết quả, đừng thêm những câu ở đầu như: 'Here is the translation:', 'Here is the translated content:'...."
`
/*
- Chỉ dịch và không tự ý thêm thông tin gì, nhưng nên có 1 bảng tóm tắt giải thích các từ vựng, loại từ, phiên âm IPA UK/US ở dưới cùng cùng với tên chuyên ngành.
### Kết quả dịch
- Hiển thị cả bản gốc và bản dịch (nếu câu cần dịch quá dài thì chỉ hiển thị bản dịch)
- Format đoạn văn để tăng tính nhận diện, dễ đọc, dễ thấy
### Thông tin bổ sung
**Phát âm:**
- Phiên âm: Cung cấp phiên âm IPA để người học biết cách phát âm chính xác.
**Ngữ pháp và từ loại:**
- Từ loại: Hiển thị từ loại của từ đó (danh từ, động từ, tính từ, trạng từ, v.v.).
- Hình thái từ: Bao gồm các dạng khác của từ đó (dạng số nhiều, dạng quá khứ, phân từ, v.v.).
**Định nghĩa:**
- Định nghĩa chi tiết: Cung cấp định nghĩa chi tiết của từ trong ngữ cảnh tiếng Anh.
- Định nghĩa đơn giản: Định nghĩa dễ hiểu hoặc phổ biến hơn cho người mới học.
**Ví dụ câu:**
- Câu ví dụ: Cung cấp câu ví dụ để minh họa cách sử dụng từ đó trong ngữ cảnh.
- Dịch câu ví dụ: Dịch các câu ví dụ sang ngôn ngữ của người học để họ hiểu rõ hơn.
**Ngữ cảnh và từ đồng nghĩa/đối nghĩa:**
- Ngữ cảnh: Giải thích các ngữ cảnh khác nhau mà từ đó có thể được sử dụng.
- Từ đồng nghĩa và từ trái nghĩa: Cung cấp danh sách các từ đồng nghĩa và từ trái nghĩa để mở rộng vốn từ vựng.
**Cụm từ liên quan và thành ngữ:**
- Cụm từ liên quan: Các cụm từ hoặc collocations phổ biến liên quan đến từ đó.
- Thành ngữ: Các thành ngữ hoặc idioms chứa từ đó.
**Ghi chú văn hóa và sử dụng đặc biệt:**
- Ghi chú văn hóa: Giải thích các khác biệt văn hóa hoặc các cách sử dụng đặc biệt của từ trong các ngữ cảnh khác nhau.
- Phong cách sử dụng: Chỉ rõ xem từ đó là trang trọng, thân mật, chuyên ngành hay thông dụng.
*/
});
requestObj.messages.push({
role: "user",
content: `You must always respond in Vietnamese (unless otherwise requested)`
});
requestObj.messages.push({
role: "user",
content: `OK, dưới đây là nội dung cần dịch:\n
${request.selectionText}`
});
}else{
requestObj.messages = request.messages;
}
break;
case "correct-english":
requestObj = {
messages: [],
model: modelName, //"llama3-70b-8192", // Replace with your actual model
temperature: temperature,
max_tokens: maxToken,
top_p: 1,
stream: false,
stop: null
};
if (request.selectionText){
requestObj.messages.push({
role: "system",
content: `You are a helpful AI assistant`
});
requestObj.messages.push({
role: "user",
content: `Bạn sẽ đóng vai là một chuyên gia về ngôn ngữ, có hiểu biết sâu sắc văn hóa bản địa, đặc biệt là tiếng Anh và tiếng Việt, bạn sẽ giúp sửa lỗi tiếng Anh.
- Câu trả lời phải là định dạng markdown
- Đừng đưa ra những câu "introduce prompt words or opening remarks" trong câu trả lời. Hãy đi thẳng vào câu trả lời. Đừng lan man, dài dòng.
- Nếu không có yêu cầu đặc biệt, hãy trả lời bằng ngôn ngữ của câu hỏi mà bạn nhận được
- Từ hoặc câu văn sau khi đã sửa chính xác (ngôn ngữ của câu đã sửa là ngôn ngữ của câu được yêu cầu sửa), ví dụ, bạn được yêu cầu sửa 1 câu tiếng Anh, thì bạn phải trả lời lại 1 câu tiếng Anh đã sửa hoàn chỉnh.
- markdown format, bôi đậm những chỗ đã sửa để highlight, phần giải thích nên được tổ chức tốt, dễ đọc, có outline...
- Nếu câu văn không có lỗi gì, thì chỉ cần nói là không có lỗi, đừng cố bịa ra câu trả lời.`});
// ### Thông tin bổ sung
// **Giải thích lỗi và sửa lỗi:**
// - Mô tả lỗi: Giải thích ngắn gọn lỗi mà người học đã mắc phải (ví dụ: sai ngữ pháp, sai chính tả, sử dụng từ không chính xác, v.v.).
// - Nguyên nhân phổ biến: Cung cấp thông tin về lý do tại sao lỗi này thường xảy ra và làm sao để tránh nó.
// - Cách sửa: Cung cấp giải pháp cụ thể để sửa lỗi.
// - Ví dụ đúng: Cung cấp ví dụ minh họa cách sử dụng đúng.
// **Quy tắc ngữ pháp liên quan:**
// - Quy tắc ngữ pháp: Cung cấp quy tắc ngữ pháp liên quan đến lỗi để người học có thể nắm rõ hơn.
// - Ghi chú ngữ pháp: Giải thích chi tiết hơn về các quy tắc ngữ pháp phức tạp nếu cần.
requestObj.messages.push({
role: "user",
content: `You must always answer in Vietnamese, unless otherwise is requested.`
});
requestObj.messages.push({
role: "user",
content: `OK, dưới đây là câu cần sửa (just correct English grammar, don't translate it):\n
${request.selectionText}`
});
}else{
requestObj.messages = request.messages;
}
break;
case "teach-me":
requestObj = {
messages: [],
model: modelName, //"llama3-70b-8192", // Replace with your actual model
temperature: temperature,
max_tokens: maxToken,
top_p: 1,
stream: false,
stop: null
};
if (request.selectionText){
requestObj.messages.push({
role: "system",
content: `You are a knowledgeable and engaging teacher.
Your goal is to educate the user about various topics they might be interested in.
Make sure the content is well-organized and easy to read, with clear main headings and subheadings that provide detailed supplementary information to guide learners through each section, making it easy for them to follow along.
Provide clear explanations, examples, and answer any questions the user may have.
Make sure to break down complex concepts into simpler terms and relate them to real-world applications when possible.
Be patient, encouraging, and responsive to the user's level of understanding.
Adapt your teaching style based on the user's feedback and engagement.
Always strive to make learning enjoyable and accessible.
IMPORTANT: Be honest, don't make things up.
IMPORTANT: You must always answer in Vietnamese, unless otherwise is requested.`
});
requestObj.messages.push({
role: "user",
content: `OK, please teach me this (always answer me in Vietnamese please from now):\n
${request.selectionText}`
});
}else{
requestObj.messages = request.messages;
}
break;
}
let defaultMessages = JSON.parse(JSON.stringify(requestObj.messages));
//console.log(requestObj);
requestBody = JSON.stringify(requestObj);
const requestOptions = {
method: "POST",
headers: myHeaders,
body: requestBody,
redirect: "follow"
};
fetch(apiUrl, requestOptions)
.then(response => response.json())
.then(data => {
console.log("API Response:", data);
if (data.choices && data.choices[0] && data.choices[0].message) {
msg = data.choices[0].message.content;
requestObj.messages.push({
role: "assistant",
content: msg
});
setTabItems(sender.tab.id, {
defaultMessages: defaultMessages,
lastSelectedCommand: request.type,
chatMessages: requestObj.messages
}, ()=>{
sendResponse({ result: msg });
});
// chrome.tabs.sendMessage(sender.tab.id, {
// type: 'setTabItems',
// itemNames: {
// defaultMessages: defaultMessages,
// lastSelectedCommand: request.type,
// chatMessages: requestObj.messages
// }
// }, res => {
// sendResponse({ result: msg });
// });
// return true;
} else {
let msg = data.error.message;
requestObj.messages.push({
role: "assistant",
content: msg
});
setTabItems(sender.tab.id, {
defaultMessages: defaultMessages,
lastSelectedCommand: request.type,
chatMessages: requestObj.messages
}, ()=>{
sendResponse({ error: msg });
});
// chrome.tabs.sendMessage(sender.tab.id, {
// type: 'setTabItems',
// itemNames: {
// defaultMessages: defaultMessages,
// lastSelectedCommand: request.type,
// chatMessages: requestObj.messages
// }
// }, res => {
// sendResponse({ error: msg });
// });
return true;
}
})
.catch(error => {
//console.error('Error during API request:', error);
let msg = 'API request failed: ' + error.message;
requestObj.messages.push({
role: "assistant",
content: msg
});
setTabItems(sender.tab.id, {
defaultMessages: defaultMessages,
lastSelectedCommand: request.type,
chatMessages: requestObj.messages
}, ()=>{
sendResponse({ error: msg });
});
// chrome.tabs.sendMessage(sender.tab.id, {
// type: 'setTabItems',
// itemNames: {
// defaultMessages: defaultMessages,
// lastSelectedCommand: request.type,
// chatMessages: requestObj.messages
// }
// }, res => {
// sendResponse({ error: msg });
// });
return true;
});
return true;
});
// Keep the message channel open
return true;
}
});
chrome.contextMenus.removeAll();
// Create context menu items
chrome.contextMenus.create({
id: "simple-chat",
title: "Simple Chat",
contexts: ["page"]
});
chrome.contextMenus.create({
id: "summarize",
title: "✨ Summarize Selection",
contexts: ["selection"]
});
chrome.contextMenus.create({
id: "translate",
title: "🌏 Translate Selection",
contexts: ["selection"]
});
chrome.contextMenus.create({
id: "correct-english",
title: "👌 Correct English",
contexts: ["selection"]
});
chrome.contextMenus.create({
id: "teach-me",
title: "🎓 Teach Me This",
contexts: ["selection"]
});
chrome.contextMenus.create({
id: "pronounce",
title: "🔉 Pronounce",
contexts: ["selection"]
});
chrome.contextMenus.onClicked.addListener((info, tab) => {
if (info.menuItemId === 'summarize' ||
info.menuItemId === 'translate' ||
info.menuItemId === 'correct-english' ||
info.menuItemId === 'teach-me' ||
info.menuItemId === 'pronounce' ||
info.menuItemId === 'simple-chat'
) {
//reset chat message
setTabItems(tab.id, {
chatMessages: [],
lastSelectedCommand: info.menuItemId
}, ()=>{
// Send the message to the content script
chrome.tabs.sendMessage(tab.id, {
type: info.menuItemId,
selectionText: info.selectionText,
isNewChat: true
}, (response) => {
// Handle the response from background.js (via content.js)
// if (response.error) {
// console.error(response.error);
// alert("An error occurred: " + response.error);
// } else {
// alert(response.result);
// }
});
});
// clearTabStorage(tab.id);
// chrome.tabs.sendMessage(tab.id, {
// type: 'setTabItems',
// itemNames: {chatMessages: []}
// }, res => {});
}
});
// Listen for tab updates
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
// Set a default value for the tab
//setTabItemValue(tabId, 'foo', 'bar');
});
// Listen for tab removals
chrome.tabs.onRemoved.addListener(function(tabId) {
clearTabStorage(tabId);
});