decant-core 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/ai/gemini.js CHANGED
@@ -1,105 +1,126 @@
1
- import { ChatParser } from './base.js';
2
- import { convertToMarkdown } from '../utils/html-to-markdown.js';
1
+ import { ChatParser } from "./base.js";
2
+ import { convertToMarkdown } from "../utils/html-to-markdown.js";
3
3
 
4
4
  export class GeminiParser extends ChatParser {
5
- name = 'Gemini';
5
+ name = "Gemini";
6
6
  isAvailable(url) {
7
- return url.includes('gemini.google.com');
7
+ return url.includes("gemini.google.com");
8
8
  }
9
9
 
10
10
  async parse() {
11
- console.log('[Gemini Parser] ========== STARTING PARSE() ==========');
11
+ console.log("[Gemini Parser] ========== STARTING PARSE() ==========");
12
12
 
13
13
  try {
14
14
  //1. Title Extraction - Enhanced for Deep Research
15
- let title = '';
15
+ let title = "";
16
16
 
17
17
  const isInsideMessage = (el) => {
18
18
  return !!el.closest(
19
- 'user-query, model-response, .conversation-container, message-content, .query-text, .markdown',
19
+ "user-query, model-response, .conversation-container, message-content, .query-text, .markdown",
20
20
  );
21
21
  };
22
22
 
23
23
  // Strategy 1: Using document.title
24
- console.log('[Gemini Parser] Strategy 1: Looking at document.title...');
24
+ console.log("[Gemini Parser] Strategy 1: Looking at document.title...");
25
25
  if (document.title) {
26
26
  const cleanedDocTitle = document.title
27
- .replace(/Google/g, '')
28
- .replace(/Gemini/g, '')
29
- .replace(/Advanced/g, '')
30
- .replace(/- /g, '')
31
- .replace(/—/g, '')
27
+ .replace(/Google/g, "")
28
+ .replace(/Gemini/g, "")
29
+ .replace(/Advanced/g, "")
30
+ .replace(/- /g, "")
31
+ .replace(/—/g, "")
32
32
  .trim();
33
33
 
34
34
  const isGeneric =
35
35
  !cleanedDocTitle ||
36
- cleanedDocTitle.toLowerCase() === 'new chat' ||
37
- cleanedDocTitle.toLowerCase() === 'help' ||
38
- cleanedDocTitle.toLowerCase() === 'settings';
36
+ cleanedDocTitle.toLowerCase() === "new chat" ||
37
+ cleanedDocTitle.toLowerCase() === "help" ||
38
+ cleanedDocTitle.toLowerCase() === "settings";
39
39
 
40
40
  if (cleanedDocTitle && !isGeneric && cleanedDocTitle.length > 2) {
41
41
  title = cleanedDocTitle;
42
- console.log('[Gemini Parser] Title set from Strategy 1 (document.title):', title);
42
+ console.log(
43
+ "[Gemini Parser] Title set from Strategy 1 (document.title):",
44
+ title,
45
+ );
43
46
  }
44
47
  }
45
48
 
46
49
  // Strategy 2: Looking for active navigation
47
50
  if (!title) {
48
- console.log('[Gemini Parser] Strategy 2: Looking for active navigation...');
49
- const activeNav = document.querySelector('a[aria-current="page"], .selected');
51
+ console.log(
52
+ "[Gemini Parser] Strategy 2: Looking for active navigation...",
53
+ );
54
+ const activeNav = document.querySelector(
55
+ 'a[aria-current="page"], .selected',
56
+ );
50
57
  if (activeNav) {
51
58
  const navText = activeNav.innerText
52
- .replace(/more_vert/g, '')
53
- .replace(/\n/g, ' ')
59
+ .replace(/more_vert/g, "")
60
+ .replace(/\n/g, " ")
54
61
  .trim();
55
- if (navText && navText.length > 2 && !navText.toLowerCase().includes('new chat')) {
62
+ if (
63
+ navText &&
64
+ navText.length > 2 &&
65
+ !navText.toLowerCase().includes("new chat")
66
+ ) {
56
67
  title = navText;
57
- console.log('[Gemini Parser] Title set from Strategy 2 (active navigation):', title);
68
+ console.log(
69
+ "[Gemini Parser] Title set from Strategy 2 (active navigation):",
70
+ title,
71
+ );
58
72
  }
59
73
  }
60
74
  }
61
75
 
62
76
  // Strategy 3: Check for Deep Research title patterns
63
77
  if (!title) {
64
- console.log('[Gemini Parser] Strategy 3: Looking for Deep Research title patterns...');
78
+ console.log(
79
+ "[Gemini Parser] Strategy 3: Looking for Deep Research title patterns...",
80
+ );
65
81
  const deepResearchTitle = document.querySelector(
66
82
  'h1, .title, .conversation-title, [data-testid="title"]',
67
83
  );
68
84
  if (deepResearchTitle && !isInsideMessage(deepResearchTitle)) {
69
85
  const text = deepResearchTitle.innerText.trim();
70
- console.log('[Gemini Parser] Found potential title:', text);
86
+ console.log("[Gemini Parser] Found potential title:", text);
71
87
  if (
72
88
  text.length > 5 &&
73
- !text.includes('Gemini') &&
74
- !text.includes('Help') &&
75
- !text.includes('Settings')
89
+ !text.includes("Gemini") &&
90
+ !text.includes("Help") &&
91
+ !text.includes("Settings")
76
92
  ) {
77
93
  title = text;
78
- console.log('[Gemini Parser] Title set from Strategy 3:', title);
94
+ console.log("[Gemini Parser] Title set from Strategy 3:", title);
79
95
  }
80
96
  }
81
97
  }
82
98
 
83
99
  // Strategy 4: Look for title in page content (Deep Research reports often have titles in content)
84
100
  if (!title) {
85
- console.log('[Gemini Parser] Strategy 4: Looking for title in page content...');
101
+ console.log(
102
+ "[Gemini Parser] Strategy 4: Looking for title in page content...",
103
+ );
86
104
  const contentTitles = document.querySelectorAll(
87
- 'main h1, main h2, article h1, article h2, .content h1, .content h2',
105
+ "main h1, main h2, article h1, article h2, .content h1, .content h2",
106
+ );
107
+ console.log(
108
+ "[Gemini Parser] Found content titles:",
109
+ contentTitles.length,
88
110
  );
89
- console.log('[Gemini Parser] Found content titles:', contentTitles.length);
90
111
  for (const el of contentTitles) {
91
112
  if (isInsideMessage(el)) continue;
92
113
  const text = el.innerText.trim();
93
114
  if (
94
115
  text.length > 5 &&
95
- !text.includes('Gemini') &&
96
- !text.includes('Help') &&
97
- !text.includes('Settings') &&
98
- !text.includes('Prompt:') &&
99
- !text.includes('Response:')
116
+ !text.includes("Gemini") &&
117
+ !text.includes("Help") &&
118
+ !text.includes("Settings") &&
119
+ !text.includes("Prompt:") &&
120
+ !text.includes("Response:")
100
121
  ) {
101
122
  title = text;
102
- console.log('[Gemini Parser] Title set from Strategy 4:', title);
123
+ console.log("[Gemini Parser] Title set from Strategy 4:", title);
103
124
  break;
104
125
  }
105
126
  }
@@ -107,25 +128,30 @@ export class GeminiParser extends ChatParser {
107
128
 
108
129
  // Strategy 5: Top Bar or Sidebar (original logic)
109
130
  if (!title) {
110
- console.log('[Gemini Parser] Strategy 5: Looking for title in top bar/sidebar...');
131
+ console.log(
132
+ "[Gemini Parser] Strategy 5: Looking for title in top bar/sidebar...",
133
+ );
111
134
  const possibleHeaders = document.querySelectorAll(
112
135
  'h1, button[aria-haspopup="true"], button[aria-expanded]',
113
136
  );
114
- console.log('[Gemini Parser] Found possible headers:', possibleHeaders.length);
137
+ console.log(
138
+ "[Gemini Parser] Found possible headers:",
139
+ possibleHeaders.length,
140
+ );
115
141
 
116
142
  for (const el of possibleHeaders) {
117
143
  if (isInsideMessage(el)) continue;
118
144
  const text = el.innerText.trim();
119
145
  if (
120
146
  text.length > 5 &&
121
- !text.includes('Gemini') &&
122
- !text.includes('Help') &&
123
- !text.includes('Settings')
147
+ !text.includes("Gemini") &&
148
+ !text.includes("Help") &&
149
+ !text.includes("Settings")
124
150
  ) {
125
151
  const rect = el.getBoundingClientRect();
126
152
  if (rect.top < 100 && rect.left > 50) {
127
153
  title = text;
128
- console.log('[Gemini Parser] Title set from Strategy 5:', title);
154
+ console.log("[Gemini Parser] Title set from Strategy 5:", title);
129
155
  break;
130
156
  }
131
157
  }
@@ -133,80 +159,90 @@ export class GeminiParser extends ChatParser {
133
159
  }
134
160
 
135
161
  if (!title || title.length < 2) {
136
- title = 'Gemini Conversation';
162
+ title = "Gemini Conversation";
137
163
  }
138
164
 
139
- console.log('[Gemini Parser] Final title:', title);
165
+ console.log("[Gemini Parser] Final title:", title);
140
166
 
141
167
  const messages = [];
142
168
  const seenTexts = new Set();
143
169
 
144
- console.log('[Gemini Parser] Starting content extraction...');
170
+ console.log("[Gemini Parser] Starting content extraction...");
145
171
  let extractionAttempted = false;
146
172
 
147
173
  // 2. Content Extraction - Enhanced for Deep Research
148
174
  // Try multiple strategies to extract content
149
175
 
150
176
  // Strategy 1: Original conversation containers
151
- console.log('[Gemini Parser] Strategy 1: Looking for conversation containers...');
152
- const conversationContainers = document.querySelectorAll('.conversation-container');
153
- console.log('[Gemini Parser] Found conversation containers:', conversationContainers.length);
177
+ console.log(
178
+ "[Gemini Parser] Strategy 1: Looking for conversation containers...",
179
+ );
180
+ const conversationContainers = document.querySelectorAll(
181
+ ".conversation-container",
182
+ );
183
+ console.log(
184
+ "[Gemini Parser] Found conversation containers:",
185
+ conversationContainers.length,
186
+ );
154
187
  if (conversationContainers.length > 0) {
155
- console.log('[Gemini Parser] Processing conversation containers...');
188
+ console.log("[Gemini Parser] Processing conversation containers...");
156
189
  extractionAttempted = true;
157
190
  conversationContainers.forEach((container) => {
158
- console.log('[Gemini Parser] Processing conversation container...');
191
+ console.log("[Gemini Parser] Processing conversation container...");
159
192
 
160
193
  // First, check for user query
161
- const userQuery = container.querySelector('user-query');
194
+ const userQuery = container.querySelector("user-query");
162
195
  if (userQuery) {
163
- console.log('[Gemini Parser] Found user query...');
164
- const queryText = userQuery.querySelector('.query-text');
196
+ console.log("[Gemini Parser] Found user query...");
197
+ const queryText = userQuery.querySelector(".query-text");
165
198
  if (queryText) {
166
- console.log('[Gemini Parser] Found query text...');
199
+ console.log("[Gemini Parser] Found query text...");
167
200
  const clone = queryText.cloneNode(true);
168
201
  clone
169
- .querySelectorAll('.cdk-visually-hidden, [class*="screen-reader"]')
202
+ .querySelectorAll(
203
+ '.cdk-visually-hidden, [class*="screen-reader"]',
204
+ )
170
205
  .forEach((el) => el.remove());
171
206
  const userText = clone.innerText.trim();
172
207
  if (userText && !seenTexts.has(userText)) {
173
208
  seenTexts.add(userText);
174
209
  messages.push({
175
- role: 'User',
210
+ role: "User",
176
211
  content: userText,
177
212
  });
178
213
  console.log(
179
- '[Gemini Parser] Added user message:',
180
- userText.substring(0, 50) + '...',
214
+ "[Gemini Parser] Added user message:",
215
+ userText.substring(0, 50) + "...",
181
216
  );
182
217
  }
183
218
  }
184
219
  }
185
220
 
186
221
  // Then, check for model response
187
- const modelResponse = container.querySelector('model-response');
222
+ const modelResponse = container.querySelector("model-response");
188
223
  if (modelResponse) {
189
- console.log('[Gemini Parser] Found model response...');
190
- const messageContent = modelResponse.querySelector('message-content');
224
+ console.log("[Gemini Parser] Found model response...");
225
+ const messageContent =
226
+ modelResponse.querySelector("message-content");
191
227
  if (messageContent) {
192
- console.log('[Gemini Parser] Found message content...');
228
+ console.log("[Gemini Parser] Found message content...");
193
229
  const markdownDiv = messageContent.querySelector(
194
- '.markdown.markdown-main-panel, .markdown',
230
+ ".markdown.markdown-main-panel, .markdown",
195
231
  );
196
232
  if (markdownDiv) {
197
- console.log('[Gemini Parser] Found markdown div...');
233
+ console.log("[Gemini Parser] Found markdown div...");
198
234
  // Clone to avoid modifying the original DOM
199
235
  const clone = markdownDiv.cloneNode(true);
200
236
 
201
237
  // Remove UI elements that shouldn't be in the export
202
238
  clone
203
239
  .querySelectorAll(
204
- 'button, .thoughts-container, .thoughts-wrapper, model-thoughts, .table-footer, .hide-from-message-actions',
240
+ "button, .thoughts-container, .thoughts-wrapper, model-thoughts, .table-footer, .hide-from-message-actions",
205
241
  )
206
242
  .forEach((el) => el.remove());
207
243
 
208
244
  // Remove response-element wrappers (they contain export buttons)
209
- clone.querySelectorAll('response-element').forEach((el) => {
245
+ clone.querySelectorAll("response-element").forEach((el) => {
210
246
  // Keep the table but remove the wrapper
211
247
  while (el.firstChild) {
212
248
  el.parentNode.insertBefore(el.firstChild, el);
@@ -216,25 +252,28 @@ export class GeminiParser extends ChatParser {
216
252
 
217
253
  // Convert to markdown
218
254
  const text = convertToMarkdown(clone);
219
- console.log('[Gemini Parser] Converted to markdown, length:', text.length);
220
- console.log('[Gemini Parser] Full markdown content:');
255
+ console.log(
256
+ "[Gemini Parser] Converted to markdown, length:",
257
+ text.length,
258
+ );
259
+ console.log("[Gemini Parser] Full markdown content:");
221
260
  console.log(text);
222
- console.log('[Gemini Parser] End of markdown content');
261
+ console.log("[Gemini Parser] End of markdown content");
223
262
 
224
263
  if (text && text.trim() && !seenTexts.has(text.trim())) {
225
264
  seenTexts.add(text.trim());
226
265
  messages.push({
227
- role: 'Model',
266
+ role: "Model",
228
267
  content: text.trim(),
229
268
  });
230
269
  console.log(
231
- '[Gemini Parser] Added model message:',
232
- text.substring(0, 50) + '...',
270
+ "[Gemini Parser] Added model message:",
271
+ text.substring(0, 50) + "...",
233
272
  );
234
273
  }
235
274
  } else {
236
275
  console.log(
237
- '[Gemini Parser] No markdown div found, trying comprehensive content extraction...',
276
+ "[Gemini Parser] No markdown div found, trying comprehensive content extraction...",
238
277
  );
239
278
 
240
279
  // Strategy 1: Look for content in nested elements within message-content
@@ -245,53 +284,60 @@ export class GeminiParser extends ChatParser {
245
284
  'div[class*="analysis"]',
246
285
  'div[class*="section"]',
247
286
  'div[class*="paragraph"]',
248
- 'p',
249
- 'article',
250
- 'section',
287
+ "p",
288
+ "article",
289
+ "section",
251
290
  ];
252
291
 
253
292
  let foundContent = false;
254
293
  for (const selector of nestedSelectors) {
255
- const nestedElements = messageContent.querySelectorAll(selector);
294
+ const nestedElements =
295
+ messageContent.querySelectorAll(selector);
256
296
  console.log(
257
- '[Gemini Parser] Looking for nested elements with selector:',
297
+ "[Gemini Parser] Looking for nested elements with selector:",
258
298
  selector,
259
- 'found:',
299
+ "found:",
260
300
  nestedElements.length,
261
301
  );
262
302
 
263
303
  nestedElements.forEach((element) => {
264
304
  const text = element.innerText.trim();
265
305
  if (text.length > 100) {
266
- console.log('[Gemini Parser] Found nested content, length:', text.length);
267
306
  console.log(
268
- '[Gemini Parser] Nested content preview:',
269
- text.substring(0, 200) + '...',
307
+ "[Gemini Parser] Found nested content, length:",
308
+ text.length,
309
+ );
310
+ console.log(
311
+ "[Gemini Parser] Nested content preview:",
312
+ text.substring(0, 200) + "...",
270
313
  );
271
314
 
272
315
  const isDeepResearch =
273
- text.includes('research') ||
274
- text.includes('analysis') ||
275
- text.includes('findings') ||
276
- text.includes('cost') ||
277
- text.includes('sweetener') ||
278
- text.includes('projection') ||
279
- text.includes('historical') ||
280
- text.includes('economic') ||
281
- text.includes('market') ||
282
- text.includes('price') ||
283
- text.includes('industry');
284
-
285
- console.log('[Gemini Parser] Is Deep Research content:', isDeepResearch);
316
+ text.includes("research") ||
317
+ text.includes("analysis") ||
318
+ text.includes("findings") ||
319
+ text.includes("cost") ||
320
+ text.includes("sweetener") ||
321
+ text.includes("projection") ||
322
+ text.includes("historical") ||
323
+ text.includes("economic") ||
324
+ text.includes("market") ||
325
+ text.includes("price") ||
326
+ text.includes("industry");
327
+
328
+ console.log(
329
+ "[Gemini Parser] Is Deep Research content:",
330
+ isDeepResearch,
331
+ );
286
332
 
287
333
  if (!seenTexts.has(text)) {
288
334
  seenTexts.add(text);
289
335
  messages.push({
290
- role: 'Model',
336
+ role: "Model",
291
337
  content: text,
292
338
  });
293
339
  console.log(
294
- '[Gemini Parser] Added nested content, Deep Research:',
340
+ "[Gemini Parser] Added nested content, Deep Research:",
295
341
  isDeepResearch,
296
342
  );
297
343
  foundContent = true;
@@ -304,32 +350,39 @@ export class GeminiParser extends ChatParser {
304
350
 
305
351
  // Strategy 2: Look for content in parent/sibling elements of model-response
306
352
  if (!foundContent) {
307
- console.log('[Gemini Parser] Trying parent/sibling element extraction...');
353
+ console.log(
354
+ "[Gemini Parser] Trying parent/sibling element extraction...",
355
+ );
308
356
  const parentContainer = modelResponse.parentElement;
309
357
  if (parentContainer) {
310
358
  const siblings = parentContainer.children;
311
- console.log('[Gemini Parser] Checking siblings, count:', siblings.length);
359
+ console.log(
360
+ "[Gemini Parser] Checking siblings, count:",
361
+ siblings.length,
362
+ );
312
363
 
313
364
  Array.from(siblings).forEach((sibling) => {
314
365
  if (sibling !== modelResponse) {
315
366
  const text = sibling.innerText.trim();
316
367
  if (text.length > 200) {
317
368
  console.log(
318
- '[Gemini Parser] Found sibling content, length:',
369
+ "[Gemini Parser] Found sibling content, length:",
319
370
  text.length,
320
371
  );
321
372
  console.log(
322
- '[Gemini Parser] Sibling content preview:',
323
- text.substring(0, 200) + '...',
373
+ "[Gemini Parser] Sibling content preview:",
374
+ text.substring(0, 200) + "...",
324
375
  );
325
376
 
326
377
  if (!seenTexts.has(text)) {
327
378
  seenTexts.add(text);
328
379
  messages.push({
329
- role: 'Model',
380
+ role: "Model",
330
381
  content: text,
331
382
  });
332
- console.log('[Gemini Parser] Added sibling content');
383
+ console.log(
384
+ "[Gemini Parser] Added sibling content",
385
+ );
333
386
  foundContent = true;
334
387
  }
335
388
  }
@@ -340,23 +393,30 @@ export class GeminiParser extends ChatParser {
340
393
 
341
394
  // Strategy 3: Look for content in the entire conversation container (outside model-response)
342
395
  if (!foundContent) {
343
- console.log('[Gemini Parser] Trying full container content extraction...');
396
+ console.log(
397
+ "[Gemini Parser] Trying full container content extraction...",
398
+ );
344
399
  const containerText = container.innerText.trim();
345
- console.log('[Gemini Parser] Full container text length:', containerText.length);
400
+ console.log(
401
+ "[Gemini Parser] Full container text length:",
402
+ containerText.length,
403
+ );
346
404
 
347
405
  if (containerText.length > 500) {
348
406
  console.log(
349
- '[Gemini Parser] Full container content preview:',
350
- containerText.substring(0, 200) + '...',
407
+ "[Gemini Parser] Full container content preview:",
408
+ containerText.substring(0, 200) + "...",
351
409
  );
352
410
 
353
411
  if (!seenTexts.has(containerText)) {
354
412
  seenTexts.add(containerText);
355
413
  messages.push({
356
- role: 'Model',
414
+ role: "Model",
357
415
  content: containerText,
358
416
  });
359
- console.log('[Gemini Parser] Added full container content');
417
+ console.log(
418
+ "[Gemini Parser] Added full container content",
419
+ );
360
420
  foundContent = true;
361
421
  }
362
422
  }
@@ -365,33 +425,39 @@ export class GeminiParser extends ChatParser {
365
425
  // Strategy 4: Last resort - get all text from message-content
366
426
  if (!foundContent) {
367
427
  const allText = messageContent.innerText.trim();
368
- console.log('[Gemini Parser] Last resort text length:', allText.length);
369
428
  console.log(
370
- '[Gemini Parser] Last resort text preview:',
371
- allText.substring(0, 200) + '...',
429
+ "[Gemini Parser] Last resort text length:",
430
+ allText.length,
431
+ );
432
+ console.log(
433
+ "[Gemini Parser] Last resort text preview:",
434
+ allText.substring(0, 200) + "...",
372
435
  );
373
436
 
374
437
  if (allText && allText.length > 50) {
375
438
  // Check if this looks like Deep Research content
376
439
  const isDeepResearch =
377
- allText.includes('research') ||
378
- allText.includes('analysis') ||
379
- allText.includes('findings') ||
380
- allText.includes('cost') ||
381
- allText.includes('sweetener') ||
382
- allText.includes('projection') ||
383
- allText.includes('historical');
440
+ allText.includes("research") ||
441
+ allText.includes("analysis") ||
442
+ allText.includes("findings") ||
443
+ allText.includes("cost") ||
444
+ allText.includes("sweetener") ||
445
+ allText.includes("projection") ||
446
+ allText.includes("historical");
384
447
 
385
- console.log('[Gemini Parser] Is Deep Research content:', isDeepResearch);
448
+ console.log(
449
+ "[Gemini Parser] Is Deep Research content:",
450
+ isDeepResearch,
451
+ );
386
452
 
387
453
  if (!seenTexts.has(allText)) {
388
454
  seenTexts.add(allText);
389
455
  messages.push({
390
- role: 'Model',
456
+ role: "Model",
391
457
  content: allText,
392
458
  });
393
459
  console.log(
394
- '[Gemini Parser] Added last resort model message, Deep Research:',
460
+ "[Gemini Parser] Added last resort model message, Deep Research:",
395
461
  isDeepResearch,
396
462
  );
397
463
  }
@@ -400,32 +466,38 @@ export class GeminiParser extends ChatParser {
400
466
  }
401
467
  } else {
402
468
  console.log(
403
- '[Gemini Parser] No message-content found, trying direct model-response text...',
469
+ "[Gemini Parser] No message-content found, trying direct model-response text...",
404
470
  );
405
471
  // Fallback: get text directly from model-response
406
472
  const directText = modelResponse.innerText.trim();
407
- console.log('[Gemini Parser] Direct model response text length:', directText.length);
473
+ console.log(
474
+ "[Gemini Parser] Direct model response text length:",
475
+ directText.length,
476
+ );
408
477
 
409
478
  if (directText && directText.length > 50) {
410
479
  const isDeepResearch =
411
- directText.includes('research') ||
412
- directText.includes('analysis') ||
413
- directText.includes('findings') ||
414
- directText.includes('cost') ||
415
- directText.includes('sweetener') ||
416
- directText.includes('projection') ||
417
- directText.includes('historical');
480
+ directText.includes("research") ||
481
+ directText.includes("analysis") ||
482
+ directText.includes("findings") ||
483
+ directText.includes("cost") ||
484
+ directText.includes("sweetener") ||
485
+ directText.includes("projection") ||
486
+ directText.includes("historical");
418
487
 
419
- console.log('[Gemini Parser] Direct text is Deep Research:', isDeepResearch);
488
+ console.log(
489
+ "[Gemini Parser] Direct text is Deep Research:",
490
+ isDeepResearch,
491
+ );
420
492
 
421
493
  if (!seenTexts.has(directText)) {
422
494
  seenTexts.add(directText);
423
495
  messages.push({
424
- role: 'Model',
496
+ role: "Model",
425
497
  content: directText,
426
498
  });
427
499
  console.log(
428
- '[Gemini Parser] Added direct model message, Deep Research:',
500
+ "[Gemini Parser] Added direct model message, Deep Research:",
429
501
  isDeepResearch,
430
502
  );
431
503
  }
@@ -438,33 +510,48 @@ export class GeminiParser extends ChatParser {
438
510
  // Strategy 2: Deep Research content extraction
439
511
  if (!extractionAttempted) {
440
512
  console.log(
441
- '[Gemini Parser] Strategy 2: No conversation containers found, trying Deep Research panel...',
513
+ "[Gemini Parser] Strategy 2: No conversation containers found, trying Deep Research panel...",
442
514
  );
443
515
  extractionAttempted = true;
444
516
 
445
517
  // First try Deep Research immersive panel structure
446
- console.log('[Gemini Parser] Looking for deep-research-immersive-panel...');
447
- const deepResearchPanel = document.querySelector('deep-research-immersive-panel');
448
- console.log('[Gemini Parser] Deep Research panel found:', !!deepResearchPanel);
518
+ console.log(
519
+ "[Gemini Parser] Looking for deep-research-immersive-panel...",
520
+ );
521
+ const deepResearchPanel = document.querySelector(
522
+ "deep-research-immersive-panel",
523
+ );
524
+ console.log(
525
+ "[Gemini Parser] Deep Research panel found:",
526
+ !!deepResearchPanel,
527
+ );
449
528
 
450
529
  if (deepResearchPanel) {
451
- console.log('[Gemini Parser] Processing Deep Research panel...');
530
+ console.log("[Gemini Parser] Processing Deep Research panel...");
452
531
 
453
532
  // Extract title from panel
454
- const panelTitle = deepResearchPanel.querySelector('.title-text, h2, h1');
533
+ const panelTitle = deepResearchPanel.querySelector(
534
+ ".title-text, h2, h1",
535
+ );
455
536
  if (panelTitle && !title) {
456
537
  const titleText = panelTitle.innerText.trim();
457
- console.log('[Gemini Parser] Found panel title:', titleText);
458
- if (titleText.length > 5 && !titleText.includes('Gemini')) {
538
+ console.log("[Gemini Parser] Found panel title:", titleText);
539
+ if (titleText.length > 5 && !titleText.includes("Gemini")) {
459
540
  title = titleText;
460
- console.log('[Gemini Parser] Title updated from panel:', title);
541
+ console.log("[Gemini Parser] Title updated from panel:", title);
461
542
  }
462
543
  }
463
544
 
464
545
  // Extract content from panel
465
- console.log('[Gemini Parser] Calling extractDeepResearchPanelContent...');
466
- const panelContent = this.extractDeepResearchPanelContent(deepResearchPanel);
467
- console.log('[Gemini Parser] Panel content extracted, sections:', panelContent.length);
546
+ console.log(
547
+ "[Gemini Parser] Calling extractDeepResearchPanelContent...",
548
+ );
549
+ const panelContent =
550
+ this.extractDeepResearchPanelContent(deepResearchPanel);
551
+ console.log(
552
+ "[Gemini Parser] Panel content extracted, sections:",
553
+ panelContent.length,
554
+ );
468
555
 
469
556
  if (panelContent.length > 0) {
470
557
  panelContent.forEach((section) => {
@@ -475,49 +562,63 @@ export class GeminiParser extends ChatParser {
475
562
  content: section.content,
476
563
  });
477
564
  console.log(
478
- '[Gemini Parser] Added panel section, role:',
565
+ "[Gemini Parser] Added panel section, role:",
479
566
  section.role,
480
- 'length:',
567
+ "length:",
481
568
  section.content.length,
482
569
  );
483
570
  }
484
571
  });
485
572
  } else {
486
- console.log('[Gemini Parser] No panel content found, trying fallback...');
573
+ console.log(
574
+ "[Gemini Parser] No panel content found, trying fallback...",
575
+ );
487
576
  }
488
577
  } else {
489
- console.log('[Gemini Parser] No Deep Research panel found');
578
+ console.log("[Gemini Parser] No Deep Research panel found");
490
579
  }
491
580
 
492
581
  // Fallback: Look for content in main, article, or content areas
493
582
  if (messages.length === 0) {
494
- console.log('[Gemini Parser] Strategy 3: Trying fallback content extraction...');
583
+ console.log(
584
+ "[Gemini Parser] Strategy 3: Trying fallback content extraction...",
585
+ );
495
586
  const contentSelectors = [
496
- 'main',
497
- 'article',
498
- '.content',
499
- '.main-content',
587
+ "main",
588
+ "article",
589
+ ".content",
590
+ ".main-content",
500
591
  '[role="main"]',
501
- '.conversation-content',
502
- '.chat-content',
503
- '.message-content',
592
+ ".conversation-content",
593
+ ".chat-content",
594
+ ".message-content",
504
595
  ];
505
596
 
506
597
  let contentFound = false;
507
598
 
508
599
  for (const selector of contentSelectors) {
509
- console.log('[Gemini Parser] Trying selector:', selector);
600
+ console.log("[Gemini Parser] Trying selector:", selector);
510
601
  const contentElement = document.querySelector(selector);
511
602
  if (contentElement) {
512
- console.log('[Gemini Parser] Found content element:', !!contentElement);
603
+ console.log(
604
+ "[Gemini Parser] Found content element:",
605
+ !!contentElement,
606
+ );
513
607
  // Extract all text content from the main content area
514
608
  const textContent = contentElement.innerText.trim();
515
- console.log('[Gemini Parser] Text content length:', textContent.length);
609
+ console.log(
610
+ "[Gemini Parser] Text content length:",
611
+ textContent.length,
612
+ );
516
613
 
517
614
  if (textContent && textContent.length > 100) {
518
615
  // Try to identify user prompts and responses
519
- const sections = this.extractDeepResearchSections(contentElement);
520
- console.log('[Gemini Parser] Extracted sections:', sections.length);
616
+ const sections =
617
+ this.extractDeepResearchSections(contentElement);
618
+ console.log(
619
+ "[Gemini Parser] Extracted sections:",
620
+ sections.length,
621
+ );
521
622
 
522
623
  if (sections.length > 0) {
523
624
  sections.forEach((section) => {
@@ -527,22 +628,31 @@ export class GeminiParser extends ChatParser {
527
628
  role: section.role,
528
629
  content: section.content,
529
630
  });
530
- console.log('[Gemini Parser] Added fallback section, role:', section.role);
631
+ console.log(
632
+ "[Gemini Parser] Added fallback section, role:",
633
+ section.role,
634
+ );
531
635
  }
532
636
  });
533
637
  contentFound = true;
534
638
  break;
535
639
  } else {
536
640
  // If we can't parse sections, treat the whole content as a response
537
- console.log('[Gemini Parser] Treating whole content as response...');
641
+ console.log(
642
+ "[Gemini Parser] Treating whole content as response...",
643
+ );
538
644
  const markdown = convertToMarkdown(contentElement);
539
- if (markdown && markdown.trim() && !seenTexts.has(markdown.trim())) {
645
+ if (
646
+ markdown &&
647
+ markdown.trim() &&
648
+ !seenTexts.has(markdown.trim())
649
+ ) {
540
650
  seenTexts.add(markdown.trim());
541
651
  messages.push({
542
- role: 'Model',
652
+ role: "Model",
543
653
  content: markdown.trim(),
544
654
  });
545
- console.log('[Gemini Parser] Added fallback message');
655
+ console.log("[Gemini Parser] Added fallback message");
546
656
  contentFound = true;
547
657
  break;
548
658
  }
@@ -553,14 +663,22 @@ export class GeminiParser extends ChatParser {
553
663
 
554
664
  // Strategy 3: Fallback - look for any meaningful content
555
665
  if (!contentFound) {
556
- console.log('[Gemini Parser] Strategy 4: Final fallback - extracting body content...');
666
+ console.log(
667
+ "[Gemini Parser] Strategy 4: Final fallback - extracting body content...",
668
+ );
557
669
  const bodyContent = document.body.innerText.trim();
558
- console.log('[Gemini Parser] Body content length:', bodyContent.length);
670
+ console.log(
671
+ "[Gemini Parser] Body content length:",
672
+ bodyContent.length,
673
+ );
559
674
 
560
675
  if (bodyContent && bodyContent.length > 200) {
561
676
  // Try to extract structured content from body
562
677
  const sections = this.extractDeepResearchSections(document.body);
563
- console.log('[Gemini Parser] Body sections extracted:', sections.length);
678
+ console.log(
679
+ "[Gemini Parser] Body sections extracted:",
680
+ sections.length,
681
+ );
564
682
 
565
683
  if (sections.length > 0) {
566
684
  sections.forEach((section) => {
@@ -570,30 +688,37 @@ export class GeminiParser extends ChatParser {
570
688
  role: section.role,
571
689
  content: section.content,
572
690
  });
573
- console.log('[Gemini Parser] Added body section, role:', section.role);
691
+ console.log(
692
+ "[Gemini Parser] Added body section, role:",
693
+ section.role,
694
+ );
574
695
  }
575
696
  });
576
697
  } else {
577
698
  // Last resort - treat as single response
578
- console.log('[Gemini Parser] Last resort - treating as single response...');
699
+ console.log(
700
+ "[Gemini Parser] Last resort - treating as single response...",
701
+ );
579
702
  messages.push({
580
- role: 'Model',
703
+ role: "Model",
581
704
  content: bodyContent,
582
705
  });
583
- console.log('[Gemini Parser] Added last resort message');
706
+ console.log("[Gemini Parser] Added last resort message");
584
707
  }
585
708
  }
586
709
  }
587
710
  }
588
711
  }
589
712
 
590
- console.log('[Gemini Parser] Total messages extracted:', messages.length);
591
- console.log('[Gemini Parser] ========== FINISHING PARSE() ==========');
713
+ console.log("[Gemini Parser] Total messages extracted:", messages.length);
714
+ console.log("[Gemini Parser] ========== FINISHING PARSE() ==========");
592
715
 
593
716
  const currentUrl =
594
- typeof window !== 'undefined' && window.location ? window.location.href || '' : '';
717
+ typeof window !== "undefined" && window.location
718
+ ? window.location.href || ""
719
+ : "";
595
720
  const metadata = {
596
- Source: 'Gemini',
721
+ Source: "Gemini",
597
722
  Date: new Date().toLocaleString(),
598
723
  Link: currentUrl,
599
724
  };
@@ -605,15 +730,17 @@ export class GeminiParser extends ChatParser {
605
730
  metadata: metadata,
606
731
  };
607
732
  } catch (error) {
608
- console.error('[Gemini Parser] Error during parsing:', error);
733
+ console.error("[Gemini Parser] Error during parsing:", error);
609
734
  const currentUrl =
610
- typeof window !== 'undefined' && window.location ? window.location.href || '' : '';
735
+ typeof window !== "undefined" && window.location
736
+ ? window.location.href || ""
737
+ : "";
611
738
  return {
612
- title: 'Gemini Conversation',
739
+ title: "Gemini Conversation",
613
740
  messages: [],
614
741
  url: currentUrl,
615
742
  metadata: {
616
- Source: 'Gemini',
743
+ Source: "Gemini",
617
744
  Date: new Date().toLocaleString(),
618
745
  Link: currentUrl,
619
746
  },
@@ -623,9 +750,9 @@ export class GeminiParser extends ChatParser {
623
750
 
624
751
  // Helper method to extract sections from Deep Research content
625
752
  extractDeepResearchSections(contentElement) {
626
- console.log('[Gemini Parser] Extracting Deep Research sections...');
753
+ console.log("[Gemini Parser] Extracting Deep Research sections...");
627
754
  const sections = [];
628
- const text = contentElement.innerText || '';
755
+ const text = contentElement.innerText || "";
629
756
 
630
757
  // Look for common Deep Research patterns
631
758
  const patterns = [
@@ -638,8 +765,10 @@ export class GeminiParser extends ChatParser {
638
765
  },
639
766
  // Pattern 2: Question/Answer format
640
767
  {
641
- promptRegex: /(?:Question|Q)[:\s]*\n*([\s\S]*?)(?=\n\s*(?:Answer|A|Response)|$)/i,
642
- responseRegex: /(?:Answer|A|Response)[:\s]*\n*([\s\S]*?)(?=\n\s*(?:Question|Q)|$)/i,
768
+ promptRegex:
769
+ /(?:Question|Q)[:\s]*\n*([\s\S]*?)(?=\n\s*(?:Answer|A|Response)|$)/i,
770
+ responseRegex:
771
+ /(?:Answer|A|Response)[:\s]*\n*([\s\S]*?)(?=\n\s*(?:Question|Q)|$)/i,
643
772
  },
644
773
  // Pattern 3: Look for research plan and results
645
774
  {
@@ -652,47 +781,53 @@ export class GeminiParser extends ChatParser {
652
781
 
653
782
  // Try each pattern
654
783
  for (const pattern of patterns) {
655
- console.log('[Gemini Parser] Trying pattern...');
784
+ console.log("[Gemini Parser] Trying pattern...");
656
785
  const promptMatches = text.match(pattern.promptRegex);
657
786
  const responseMatches = text.match(pattern.responseRegex);
658
787
 
659
788
  if (promptMatches && promptMatches[1]) {
660
789
  const promptContent = promptMatches[1].trim();
661
- console.log('[Gemini Parser] Found prompt content, length:', promptContent.length);
790
+ console.log(
791
+ "[Gemini Parser] Found prompt content, length:",
792
+ promptContent.length,
793
+ );
662
794
  if (promptContent.length > 20) {
663
795
  sections.push({
664
- role: 'User',
796
+ role: "User",
665
797
  content: promptContent,
666
798
  });
667
- console.log('[Gemini Parser] Added prompt section');
799
+ console.log("[Gemini Parser] Added prompt section");
668
800
  }
669
801
  }
670
802
 
671
803
  if (responseMatches && responseMatches[1]) {
672
804
  const responseContent = responseMatches[1].trim();
673
- console.log('[Gemini Parser] Found response content, length:', responseContent.length);
805
+ console.log(
806
+ "[Gemini Parser] Found response content, length:",
807
+ responseContent.length,
808
+ );
674
809
  if (responseContent.length > 50) {
675
810
  sections.push({
676
- role: 'Model',
811
+ role: "Model",
677
812
  content: responseContent,
678
813
  });
679
- console.log('[Gemini Parser] Added response section');
814
+ console.log("[Gemini Parser] Added response section");
680
815
  }
681
816
  }
682
817
 
683
818
  // If we found meaningful sections, stop trying other patterns
684
819
  if (sections.length > 0) {
685
- console.log('[Gemini Parser] Found sections using pattern matching');
820
+ console.log("[Gemini Parser] Found sections using pattern matching");
686
821
  return sections;
687
822
  }
688
823
  }
689
824
 
690
825
  // If no structured sections found, try to extract based on HTML structure
691
- console.log('[Gemini Parser] Trying HTML structure extraction...');
826
+ console.log("[Gemini Parser] Trying HTML structure extraction...");
692
827
  const userElements = contentElement.querySelectorAll(
693
828
  '.user-query, .prompt, .question, [data-role="user"]',
694
829
  );
695
- console.log('[Gemini Parser] Found user elements:', userElements.length);
830
+ console.log("[Gemini Parser] Found user elements:", userElements.length);
696
831
  userElements.forEach((el) => {
697
832
  const clone = el.cloneNode(true);
698
833
  clone
@@ -701,10 +836,10 @@ export class GeminiParser extends ChatParser {
701
836
  const content = clone.innerText.trim();
702
837
  if (content.length > 20) {
703
838
  sections.push({
704
- role: 'User',
839
+ role: "User",
705
840
  content: content,
706
841
  });
707
- console.log('[Gemini Parser] Added user element from HTML structure');
842
+ console.log("[Gemini Parser] Added user element from HTML structure");
708
843
  }
709
844
  });
710
845
 
@@ -712,21 +847,26 @@ export class GeminiParser extends ChatParser {
712
847
  const responseElements = contentElement.querySelectorAll(
713
848
  '.model-response, .response, .answer, [data-role="model"], .research-content',
714
849
  );
715
- console.log('[Gemini Parser] Found response elements:', responseElements.length);
850
+ console.log(
851
+ "[Gemini Parser] Found response elements:",
852
+ responseElements.length,
853
+ );
716
854
  responseElements.forEach((el) => {
717
855
  const content = el.innerText.trim();
718
856
  if (content.length > 50) {
719
857
  sections.push({
720
- role: 'Model',
858
+ role: "Model",
721
859
  content: content,
722
860
  });
723
- console.log('[Gemini Parser] Added response element from HTML structure');
861
+ console.log(
862
+ "[Gemini Parser] Added response element from HTML structure",
863
+ );
724
864
  }
725
865
  });
726
866
 
727
867
  // If still no sections, try to split by common delimiters
728
868
  if (sections.length === 0) {
729
- console.log('[Gemini Parser] Trying delimiter splitting...');
869
+ console.log("[Gemini Parser] Trying delimiter splitting...");
730
870
  const delimiterPatterns = [
731
871
  /\n\s*You said\s*\n/i,
732
872
  /\n\s*Response\s*\n/i,
@@ -743,90 +883,98 @@ export class GeminiParser extends ChatParser {
743
883
  const trimmedPart = part.trim();
744
884
  if (trimmedPart.length > 50) {
745
885
  // Alternate between User and Model roles
746
- const role = index % 2 === 0 ? 'User' : 'Model';
886
+ const role = index % 2 === 0 ? "User" : "Model";
747
887
  sections.push({
748
888
  role: role,
749
889
  content: trimmedPart,
750
890
  });
751
- console.log('[Gemini Parser] Added delimiter section, role:', role);
891
+ console.log("[Gemini Parser] Added delimiter section, role:", role);
752
892
  }
753
893
  });
754
894
  }
755
895
 
756
- console.log('[Gemini Parser] Total sections extracted:', sections.length);
896
+ console.log("[Gemini Parser] Total sections extracted:", sections.length);
757
897
  return sections;
758
898
  }
759
899
 
760
900
  // Helper method to extract content from Deep Research immersive panel
761
901
  extractDeepResearchPanelContent(panelElement) {
762
- console.log('[Gemini Parser] Looking for Deep Research panel content...');
902
+ console.log("[Gemini Parser] Looking for Deep Research panel content...");
763
903
  const sections = [];
764
904
 
765
- console.log('[Gemini Parser] Panel element found:', !!panelElement);
905
+ console.log("[Gemini Parser] Panel element found:", !!panelElement);
766
906
  console.log(
767
- '[Gemini Parser] Panel innerText length:',
907
+ "[Gemini Parser] Panel innerText length:",
768
908
  panelElement.innerText ? panelElement.innerText.length : 0,
769
909
  );
770
910
 
771
911
  try {
772
912
  // Look for content within panel
773
913
  const contentSelectors = [
774
- '.markdown',
775
- '.content',
776
- '.research-content',
777
- '.panel-content',
914
+ ".markdown",
915
+ ".content",
916
+ ".research-content",
917
+ ".panel-content",
778
918
  'div[class*="content"]',
779
919
  'div[class*="markdown"]',
780
920
  'div[class*="research"]',
781
921
  ];
782
922
 
783
923
  for (const selector of contentSelectors) {
784
- console.log('[Gemini Parser] Trying selector:', selector);
924
+ console.log("[Gemini Parser] Trying selector:", selector);
785
925
  const contentElements = panelElement.querySelectorAll(selector);
786
- console.log('[Gemini Parser] Found elements:', contentElements.length);
926
+ console.log("[Gemini Parser] Found elements:", contentElements.length);
787
927
  contentElements.forEach((element) => {
788
928
  const text = element.innerText.trim();
789
929
  if (text.length > 100) {
790
930
  sections.push({
791
- role: 'Model',
931
+ role: "Model",
792
932
  content: text,
793
933
  });
794
- console.log('[Gemini Parser] Added panel content via selector:', selector);
934
+ console.log(
935
+ "[Gemini Parser] Added panel content via selector:",
936
+ selector,
937
+ );
795
938
  }
796
939
  });
797
940
  }
798
941
 
799
942
  // If no structured content found, extract all text from panel
800
943
  if (sections.length === 0) {
801
- console.log('[Gemini Parser] No structured content found, extracting all panel text...');
944
+ console.log(
945
+ "[Gemini Parser] No structured content found, extracting all panel text...",
946
+ );
802
947
  const panelText = panelElement.innerText.trim();
803
- console.log('[Gemini Parser] Panel text length:', panelText.length);
948
+ console.log("[Gemini Parser] Panel text length:", panelText.length);
804
949
  if (panelText.length > 200) {
805
950
  // Try to split into logical sections
806
951
  const parts = this.splitIntoSections(panelText);
807
- console.log('[Gemini Parser] Split into parts:', parts.length);
952
+ console.log("[Gemini Parser] Split into parts:", parts.length);
808
953
  parts.forEach((part) => {
809
954
  if (part.length > 50) {
810
955
  sections.push({
811
- role: 'Model',
956
+ role: "Model",
812
957
  content: part,
813
958
  });
814
- console.log('[Gemini Parser] Added panel text part');
959
+ console.log("[Gemini Parser] Added panel text part");
815
960
  }
816
961
  });
817
962
  }
818
963
  }
819
964
  } catch (error) {
820
- console.error('[Gemini Parser] Error extracting panel content:', error);
965
+ console.error("[Gemini Parser] Error extracting panel content:", error);
821
966
  }
822
967
 
823
- console.log('[Gemini Parser] Panel content extraction complete, sections:', sections.length);
968
+ console.log(
969
+ "[Gemini Parser] Panel content extraction complete, sections:",
970
+ sections.length,
971
+ );
824
972
  return sections;
825
973
  }
826
974
 
827
975
  // Helper method to split text into logical sections
828
976
  splitIntoSections(text) {
829
- console.log('[Gemini Parser] Splitting text into sections...');
977
+ console.log("[Gemini Parser] Splitting text into sections...");
830
978
  const sections = [];
831
979
 
832
980
  // Try to split by common delimiters
@@ -846,11 +994,17 @@ export class GeminiParser extends ChatParser {
846
994
  const cleaned = part.trim();
847
995
  if (cleaned.length > 50 && !cleaned.match(/^\d+$/)) {
848
996
  sections.push(cleaned);
849
- console.log('[Gemini Parser] Added split section, length:', cleaned.length);
997
+ console.log(
998
+ "[Gemini Parser] Added split section, length:",
999
+ cleaned.length,
1000
+ );
850
1001
  }
851
1002
  });
852
1003
 
853
- console.log('[Gemini Parser] Text splitting complete, sections:', sections.length);
1004
+ console.log(
1005
+ "[Gemini Parser] Text splitting complete, sections:",
1006
+ sections.length,
1007
+ );
854
1008
  return sections;
855
1009
  }
856
1010
  }