@cloro-dev/response-parser 0.1.2 → 0.1.4

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.
Files changed (60) hide show
  1. package/README.md +107 -50
  2. package/dist/core/types.d.ts +5 -6
  3. package/dist/core/types.d.ts.map +1 -1
  4. package/dist/index.d.ts +78 -13
  5. package/dist/index.esm.js +1 -1
  6. package/dist/index.esm.js.map +1 -1
  7. package/dist/index.js +1 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/providers/ai-mode.d.ts +14 -3
  10. package/dist/providers/ai-mode.d.ts.map +1 -1
  11. package/dist/providers/ai-overview.d.ts +14 -3
  12. package/dist/providers/ai-overview.d.ts.map +1 -1
  13. package/dist/providers/base-provider.d.ts +4 -1
  14. package/dist/providers/base-provider.d.ts.map +1 -1
  15. package/dist/providers/chatgpt.d.ts +15 -3
  16. package/dist/providers/chatgpt.d.ts.map +1 -1
  17. package/dist/providers/copilot.d.ts +12 -1
  18. package/dist/providers/copilot.d.ts.map +1 -1
  19. package/dist/providers/gemini.d.ts +12 -1
  20. package/dist/providers/gemini.d.ts.map +1 -1
  21. package/dist/providers/perplexity.d.ts +10 -3
  22. package/dist/providers/perplexity.d.ts.map +1 -1
  23. package/dist/react/components/AiResponseRenderer.d.ts +2 -2
  24. package/dist/react/components/AiResponseRenderer.d.ts.map +1 -1
  25. package/dist/react/components/ResponseRenderer.d.ts +24 -0
  26. package/dist/react/components/ResponseRenderer.d.ts.map +1 -0
  27. package/dist/react/core/types.d.ts +5 -6
  28. package/dist/react/core/types.d.ts.map +1 -1
  29. package/dist/react/hooks/useAiResponse.d.ts.map +1 -1
  30. package/dist/react/hooks/useResponse.d.ts +19 -0
  31. package/dist/react/hooks/useResponse.d.ts.map +1 -0
  32. package/dist/react/index.d.ts +13 -14
  33. package/dist/react/index.esm.js +1 -1
  34. package/dist/react/index.esm.js.map +1 -1
  35. package/dist/react/index.js +1 -1
  36. package/dist/react/index.js.map +1 -1
  37. package/dist/react/providers/ai-mode.d.ts +14 -3
  38. package/dist/react/providers/ai-mode.d.ts.map +1 -1
  39. package/dist/react/providers/ai-overview.d.ts +14 -3
  40. package/dist/react/providers/ai-overview.d.ts.map +1 -1
  41. package/dist/react/providers/base-provider.d.ts +4 -1
  42. package/dist/react/providers/base-provider.d.ts.map +1 -1
  43. package/dist/react/providers/chatgpt.d.ts +15 -3
  44. package/dist/react/providers/chatgpt.d.ts.map +1 -1
  45. package/dist/react/providers/copilot.d.ts +12 -1
  46. package/dist/react/providers/copilot.d.ts.map +1 -1
  47. package/dist/react/providers/gemini.d.ts +12 -1
  48. package/dist/react/providers/gemini.d.ts.map +1 -1
  49. package/dist/react/providers/perplexity.d.ts +10 -3
  50. package/dist/react/providers/perplexity.d.ts.map +1 -1
  51. package/dist/react/react/components/AiResponseRenderer.d.ts +2 -2
  52. package/dist/react/react/components/AiResponseRenderer.d.ts.map +1 -1
  53. package/dist/react/react/components/ResponseRenderer.d.ts +24 -0
  54. package/dist/react/react/components/ResponseRenderer.d.ts.map +1 -0
  55. package/dist/react/react/hooks/useAiResponse.d.ts.map +1 -1
  56. package/dist/react/react/hooks/useResponse.d.ts +19 -0
  57. package/dist/react/react/hooks/useResponse.d.ts.map +1 -0
  58. package/dist/react/react/index.d.ts +6 -6
  59. package/dist/react/react/index.d.ts.map +1 -1
  60. package/package.json +1 -1
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # @cloro/response-parser
1
+ # @cloro-dev/response-parser
2
2
 
3
3
  A powerful TypeScript library for parsing and rendering AI model responses from ChatGPT, Gemini, Perplexity, Copilot, and Google AI Overview/Mode.
4
4
 
@@ -6,20 +6,20 @@ A powerful TypeScript library for parsing and rendering AI model responses from
6
6
 
7
7
  - 🤖 **Multi-Provider Support**: ChatGPT, Gemini, Perplexity, Copilot, AI Overview, AI Mode
8
8
  - 🔍 **Auto-Detection**: Automatically detects the AI provider from response structure
9
- - 🎨 **Theme Support**: Built-in dark and light mode styling
9
+ - 🎨 **Built-in Styling**: Provider-specific styling with dark mode support
10
10
  - ⚡ **React Components**: Ready-to-use React components for rendering
11
- - 🔒 **Secure**: Sandboxed rendering with script sanitization
11
+ - 🔒 **Secure**: Sandboxed rendering with automatic script sanitization
12
12
  - 📦 **TypeScript**: Full TypeScript support with comprehensive types
13
13
  - 🎯 **Lightweight**: No runtime dependencies for core parsing
14
14
 
15
15
  ## Installation
16
16
 
17
17
  ```bash
18
- npm install @cloro/response-parser
18
+ npm install @cloro-dev/response-parser
19
19
  # or
20
- yarn add @cloro/response-parser
20
+ yarn add @cloro-dev/response-parser
21
21
  # or
22
- pnpm add @cloro/response-parser
22
+ pnpm add @cloro-dev/response-parser
23
23
  ```
24
24
 
25
25
  ## Quick Start
@@ -27,11 +27,11 @@ pnpm add @cloro/response-parser
27
27
  ### Basic Parsing
28
28
 
29
29
  ```typescript
30
- import { parseAiResponse, detectProvider } from '@cloro/response-parser';
30
+ import { parseAiResponse, detectProvider } from "@cloro-dev/response-parser";
31
31
 
32
32
  // Auto-detect provider and parse
33
33
  const response = await fetchAIResponse();
34
- const parsed = parseAiResponse(response, { theme: 'dark' });
34
+ const parsed = parseAiResponse(response);
35
35
 
36
36
  console.log(parsed.provider); // 'CHATGPT' | 'GEMINI' | etc.
37
37
  console.log(parsed.html); // Sanitized HTML ready for rendering
@@ -41,21 +41,22 @@ console.log(parsed.text); // Plain text version
41
41
  ### React Component
42
42
 
43
43
  ```tsx
44
- import { AiResponseRenderer } from '@cloro/response-parser/react';
44
+ import { ResponseRenderer } from "@cloro-dev/response-parser/react";
45
45
 
46
46
  function MyComponent() {
47
47
  const [aiResponse, setAiResponse] = useState(null);
48
48
 
49
49
  return (
50
- <AiResponseRenderer
50
+ <ResponseRenderer
51
51
  response={aiResponse}
52
- theme="dark"
52
+ removeLinks={false}
53
+ invertColors={false}
53
54
  autoDetect
54
55
  className="w-full h-96"
55
56
  iframeProps={{
56
- sandbox: 'allow-popups'
57
+ sandbox: "allow-popups",
57
58
  }}
58
- onProviderDetected={(provider) => console.log('Detected:', provider)}
59
+ onProviderDetected={(provider) => console.log("Detected:", provider)}
59
60
  />
60
61
  );
61
62
  }
@@ -70,10 +71,12 @@ function MyComponent() {
70
71
  Parse an AI response with auto-detected provider.
71
72
 
72
73
  **Options:**
73
- - `theme`: `'light' | 'dark'` (default: `'dark'`)
74
- - `baseUrl`: Base URL for relative links
75
- - `sanitize`: Remove scripts (default: `true`)
76
- - `includeStyles`: Inject provider-specific styles (default: `true`)
74
+
75
+ - `removeLinks`: `boolean` - Remove all hyperlinks from HTML (default: `false`)
76
+ - `invertColors`: `boolean` - Apply color inversion for dark mode (default: `false`)
77
+ - `removeNavbar`: `boolean` - Remove navigation bar (default: `false`, Perplexity, Gemini & Copilot)
78
+ - `removeFollowup`: `boolean` - Remove follow-up input box (default: `false`, ChatGPT, Perplexity, Gemini & Copilot)
79
+ - `removeSidebar`: `boolean` - Remove sidebar (default: `false`, ChatGPT, Gemini & Copilot)
77
80
 
78
81
  **Returns:** `ParsedResponse | null`
79
82
 
@@ -85,75 +88,110 @@ Detect the AI provider from a response.
85
88
 
86
89
  ### React Components
87
90
 
88
- #### `<AiResponseRenderer />`
91
+ #### `<ResponseRenderer />`
89
92
 
90
93
  Main React component for rendering AI responses.
91
94
 
92
95
  **Props:**
96
+
93
97
  - `response`: The AI response object
94
- - `theme`: Light or dark mode
95
98
  - `autoDetect`: Auto-detect provider (default: `true`)
96
99
  - `provider`: Explicitly specify provider
100
+ - `removeLinks`: Remove all hyperlinks (default: `false`)
101
+ - `invertColors`: Apply color inversion (default: `false`)
102
+ - `removeNavbar`: Remove navigation bar (default: `false`, Perplexity & Gemini)
103
+ - `removeFollowup`: Remove follow-up input box (default: `false`, Perplexity only)
97
104
  - `className`: CSS class for container
98
105
  - `iframeProps`: Additional props for iframe
99
106
  - `loadingComponent`: Custom loading component
100
107
  - `errorComponent`: Custom error component
108
+ - `fallbackComponent`: Custom fallback component
109
+ - `onRenderComplete`: Callback when rendering completes
101
110
  - `onProviderDetected`: Callback when provider is detected
102
111
 
103
112
  ### Hooks
104
113
 
105
- #### `useAiResponse(response, options?)`
114
+ #### `useResponse(response, options?)`
106
115
 
107
116
  React hook for parsing AI responses.
108
117
 
118
+ **Options:**
119
+
120
+ - `autoDetect`: Auto-detect provider (default: `true`)
121
+ - `provider`: Explicitly specify provider
122
+ - `removeLinks`: Remove all hyperlinks (default: `false`)
123
+ - `invertColors`: Apply color inversion (default: `false`)
124
+ - `removeNavbar`: Remove navigation bar (default: `false`, Perplexity & Gemini)
125
+ - `removeFollowup`: Remove follow-up input box (default: `false`, Perplexity only)
126
+ - `onProviderDetected`: Callback when provider is detected
127
+ - `onError`: Callback when error occurs
128
+
109
129
  **Returns:**
130
+
110
131
  - `parsed`: Parsed response object
111
132
  - `provider`: Detected provider
112
133
  - `isLoading`: Loading state
113
134
  - `error`: Error object
114
135
  - `html`: HTML string
115
136
  - `text`: Plain text string
137
+ - `sources`: Sources array (if available)
116
138
  - `reparse`: Function to re-parse with new options
117
139
 
118
140
  ## Supported Providers
119
141
 
120
- | Provider | Status | Features |
121
- |----------|--------|----------|
122
- | ChatGPT | ✅ | Dark mode, sidebar hiding |
123
- | Gemini | ✅ | Material Design overrides |
124
- | Perplexity | ✅ | Color inversion for dark mode |
125
- | Copilot | ✅ | UI element hiding |
126
- | AI Overview | ✅ | WIZ data extraction |
127
- | AI Mode | ✅ | Google UI hiding |
142
+ | Provider | Status | Features |
143
+ | ----------- | ------ | ---------------------------------------------------- |
144
+ | ChatGPT | ✅ | Dark mode, sidebar hiding |
145
+ | Gemini | ✅ | Material Design overrides, navbar removal |
146
+ | Perplexity | ✅ | Color inversion, link removal, UI element removal |
147
+ | Copilot | ✅ | UI element hiding |
148
+ | AI Overview | ✅ | WIZ data extraction |
149
+ | AI Mode | ✅ | Google UI hiding |
128
150
 
129
151
  ## Examples
130
152
 
131
- ### Manual Provider Specification
153
+ ### Remove Hyperlinks
132
154
 
133
155
  ```typescript
134
- import { parseAiResponse } from 'ai-response-parser';
156
+ import { parseAiResponse } from "@cloro-dev/response-parser";
135
157
 
136
158
  const parsed = parseAiResponse(response, {
137
- provider: 'CHATGPT',
138
- theme: 'dark'
159
+ removeLinks: true, // Removes all <a> tags, keeps text
139
160
  });
140
161
  ```
141
162
 
142
- ### Advanced Usage with Custom Styles
163
+ ### Dark Mode
143
164
 
144
165
  ```tsx
145
- <AiResponseRenderer
166
+ <ResponseRenderer
146
167
  response={response}
147
- theme="dark"
148
- onError={(error) => console.error(error)}
149
- onRenderComplete={(html) => console.log('Rendered', html)}
150
- iframeProps={{
151
- className: 'custom-iframe',
152
- style: { border: 'none', borderRadius: '8px' }
153
- }}
168
+ invertColors={true} // Apply CSS filter for dark mode
169
+ removeLinks={true} // Optionally remove links
154
170
  />
155
171
  ```
156
172
 
173
+ ### Clean View (Remove UI Elements)
174
+
175
+ ```tsx
176
+ <ResponseRenderer
177
+ response={response}
178
+ removeNavbar={true} // Remove top navigation bar
179
+ removeFollowup={true} // Remove follow-up input box
180
+ removeLinks={true} // Remove all hyperlinks
181
+ invertColors={true} // Dark mode
182
+ />
183
+ ```
184
+
185
+ ### Manual Provider Specification
186
+
187
+ ```typescript
188
+ import { parseAiResponse, AIProvider } from "@cloro-dev/response-parser";
189
+
190
+ const parsed = parseAiResponse(response, {
191
+ provider: "CHATGPT",
192
+ });
193
+ ```
194
+
157
195
  ### Error Handling
158
196
 
159
197
  ```tsx
@@ -164,12 +202,35 @@ const ErrorComponent = ({ error, retry }) => (
164
202
  </div>
165
203
  );
166
204
 
167
- <AiResponseRenderer
168
- response={response}
169
- errorComponent={ErrorComponent}
170
- />
205
+ <ResponseRenderer response={response} errorComponent={ErrorComponent} />;
171
206
  ```
172
207
 
208
+ ## What's Changed in v0.1.3
209
+
210
+ ### Simplified API
211
+
212
+ - ✅ **Always sanitizes** HTML by default (removes scripts for security)
213
+ - ✅ **Always includes** provider-specific styles
214
+ - ✅ **Always uses** provider's base URL for relative links
215
+ - ❌ **Removed** `theme` option (styles are provider-specific)
216
+ - ❌ **Removed** `sanitize` option (always enabled)
217
+ - ❌ **Removed** `includeStyles` option (always enabled)
218
+ - ❌ **Removed** `baseUrl` option (uses provider default)
219
+ - ✅ **Added** `removeNavbar` option (removes navigation bar)
220
+ - ✅ **Added** `removeFollowup` option (removes follow-up input)
221
+
222
+ ### Remaining Options
223
+
224
+ - `removeLinks`: Remove all hyperlinks from HTML
225
+ - `invertColors`: Apply color inversion
226
+ - `removeNavbar`: Remove navigation bar (Perplexity & Gemini)
227
+ - `removeFollowup`: Remove follow-up input (Perplexity only)
228
+
229
+ ### Component Renaming
230
+
231
+ - `AiResponseRenderer` → `ResponseRenderer`
232
+ - `useAiResponse` → `useResponse`
233
+
173
234
  ## Development
174
235
 
175
236
  ```bash
@@ -186,10 +247,6 @@ pnpm test
186
247
  pnpm dev
187
248
  ```
188
249
 
189
- ## Contributing
190
-
191
- Contributions are welcome! Please feel free to submit a Pull Request.
192
-
193
250
  ## License
194
251
 
195
- MIT © [Your Name](https://github.com/yourusername)
252
+ MIT © cloro
@@ -7,22 +7,21 @@ export interface ParsedResponse {
7
7
  metadata?: Record<string, any>;
8
8
  }
9
9
  export interface ParseOptions {
10
- theme?: 'light' | 'dark';
11
- baseUrl?: string;
12
- sanitize?: boolean;
13
- includeStyles?: boolean;
10
+ removeLinks?: boolean;
11
+ invertColors?: boolean;
12
+ removeHeader?: boolean;
13
+ removeFooter?: boolean;
14
+ removeSidebar?: boolean;
14
15
  }
15
16
  export interface ProviderConfig {
16
17
  name: AIProvider;
17
18
  baseUrl: string;
18
- defaultStyles: string;
19
19
  }
20
20
  export interface DetectedProvider {
21
21
  provider: AIProvider;
22
22
  confidence: number;
23
23
  }
24
24
  export interface StyleOptions {
25
- theme?: 'light' | 'dark';
26
25
  customCSS?: string;
27
26
  hideUI?: boolean;
28
27
  baseUrl?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAClB,SAAS,GACT,QAAQ,GACR,YAAY,GACZ,SAAS,GACT,YAAY,GACZ,QAAQ,CAAC;AAEb,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,UAAU,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,UAAU,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,UAAU,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC;CACjB,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAClB,SAAS,GACT,QAAQ,GACR,YAAY,GACZ,SAAS,GACT,YAAY,GACZ,QAAQ,CAAC;AAEb,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,UAAU,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,UAAU,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,UAAU,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC;CACjB,CAAC"}
package/dist/index.d.ts CHANGED
@@ -7,22 +7,21 @@ interface ParsedResponse {
7
7
  metadata?: Record<string, any>;
8
8
  }
9
9
  interface ParseOptions {
10
- theme?: 'light' | 'dark';
11
- baseUrl?: string;
12
- sanitize?: boolean;
13
- includeStyles?: boolean;
10
+ removeLinks?: boolean;
11
+ invertColors?: boolean;
12
+ removeHeader?: boolean;
13
+ removeFooter?: boolean;
14
+ removeSidebar?: boolean;
14
15
  }
15
16
  interface ProviderConfig {
16
17
  name: AIProvider;
17
18
  baseUrl: string;
18
- defaultStyles: string;
19
19
  }
20
20
  interface DetectedProvider {
21
21
  provider: AIProvider;
22
22
  confidence: number;
23
23
  }
24
24
  interface StyleOptions {
25
- theme?: 'light' | 'dark';
26
25
  customCSS?: string;
27
26
  hideUI?: boolean;
28
27
  baseUrl?: string;
@@ -91,7 +90,6 @@ declare class ProviderDetector {
91
90
  declare abstract class BaseProvider {
92
91
  abstract readonly name: AIProvider;
93
92
  abstract readonly baseUrl: string;
94
- abstract readonly defaultStyles: string;
95
93
  /**
96
94
  * Parse an AI response and return structured content
97
95
  */
@@ -112,6 +110,10 @@ declare abstract class BaseProvider {
112
110
  * Check if content is a full HTML document
113
111
  */
114
112
  isFullDocument(html: string): boolean;
113
+ /**
114
+ * Remove all links from HTML, keeping the text content
115
+ */
116
+ removeLinks(html: string): string;
115
117
  /**
116
118
  * Wrap HTML fragment in a document
117
119
  */
@@ -121,48 +123,111 @@ declare abstract class BaseProvider {
121
123
  declare class ChatGPTProvider extends BaseProvider {
122
124
  readonly name: AIProvider;
123
125
  readonly baseUrl = "https://chatgpt.com";
124
- readonly defaultStyles = "\n /* Force Dark Background on main containers and wrappers */\n html, body, main, article, footer, form,\n [class*=\"bg-\"], [class*=\"footer\"], [class*=\"bottom\"],\n div[class*=\"border-t\"],\n #thread-bottom-container, #thread-bottom,\n #thread, .composer-parent, [class*=\"group\\/thread\"] {\n background-color: #131314 !important;\n color: #e3e3e3 !important;\n border-color: #2a2b36 !important;\n }\n\n /* Force background on specific white artifacts in the footer */\n #thread-bottom-container .bg-clip-padding,\n #thread-bottom-container .content-fade,\n #thread-bottom-container .absolute {\n background-color: transparent !important;\n }\n\n /* Specific targeting for the composer/input box (was white) */\n form .bg-token-bg-primary, form .shadow-short {\n background-color: #2a2b36 !important;\n border-color: #3e3f4b !important;\n box-shadow: none !important;\n }\n\n /* Disclaimer Footer - Force Dark Background */\n div[class*=\"text-token-text-secondary\"] {\n color: #9ca3af !important;\n background-color: #131314 !important;\n }\n\n /* Force Text Color to Light */\n p, h1, h2, h3, h4, h5, h6, li, span, div, td, th, textarea, button {\n color: #e3e3e3 !important;\n }\n\n /* Links - Light Blue */\n a, a span {\n color: #8ab4f8 !important;\n }\n\n /* Code Blocks */\n pre, code, pre div, code span {\n background-color: #2a2b36 !important;\n color: #e3e3e3 !important;\n text-shadow: none !important;\n }\n\n /* Inputs/Textareas */\n input, textarea {\n background-color: transparent !important;\n color: #e3e3e3 !important;\n border-color: #3e3f4b !important;\n }\n\n /* Placeholder text */\n textarea::placeholder {\n color: #9ca3af !important;\n }\n\n /* Hide Sidebar */\n nav, [class*=\"sidebar\"] {\n display: none !important;\n }\n\n /* Media visibility */\n img, video {\n opacity: 1 !important;\n }\n ";
125
126
  extractContent(response: any): ContentExtraction;
127
+ /**
128
+ * Remove links from HTML, preserving badge styling
129
+ * Converts <a> tags to <span> while keeping class attributes
130
+ */
131
+ removeLinks(html: string): string;
132
+ /**
133
+ * Remove ChatGPT sidebar from HTML
134
+ */
135
+ removeSidebar(html: string): string;
136
+ /**
137
+ * Remove ChatGPT footer/composer from HTML
138
+ */
139
+ removeFooter(html: string): string;
126
140
  parse(response: any, options?: ParseOptions): ParsedResponse;
127
141
  }
128
142
 
129
143
  declare class GeminiProvider extends BaseProvider {
130
144
  readonly name: AIProvider;
131
145
  readonly baseUrl = "https://gemini.google.com";
132
- readonly defaultStyles = "\n /* Gemini Dark Mode Variable Overrides */\n :root {\n --gem-sys-color--surface: #131314 !important;\n --gem-sys-color--surface-container: #1e1f20 !important;\n --gem-sys-color--on-surface: #e3e3e3 !important;\n --bard-color-synthetic--chat-window-surface: #131314 !important;\n --bard-color-surface-dim-tmp: #131314 !important;\n }\n\n /* UI hiding - Gemini */\n bard-sidenav, mat-sidenav, .mat-drawer-backdrop, .side-nav-menu-button,\n\n /* Gemini \"About Gemini\" footer/navigation block */\n .gb_5a, .gb_5c, .gb_5d, .gb_5e,\n .gb_Uc, .gb_Vc, .gb_Wc,\n a[href*=\"about\"],\n a[href*=\"subscriptions\"],\n a[href*=\"business\"],\n div[class*=\"gb_5\"],\n .gb_Pd, .gb_Qd, .gb_Rd,\n .gb_Sd, .gb_Td, .gb_Ud, .gb_Vd,\n [aria-label*=\"About\"],\n [aria-label*=\"Gemini App\"],\n [aria-label*=\"Subscriptions\"],\n [aria-label*=\"For Business\"],\n *:contains(\"About Gemini\"),\n *:contains(\"Gemini App\"),\n *:contains(\"Subscriptions\"),\n *:contains(\"For Business\") {\n display: none !important;\n }\n\n /* General Layout */\n main { width: 100% !important; max-width: 100% !important; margin: 0 !important; }\n\n /* Force Dark Mode on Body and Gemini Containers */\n body, .content-container, chat-app, .main-content, .chat-container {\n background-color: #131314 !important;\n color: #e3e3e3 !important;\n }\n ";
133
146
  extractContent(response: any): ContentExtraction;
147
+ /**
148
+ * Remove Gemini header/navbar from HTML
149
+ */
150
+ removeHeader(html: string): string;
151
+ /**
152
+ * Remove Gemini footer/follow-up input box from HTML
153
+ */
154
+ removeFooter(html: string): string;
155
+ /**
156
+ * Remove Gemini sidebar from HTML
157
+ */
158
+ removeSidebar(html: string): string;
134
159
  parse(response: any, options?: ParseOptions): ParsedResponse;
135
160
  }
136
161
 
137
162
  declare class PerplexityProvider extends BaseProvider {
138
163
  readonly name: AIProvider;
139
164
  readonly baseUrl = "https://www.perplexity.ai";
140
- readonly defaultStyles = "\n html {\n filter: invert(1) hue-rotate(180deg);\n background-color: white !important;\n }\n img, video, iframe, svg {\n filter: invert(1) hue-rotate(180deg);\n }\n ";
141
165
  extractContent(response: any): ContentExtraction;
166
+ /**
167
+ * Remove Perplexity header/navbar from HTML
168
+ */
169
+ removeHeader(html: string): string;
170
+ /**
171
+ * Remove Perplexity footer/followup input from HTML
172
+ */
173
+ removeFooter(html: string): string;
142
174
  parse(response: any, options?: ParseOptions): ParsedResponse;
143
175
  }
144
176
 
145
177
  declare class CopilotProvider extends BaseProvider {
146
178
  readonly name: AIProvider;
147
179
  readonly baseUrl = "https://copilot.microsoft.com";
148
- readonly defaultStyles = "\n /* Copilot Sidebar & Header */\n div:has(> [data-testid=\"sidebar-container\"]),\n [data-testid=\"sidebar-container\"],\n [data-testid=\"sticky-header\"],\n .side-nav-menu-button {\n display: none !important;\n }\n\n /* General Layout Fixes */\n main {\n width: 100% !important;\n max-width: 100% !important;\n margin: 0 !important;\n }\n ";
149
180
  extractContent(response: any): ContentExtraction;
181
+ /**
182
+ * Remove Copilot header/navbar from HTML
183
+ */
184
+ removeHeader(html: string): string;
185
+ /**
186
+ * Remove Copilot footer/followup input box from HTML
187
+ */
188
+ removeFooter(html: string): string;
189
+ /**
190
+ * Remove Copilot sidebar from HTML
191
+ */
192
+ removeSidebar(html: string): string;
150
193
  parse(response: any, options?: ParseOptions): ParsedResponse;
151
194
  }
152
195
 
153
196
  declare class AIOverviewProvider extends BaseProvider {
154
197
  readonly name: AIProvider;
155
198
  readonly baseUrl = "https://www.google.com";
156
- readonly defaultStyles = "\n /* UI hiding - Google Search (AI Overview) */\n header, #header, #searchform, .sfbg, #appbar,\n div[role=\"navigation\"], #leftnav, #sidetogether,\n [role=\"banner\"], .Fgvgjc, #hdtb, .hdtb-msb,\n footer, #footer, .fbar,\n .pdp-nav, [aria-label=\"Main menu\"], .gb_Td, .gb_L,\n\n /* Specific AI Mode Selectors */\n .DZ13He,\n .wYq63b,\n .eT9Cje,\n .bNg8Rb,\n .S6VXfe,\n .Lu57id {\n display: none !important;\n }\n\n /* General Layout */\n main { width: 100% !important; max-width: 100% !important; margin: 0 !important; }\n ";
157
199
  extractContent(response: any): ContentExtraction;
200
+ /**
201
+ * Remove Google Search header/navbar from HTML
202
+ */
203
+ removeHeader(html: string): string;
204
+ /**
205
+ * Remove Google Search footer from HTML
206
+ */
207
+ removeFooter(html: string): string;
208
+ /**
209
+ * Remove Google Search sidebar from HTML
210
+ */
211
+ removeSidebar(html: string): string;
158
212
  parse(response: any, options?: ParseOptions): ParsedResponse;
159
213
  }
160
214
 
161
215
  declare class AIModeProvider extends BaseProvider {
162
216
  readonly name: AIProvider;
163
217
  readonly baseUrl = "https://www.google.com";
164
- readonly defaultStyles = "\n /* UI hiding - Google Search (AI Mode) */\n header, #header, #searchform, .sfbg, #appbar,\n div[role=\"navigation\"], #leftnav, #sidetogether,\n [role=\"banner\"], .Fgvgjc, #hdtb, .hdtb-msb,\n footer, #footer, .fbar,\n .pdp-nav, [aria-label=\"Main menu\"], .gb_Td, .gb_L,\n\n /* Specific AI Mode Selectors found in analysis */\n .DZ13He, /* Main sticky top bar */\n .wYq63b, /* Accessibility links bar */\n .eT9Cje, /* History/New Search buttons */\n .bNg8Rb, /* Hidden H1 headers */\n .S6VXfe, /* Accessibility container */\n .Lu57id /* Potential other top bar */ {\n display: none !important;\n }\n\n /* General Layout */\n main { width: 100% !important; max-width: 100% !important; margin: 0 !important; }\n ";
165
218
  extractContent(response: any): ContentExtraction;
219
+ /**
220
+ * Remove Google Search header/navbar from HTML
221
+ */
222
+ removeHeader(html: string): string;
223
+ /**
224
+ * Remove Google Search footer from HTML
225
+ */
226
+ removeFooter(html: string): string;
227
+ /**
228
+ * Remove Google Search sidebar from HTML
229
+ */
230
+ removeSidebar(html: string): string;
166
231
  parse(response: any, options?: ParseOptions): ParsedResponse;
167
232
  }
168
233
 
package/dist/index.esm.js CHANGED
@@ -1,2 +1,2 @@
1
- class t{static detect(t){const e={CHATGPT:0,GEMINI:0,PERPLEXITY:0,COPILOT:0,AIOVERVIEW:0,AIMODE:0};for(const[n,r]of Object.entries(this.PROVIDER_PATTERNS))for(const o of r)try{o(t)&&e[n]++}catch(t){}let n=0,r=null;for(const[t,o]of Object.entries(e))o>n&&(n=o,r=t);return 0===n?null:{provider:r,confidence:n/Object.values(e).reduce((t,e)=>Math.max(t,e),1)}}static getAllProviders(t){const e=[];for(const[n,r]of Object.entries(this.PROVIDER_PATTERNS)){let o=0;for(const e of r)try{e(t)&&o++}catch(t){}o>0&&e.push({provider:n,confidence:o/r.length})}return e.sort((t,e)=>e.confidence-t.confidence)}static validate(t,e){const n=this.detect(t);return(null==n?void 0:n.provider)===e&&n.confidence>.5}}t.PROVIDER_PATTERNS={CHATGPT:[t=>{var e;const n=(null===(e=null==t?void 0:t.result)||void 0===e?void 0:e.html)||(null==t?void 0:t.html)||"";return n.includes("bg-token-bg-primary")||n.includes("text-token-text-secondary")},t=>{var e;const n=(null===(e=null==t?void 0:t.result)||void 0===e?void 0:e.html)||(null==t?void 0:t.html)||"";return n.includes("chatgpt.com")||n.includes("openai.com")}],GEMINI:[t=>{var e;const n=(null===(e=null==t?void 0:t.result)||void 0===e?void 0:e.html)||(null==t?void 0:t.html)||"";return n.includes("bard-sidenav")||n.includes("mat-sidenav")},t=>{var e;const n=(null===(e=null==t?void 0:t.result)||void 0===e?void 0:e.html)||(null==t?void 0:t.html)||"";return n.includes("gemini.google.com")||n.includes("gem-sys-color")}],PERPLEXITY:[t=>{var e;const n=(null===(e=null==t?void 0:t.result)||void 0===e?void 0:e.html)||(null==t?void 0:t.html)||"";return n.includes("perplexity.ai")||n.includes("prose")}],COPILOT:[t=>{var e;const n=(null===(e=null==t?void 0:t.result)||void 0===e?void 0:e.html)||(null==t?void 0:t.html)||"";return n.includes("copilot.microsoft.com")||n.includes('data-testid="sidebar-container"')}],AIOVERVIEW:[t=>{var e,n,r,o;if(null===(n=null===(e=null==t?void 0:t.result)||void 0===e?void 0:e.aioverview)||void 0===n?void 0:n.text)return!0;if(null===(r=null==t?void 0:t.aioverview)||void 0===r?void 0:r.text)return!0;const i=(null===(o=null==t?void 0:t.result)||void 0===o?void 0:o.html)||(null==t?void 0:t.html)||"";return i.includes("WIZ_global_data")||i.includes("DnVkpd")}],AIMODE:[t=>{var e;const n=(null===(e=null==t?void 0:t.result)||void 0===e?void 0:e.html)||(null==t?void 0:t.html)||"";return n.includes("DZ13He")||n.includes("wYq63b")||n.includes("AI Mode")}]};class e{injectStyles(t,e){let n=t;(null==e?void 0:e.baseUrl)&&!t.includes("<base ")&&(n=n.includes("<head>")?n.replace("<head>",`<head><base href="${e.baseUrl}">`):n.replace(/(<html[^>]*>)/i,`$1<head><base href="${e.baseUrl}"></head>`));const r=(null==e?void 0:e.customCSS)?this.defaultStyles+"\n"+e.customCSS:this.defaultStyles;return n=n.includes("<head>")?n.replace("<head>",`<head><style>${r}</style>`):n.replace(/(<html[^>]*>)/i,`$1<head><style>${r}</style></head>`),n}sanitizeHtml(t){let e=t.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gim,"");return e=e.replace(/<noscript[\s\S]*?<\/noscript>/gi,""),e}isFullDocument(t){return/^\s*(<html|<!DOCTYPE)/i.test(t)}wrapFragment(t){return`<!DOCTYPE html>\n<html>\n<head>\n <meta charset="utf-8">\n <meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'none'; style-src 'unsafe-inline';">\n <style>\n body {\n margin: 0;\n padding: 16px;\n font-family: system-ui, -apple-system, sans-serif;\n white-space: pre-wrap;\n word-wrap: break-word;\n }\n img { max-width: 100%; height: auto; }\n body {\n pointer-events: none;\n user-select: none;\n }\n </style>\n</head>\n<body>\n ${t}\n</body>\n</html>`}}class n extends e{constructor(){super(...arguments),this.name="CHATGPT",this.baseUrl="https://chatgpt.com",this.defaultStyles='\n /* Force Dark Background on main containers and wrappers */\n html, body, main, article, footer, form,\n [class*="bg-"], [class*="footer"], [class*="bottom"],\n div[class*="border-t"],\n #thread-bottom-container, #thread-bottom,\n #thread, .composer-parent, [class*="group\\/thread"] {\n background-color: #131314 !important;\n color: #e3e3e3 !important;\n border-color: #2a2b36 !important;\n }\n\n /* Force background on specific white artifacts in the footer */\n #thread-bottom-container .bg-clip-padding,\n #thread-bottom-container .content-fade,\n #thread-bottom-container .absolute {\n background-color: transparent !important;\n }\n\n /* Specific targeting for the composer/input box (was white) */\n form .bg-token-bg-primary, form .shadow-short {\n background-color: #2a2b36 !important;\n border-color: #3e3f4b !important;\n box-shadow: none !important;\n }\n\n /* Disclaimer Footer - Force Dark Background */\n div[class*="text-token-text-secondary"] {\n color: #9ca3af !important;\n background-color: #131314 !important;\n }\n\n /* Force Text Color to Light */\n p, h1, h2, h3, h4, h5, h6, li, span, div, td, th, textarea, button {\n color: #e3e3e3 !important;\n }\n\n /* Links - Light Blue */\n a, a span {\n color: #8ab4f8 !important;\n }\n\n /* Code Blocks */\n pre, code, pre div, code span {\n background-color: #2a2b36 !important;\n color: #e3e3e3 !important;\n text-shadow: none !important;\n }\n\n /* Inputs/Textareas */\n input, textarea {\n background-color: transparent !important;\n color: #e3e3e3 !important;\n border-color: #3e3f4b !important;\n }\n\n /* Placeholder text */\n textarea::placeholder {\n color: #9ca3af !important;\n }\n\n /* Hide Sidebar */\n nav, [class*="sidebar"] {\n display: none !important;\n }\n\n /* Media visibility */\n img, video {\n opacity: 1 !important;\n }\n '}extractContent(t){let e="",n="",r=t;return t.result&&(r=t.result),"string"==typeof r?r.trim().startsWith("<")&&r.includes(">")?e=r:n=r:"object"==typeof r&&null!==r&&(r.html?e=r.html:r.content?r.content.trim().startsWith("<")?e=r.content:n=r.content:r.text&&(n=r.text)),{html:e,text:n}}parse(t,e){const{html:n,text:r}=this.extractContent(t);if(!n&&!r)throw new Error("No content found in ChatGPT response");let o=n||"";return!o&&r&&(o=`<div>${r.replace(/\n/g,"<br>")}</div>`),o=this.sanitizeHtml(o),o=this.injectStyles(o,{theme:(null==e?void 0:e.theme)||"dark",baseUrl:(null==e?void 0:e.baseUrl)||this.baseUrl}),{provider:this.name,html:o,text:r,metadata:{isFullDocument:this.isFullDocument(o)}}}}class r extends e{constructor(){super(...arguments),this.name="GEMINI",this.baseUrl="https://gemini.google.com",this.defaultStyles='\n /* Gemini Dark Mode Variable Overrides */\n :root {\n --gem-sys-color--surface: #131314 !important;\n --gem-sys-color--surface-container: #1e1f20 !important;\n --gem-sys-color--on-surface: #e3e3e3 !important;\n --bard-color-synthetic--chat-window-surface: #131314 !important;\n --bard-color-surface-dim-tmp: #131314 !important;\n }\n\n /* UI hiding - Gemini */\n bard-sidenav, mat-sidenav, .mat-drawer-backdrop, .side-nav-menu-button,\n\n /* Gemini "About Gemini" footer/navigation block */\n .gb_5a, .gb_5c, .gb_5d, .gb_5e,\n .gb_Uc, .gb_Vc, .gb_Wc,\n a[href*="about"],\n a[href*="subscriptions"],\n a[href*="business"],\n div[class*="gb_5"],\n .gb_Pd, .gb_Qd, .gb_Rd,\n .gb_Sd, .gb_Td, .gb_Ud, .gb_Vd,\n [aria-label*="About"],\n [aria-label*="Gemini App"],\n [aria-label*="Subscriptions"],\n [aria-label*="For Business"],\n *:contains("About Gemini"),\n *:contains("Gemini App"),\n *:contains("Subscriptions"),\n *:contains("For Business") {\n display: none !important;\n }\n\n /* General Layout */\n main { width: 100% !important; max-width: 100% !important; margin: 0 !important; }\n\n /* Force Dark Mode on Body and Gemini Containers */\n body, .content-container, chat-app, .main-content, .chat-container {\n background-color: #131314 !important;\n color: #e3e3e3 !important;\n }\n '}extractContent(t){let e="",n="",r=[],o=t;return t.result&&(o=t.result),"string"==typeof o?o.trim().startsWith("<")&&o.includes(">")?e=o:n=o:"object"==typeof o&&null!==o&&(o.html?e=o.html:o.content?o.content.trim().startsWith("<")?e=o.content:n=o.content:o.text&&(n=o.text),o.aioverview&&(o.aioverview.text&&(n=o.aioverview.text),o.aioverview.sources&&(r=o.aioverview.sources))),{html:e,text:n,sources:r}}parse(t,e){const{html:n,text:r,sources:o}=this.extractContent(t);if(!n&&!r)throw new Error("No content found in Gemini response");let i=n||"";return!i&&r&&(i=`<div>${r.replace(/\n/g,"<br>")}</div>`),i=this.sanitizeHtml(i),i=this.injectStyles(i,{theme:(null==e?void 0:e.theme)||"dark",baseUrl:(null==e?void 0:e.baseUrl)||this.baseUrl}),{provider:this.name,html:i,text:r,sources:o,metadata:{isFullDocument:this.isFullDocument(i)}}}}class o extends e{constructor(){super(...arguments),this.name="PERPLEXITY",this.baseUrl="https://www.perplexity.ai",this.defaultStyles="\n html {\n filter: invert(1) hue-rotate(180deg);\n background-color: white !important;\n }\n img, video, iframe, svg {\n filter: invert(1) hue-rotate(180deg);\n }\n "}extractContent(t){let e="",n="",r=t;return t.result&&(r=t.result),"string"==typeof r?r.trim().startsWith("<")&&r.includes(">")?e=r:n=r:"object"==typeof r&&null!==r&&(r.html?e=r.html:r.content?r.content.trim().startsWith("<")?e=r.content:n=r.content:r.text&&(n=r.text)),{html:e,text:n}}parse(t,e){const{html:n,text:r}=this.extractContent(t);if(!n&&!r)throw new Error("No content found in Perplexity response");let o=n||"";return!o&&r&&(o=`<div>${r.replace(/\n/g,"<br>")}</div>`),o=this.injectStyles(o,{theme:(null==e?void 0:e.theme)||"dark",baseUrl:(null==e?void 0:e.baseUrl)||this.baseUrl,customCSS:"light"===(null==e?void 0:e.theme)?"":this.defaultStyles}),{provider:this.name,html:o,text:r,metadata:{isFullDocument:this.isFullDocument(o)}}}}class i extends e{constructor(){super(...arguments),this.name="COPILOT",this.baseUrl="https://copilot.microsoft.com",this.defaultStyles='\n /* Copilot Sidebar & Header */\n div:has(> [data-testid="sidebar-container"]),\n [data-testid="sidebar-container"],\n [data-testid="sticky-header"],\n .side-nav-menu-button {\n display: none !important;\n }\n\n /* General Layout Fixes */\n main {\n width: 100% !important;\n max-width: 100% !important;\n margin: 0 !important;\n }\n '}extractContent(t){let e="",n="",r=t;return t.result&&(r=t.result),"string"==typeof r?r.trim().startsWith("<")&&r.includes(">")?e=r:n=r:"object"==typeof r&&null!==r&&(r.html?e=r.html:r.content?r.content.trim().startsWith("<")?e=r.content:n=r.content:r.text&&(n=r.text)),{html:e,text:n}}parse(t,e){const{html:n,text:r}=this.extractContent(t);if(!n&&!r)throw new Error("No content found in Copilot response");let o=n||"";return!o&&r&&(o=`<div>${r.replace(/\n/g,"<br>")}</div>`),o=o.replace(/<noscript[\s\S]*?<\/noscript>/gi,""),o=this.injectStyles(o,{theme:(null==e?void 0:e.theme)||"dark",baseUrl:(null==e?void 0:e.baseUrl)||this.baseUrl}),{provider:this.name,html:o,text:r,metadata:{isFullDocument:this.isFullDocument(o)}}}}class s extends e{constructor(){super(...arguments),this.name="AIOVERVIEW",this.baseUrl="https://www.google.com",this.defaultStyles='\n /* UI hiding - Google Search (AI Overview) */\n header, #header, #searchform, .sfbg, #appbar,\n div[role="navigation"], #leftnav, #sidetogether,\n [role="banner"], .Fgvgjc, #hdtb, .hdtb-msb,\n footer, #footer, .fbar,\n .pdp-nav, [aria-label="Main menu"], .gb_Td, .gb_L,\n\n /* Specific AI Mode Selectors */\n .DZ13He,\n .wYq63b,\n .eT9Cje,\n .bNg8Rb,\n .S6VXfe,\n .Lu57id {\n display: none !important;\n }\n\n /* General Layout */\n main { width: 100% !important; max-width: 100% !important; margin: 0 !important; }\n '}extractContent(t){let e="",n="",r=[],o=t;if(t.result&&(o=t.result),o.aioverview&&(o.aioverview.text&&(n=o.aioverview.text),o.aioverview.sources&&(r=o.aioverview.sources)),"string"==typeof o?o.trim().startsWith("<")&&o.includes(">")?e=o:n=n||o:"object"==typeof o&&null!==o&&(o.html&&!n?e=o.html:o.content&&!n?o.content.trim().startsWith("<")?e=o.content:n=o.content:o.text&&!n&&(n=o.text)),e){const t=e.match(/"DnVkpd"\s*:\s*"((?:[^"\\]|\\.)*)"/);if(t&&t[1])try{let e=JSON.parse(`"${t[1]}"`);e=e.replace(/∰/g,'<hr class="gemini-separator">'),e=e.replace(/∞(https:\/\/[^ ]+\.(?:jpg|png|webp|gif|jpeg)(?:\?[^ ]*)?)/gi,'<br><img src="$1" class="gemini-image" alt="Generated Image"><br>'),e=e.replace(/∞/g,"<br>"),e=e.replace(/\n/g,"<br>"),n=e}catch(t){console.error("Failed to parse AI Overview WIZ data",t)}}return{html:e,text:n,sources:r}}parse(t,e){const{html:n,text:r,sources:o}=this.extractContent(t);if(!n&&!r)throw new Error("No content found in AI Overview response");let i="";if(r&&!n){const t="\n body {\n font-family: 'Google Sans', Roboto, sans-serif;\n line-height: 1.5;\n padding: 20px;\n color: #e3e3e3;\n background-color: #131314;\n }\n .gemini-separator {\n border: 0;\n border-top: 1px solid #444;\n margin: 24px 0;\n }\n .gemini-image {\n max-width: 100%;\n border-radius: 8px;\n margin: 12px 0;\n border: 1px solid #333;\n }\n a { color: #8ab4f8; }\n table { border-collapse: collapse; width: 100%; margin: 16px 0; }\n th, td { border: 1px solid #444; padding: 8px; text-align: left; }\n th { background-color: #1f1f1f; }\n ";i=`<!DOCTYPE html>\n <html>\n <head>\n <base href="${(null==e?void 0:e.baseUrl)||this.baseUrl}">\n <style>${t}</style>\n </head>\n <body>\n ${r}\n </body>\n </html>`}else i=n||"",i=this.sanitizeHtml(i),i=this.injectStyles(i,{theme:(null==e?void 0:e.theme)||"dark",baseUrl:(null==e?void 0:e.baseUrl)||this.baseUrl,hideUI:!0});return{provider:this.name,html:i,text:r,sources:o,metadata:{isFullDocument:this.isFullDocument(i),hasWizData:!!r&&!n}}}}class a extends e{constructor(){super(...arguments),this.name="AIMODE",this.baseUrl="https://www.google.com",this.defaultStyles='\n /* UI hiding - Google Search (AI Mode) */\n header, #header, #searchform, .sfbg, #appbar,\n div[role="navigation"], #leftnav, #sidetogether,\n [role="banner"], .Fgvgjc, #hdtb, .hdtb-msb,\n footer, #footer, .fbar,\n .pdp-nav, [aria-label="Main menu"], .gb_Td, .gb_L,\n\n /* Specific AI Mode Selectors found in analysis */\n .DZ13He, /* Main sticky top bar */\n .wYq63b, /* Accessibility links bar */\n .eT9Cje, /* History/New Search buttons */\n .bNg8Rb, /* Hidden H1 headers */\n .S6VXfe, /* Accessibility container */\n .Lu57id /* Potential other top bar */ {\n display: none !important;\n }\n\n /* General Layout */\n main { width: 100% !important; max-width: 100% !important; margin: 0 !important; }\n '}extractContent(t){let e="",n="",r=t;return t.result&&(r=t.result),"string"==typeof r?r.trim().startsWith("<")&&r.includes(">")?e=r:n=r:"object"==typeof r&&null!==r&&(r.html?e=r.html:r.content?r.content.trim().startsWith("<")?e=r.content:n=r.content:r.text&&(n=r.text)),{html:e,text:n}}parse(t,e){const{html:n,text:r}=this.extractContent(t);if(!n&&!r)throw new Error("No content found in AI Mode response");let o=n||"";return!o&&r&&(o=`<div>${r.replace(/\n/g,"<br>")}</div>`),o=this.sanitizeHtml(o),o=this.injectStyles(o,{theme:(null==e?void 0:e.theme)||"dark",baseUrl:(null==e?void 0:e.baseUrl)||this.baseUrl,hideUI:!0}),{provider:this.name,html:o,text:r,metadata:{isFullDocument:this.isFullDocument(o)}}}}class l{constructor(){this.providers=new Map,this.providers.set("CHATGPT",new n),this.providers.set("GEMINI",new r),this.providers.set("PERPLEXITY",new o),this.providers.set("COPILOT",new i),this.providers.set("AIOVERVIEW",new s),this.providers.set("AIMODE",new a)}parse(e,n){const r=t.detect(e);if(!r)return this.parseGeneric(e,n);const o=this.providers.get(r.provider);if(!o)return null;try{const t=o.parse(e,n);return{...t,metadata:{...t.metadata,detectionConfidence:r.confidence}}}catch(t){return console.error(`Failed to parse response with ${r.provider}:`,t),null}}parseWithProvider(t,e,n){const r=this.providers.get(e);if(!r)throw new Error(`Unknown provider: ${e}`);try{return r.parse(t,n)}catch(t){return console.error(`Failed to parse response with ${e}:`,t),null}}detectProvider(e){const n=t.detect(e);return(null==n?void 0:n.provider)||null}detectAllProviders(e){return t.getAllProviders(e)}parseGeneric(t,e){let n="",r="";let o=t;var i;return t.result&&(o=t.result),"string"==typeof(i=o)?i.trim().startsWith("<")&&i.includes(">")?n=i:r=i:"object"==typeof i&&null!==i&&(i.html?n=i.html:i.content?i.content.trim().startsWith("<")?n=i.content:r=i.content:i.text&&(r=i.text)),n||r?(n&&(n=n.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gim,""),n=n.replace(/<noscript[\s\S]*?<\/noscript>/gi,"")),{provider:"CHATGPT",html:n,text:r,metadata:{isGeneric:!0}}):null}getSupportedProviders(){return Array.from(this.providers.keys())}registerProvider(t,e){this.providers.set(t,e)}}const c=new l,d=(t,e)=>c.parse(t,e),h=t=>c.detectProvider(t);export{a as AIModeProvider,s as AIOverviewProvider,l as AIResponseParser,e as BaseProvider,n as ChatGPTProvider,i as CopilotProvider,r as GeminiProvider,o as PerplexityProvider,t as ProviderDetector,h as detectProvider,d as parseAiResponse,c as parser};
1
+ class e{static detect(e){const t={CHATGPT:0,GEMINI:0,PERPLEXITY:0,COPILOT:0,AIOVERVIEW:0,AIMODE:0};for(const[r,o]of Object.entries(this.PROVIDER_PATTERNS))for(const n of o)try{n(e)&&t[r]++}catch(e){}let r=0,o=null;for(const[e,n]of Object.entries(t))n>r&&(r=n,o=e);return 0===r?null:{provider:o,confidence:r/Object.values(t).reduce((e,t)=>Math.max(e,t),1)}}static getAllProviders(e){const t=[];for(const[r,o]of Object.entries(this.PROVIDER_PATTERNS)){let n=0;for(const t of o)try{t(e)&&n++}catch(e){}n>0&&t.push({provider:r,confidence:n/o.length})}return t.sort((e,t)=>t.confidence-e.confidence)}static validate(e,t){const r=this.detect(e);return(null==r?void 0:r.provider)===t&&r.confidence>.5}}e.PROVIDER_PATTERNS={CHATGPT:[e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("bg-token-bg-primary")||r.includes("text-token-text-secondary")},e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("chatgpt.com")||r.includes("openai.com")}],GEMINI:[e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("bard-sidenav")||r.includes("mat-sidenav")},e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("gemini.google.com")||r.includes("gem-sys-color")}],PERPLEXITY:[e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("perplexity.ai")||r.includes("prose")}],COPILOT:[e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("copilot.microsoft.com")||r.includes('data-testid="sidebar-container"')}],AIOVERVIEW:[e=>{var t,r,o,n;if(null===(r=null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.aioverview)||void 0===r?void 0:r.text)return!0;if(null===(o=null==e?void 0:e.aioverview)||void 0===o?void 0:o.text)return!0;const i=(null===(n=null==e?void 0:e.result)||void 0===n?void 0:n.html)||(null==e?void 0:e.html)||"";return i.includes("WIZ_global_data")||i.includes("DnVkpd")}],AIMODE:[e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("DZ13He")||r.includes("wYq63b")||r.includes("AI Mode")}]};class t{injectStyles(e,t){let r=e;(null==t?void 0:t.baseUrl)&&!e.includes("<base ")&&(r=r.includes("<head>")?r.replace("<head>",`<head><base href="${t.baseUrl}">`):r.replace(/(<html[^>]*>)/i,`$1<head><base href="${t.baseUrl}"></head>`));const o=(null==t?void 0:t.customCSS)||"";return o&&r.includes("<head>")?r=r.replace("<head>",`<head><style>${o}</style>`):o&&(r=r.replace(/(<html[^>]*>)/i,`$1<head><style>${o}</style></head>`)),r}sanitizeHtml(e){let t=e.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gim,"");return t=t.replace(/<noscript[\s\S]*?<\/noscript>/gi,""),t}isFullDocument(e){return/^\s*(<html|<!DOCTYPE)/i.test(e)}removeLinks(e){return e.replace(/<a\b[^>]*>([\s\S]*?)<\/a>/gim,"$1")}wrapFragment(e){return`<!DOCTYPE html>\n<html>\n<head>\n <meta charset="utf-8">\n <meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'none'; style-src 'unsafe-inline';">\n <style>\n body {\n margin: 0;\n padding: 16px;\n font-family: system-ui, -apple-system, sans-serif;\n white-space: pre-wrap;\n word-wrap: break-word;\n }\n img { max-width: 100%; height: auto; }\n body {\n pointer-events: none;\n user-select: none;\n }\n </style>\n</head>\n<body>\n ${e}\n</body>\n</html>`}}class r extends t{constructor(){super(...arguments),this.name="CHATGPT",this.baseUrl="https://chatgpt.com"}extractContent(e){let t="",r="",o=e;return e.result&&(o=e.result),"string"==typeof o?o.trim().startsWith("<")&&o.includes(">")?t=o:r=o:"object"==typeof o&&null!==o&&(o.html?t=o.html:o.content?o.content.trim().startsWith("<")?t=o.content:r=o.content:o.text&&(r=o.text)),{html:t,text:r}}removeLinks(e){return e.replace(/<a\b([^>]*)>/gi,(e,t)=>{const r=t.replace(/\s+href\s*=\s*["'][^"']*["']/gi,"").replace(/\s+alt\s*=\s*["'][^"']*["']/gi,"").replace(/\s+rel\s*=\s*["'][^"']*["']/gi,"").replace(/\s+target\s*=\s*["'][^"']*["']/gi,"").trim();return`<span${r?" "+r:""}>`}).replace(/<\/a>/gi,"</span>")}removeSidebar(e){let t=e;return t=t.replace(/<nav[^>]*>.*?<\/nav>/gis,""),t=t.replace(/<div[^>]*class="[^"]*sidebar[^"]*"[^>]*>.*?<\/div>/gis,""),t}removeFooter(e){let t=e;return t=t.replace(/<div[^>]*id="thread-bottom-container"[^>]*>.*?<\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*id="thread-bottom"[^>]*>.*?<\/div><\/div><\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*\[grid-area:leading\][^"]*"[^>]*>.*?<\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*\[grid-area:footer\][^"]*"[^>]*>.*?<\/div><\/div><\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*\[grid-area:trailing\][^"]*"[^>]*>.*?<\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*text-token-text-secondary[^"]*"[^>]*>.*?ChatGPT can make mistakes\. Check important info\..*?<\/div><\/div>/gis,""),t}parse(e,t){var r;const{html:o,text:n}=this.extractContent(e);if(!o)throw new Error("No HTML content found in ChatGPT response");let i=o;const s=null!==(r=null==t?void 0:t.removeFooter)&&void 0!==r&&r;i=this.sanitizeHtml(i),(null==t?void 0:t.removeSidebar)&&(i=this.removeSidebar(i)),s&&(i=this.removeFooter(i)),(null==t?void 0:t.removeLinks)&&(i=this.removeLinks(i));const l=(null==t?void 0:t.invertColors)?"\n /* Force Dark Background on main containers */\n html, body, main, article, footer, form {\n background-color: #131314 !important;\n }\n ":'\n /* Force Light Background on main containers */\n html, body, main, article, footer, form {\n background-color: #ffffff !important;\n }\n\n /* Override ChatGPT token text color classes - targeting text content only */\n p[class*="text-token"], span[class*="text-token"], div[class*="text-token"],\n h1[class*="text-token"], h2[class*="text-token"], h3[class*="text-token"],\n h4[class*="text-token"], h5[class*="text-token"], h6[class*="text-token"],\n li[class*="text-token"], td[class*="text-token"], th[class*="text-token"],\n [class*="markdown-"], strong, b, em, i, h1, h2, h3, h4, h5, h6, p, li, td, th {\n color: #1a1a1a !important;\n }\n\n /* Force borders and dividers to be visible */\n hr, [class*="border"], [class*="divider"], [class*="separator"],\n [class*="border-t"], [class*="border-b"], [class*="border-l"], [class*="border-r"],\n table, tr, td, th {\n border-color: #d4d4d4 !important;\n }\n ';return i=this.injectStyles(i,{baseUrl:this.baseUrl,customCSS:l}),{provider:this.name,html:i,text:n,metadata:{isFullDocument:this.isFullDocument(i),sidebarRemoved:(null==t?void 0:t.removeSidebar)||!1,footerRemoved:s,linksRemoved:(null==t?void 0:t.removeLinks)||!1,colorsInverted:(null==t?void 0:t.invertColors)||!1}}}}class o extends t{constructor(){super(...arguments),this.name="GEMINI",this.baseUrl="https://gemini.google.com"}extractContent(e){let t="",r="",o=[],n=e;return e.result&&(n=e.result),"string"==typeof n?n.trim().startsWith("<")&&n.includes(">")?t=n:r=n:"object"==typeof n&&null!==n&&(n.html?t=n.html:n.content?n.content.trim().startsWith("<")?t=n.content:r=n.content:n.text&&(r=n.text),n.aioverview&&(n.aioverview.text&&(r=n.aioverview.text),n.aioverview.sources&&(o=n.aioverview.sources))),{html:t,text:r,sources:o}}removeHeader(e){let t=e;return t=t.replace(/<div[^>]*class="[^"]*boqOnegoogleliteOgbOneGoogleBar[^"]*"[^>]*>.*?<\/div><\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*side-nav-menu-button[^"]*"[^>]*>.*?<\/div>/gis,""),t=t.replace(/<top-bar-actions[^>]*>.*?<\/top-bar-actions>/gis,""),t=t.replace(/<div[^>]*class="[^"]*desktop-ogb-buffer[^"]*"[^>]*><\/div>/gis,""),t}removeFooter(e){return e.replace(/<input-container[^>]*>.*?<\/input-container>/gis,"")}removeSidebar(e){return e.replace(/<bard-sidenav[^>]*>.*?<\/bard-sidenav>/gis,"")}parse(e,t){var r,o;const{html:n,text:i,sources:s}=this.extractContent(e);if(!n)throw new Error("No HTML content found in Gemini response");let l=n;const a=null!==(r=null==t?void 0:t.removeHeader)&&void 0!==r&&r,d=null!==(o=null==t?void 0:t.removeFooter)&&void 0!==o&&o;return l=this.sanitizeHtml(l),a&&(l=this.removeHeader(l)),d&&(l=this.removeFooter(l)),(null==t?void 0:t.removeSidebar)&&(l=this.removeSidebar(l)),(null==t?void 0:t.removeLinks)&&(l=this.removeLinks(l)),l=this.injectStyles(l,{baseUrl:this.baseUrl,customCSS:""}),{provider:this.name,html:l,text:i,sources:s,metadata:{isFullDocument:this.isFullDocument(l),headerRemoved:a,footerRemoved:d,sidebarRemoved:(null==t?void 0:t.removeSidebar)||!1,linksRemoved:(null==t?void 0:t.removeLinks)||!1}}}}class n extends t{constructor(){super(...arguments),this.name="PERPLEXITY",this.baseUrl="https://www.perplexity.ai"}extractContent(e){let t="",r="",o=e;return e.result&&(o=e.result),"string"==typeof o?o.trim().startsWith("<")&&o.includes(">")?t=o:r=o:"object"==typeof o&&null!==o&&(o.html?t=o.html:o.content?o.content.trim().startsWith("<")?t=o.content:r=o.content:o.text&&(r=o.text)),{html:t,text:r}}removeHeader(e){return e.replace(/<div[^>]*class="[^"]*@container\/header[^"]*"[^>]*>.*?<div[^>]*class="[^"]*absolute bottom-0 inset-x-0 border-b[^"]*"[^>]*><\/div>/gis,"")}removeFooter(e){return e.replace(/<div[^>]*class="[^"]*erp-sidecar:fixed[^"]*"[^>]*>.*?<\/div>\s*<\/div>\s*<\/div>\s*<\/div>/gis,"")}parse(e,t){var r,o;const{html:n,text:i}=this.extractContent(e);if(!n)throw new Error("No HTML content found in Perplexity response");let s=n;const l=null!==(r=null==t?void 0:t.removeHeader)&&void 0!==r&&r,a=null!==(o=null==t?void 0:t.removeFooter)&&void 0!==o&&o;s=this.sanitizeHtml(s),l&&(s=this.removeHeader(s)),a&&(s=this.removeFooter(s)),(null==t?void 0:t.removeLinks)&&(s=this.removeLinks(s));const d=(null==t?void 0:t.invertColors)?"\n html {\n filter: invert(1) hue-rotate(180deg);\n background-color: white !important;\n }\n ":"";return s=this.injectStyles(s,{baseUrl:this.baseUrl,customCSS:d}),{provider:this.name,html:s,text:i,metadata:{isFullDocument:this.isFullDocument(s),linksRemoved:(null==t?void 0:t.removeLinks)||!1,colorsInverted:(null==t?void 0:t.invertColors)||!1,headerRemoved:l,footerRemoved:a}}}}class i extends t{constructor(){super(...arguments),this.name="COPILOT",this.baseUrl="https://copilot.microsoft.com"}extractContent(e){let t="",r="",o=e;return e.result&&(o=e.result),"string"==typeof o?o.trim().startsWith("<")&&o.includes(">")?t=o:r=o:"object"==typeof o&&null!==o&&(o.html?t=o.html:o.content?o.content.trim().startsWith("<")?t=o.content:r=o.content:o.text&&(r=o.text)),{html:t,text:r}}removeHeader(e){let t=e;return t=t.replace(/<div[^>]*class="[^"]*relative shrink-0 min-h-14[^"]*"[^>]*data-testid="backstage-chats"[^>]*>.*?<\/div>/gis,""),t}removeFooter(e){let t=e;return t=t.replace(/<div[^>]*class="[^"]*absolute bottom-0 w-full[^"]*"[^>]*>.*?<\/div><\/div><\/div><\/div><\/div><\/div><\/div><\/div><\/div><\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*mt-\[var\(--composer-container-height\)\][^"]*"[^>]*><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*pointer-events-none absolute flex justify-center z-20 inset-x-0 bottom-\[calc\(var\(--composer-container-height\)\+1rem\)\][^"]*"[^>]*>.*?<button[^>]*data-testid="scroll-to-bottom-button"[^>]*>.*?<\/button><\/div>/gis,""),t}removeSidebar(e){let t=e;return t=t.replace(/<div[^>]*class="[^"]*absolute h-full w-0 will-change-auto max-md:bg-sidebar-light[^"]*"[^>]*style="[^"]*"[^>]*>.*?<main/gis,"<main"),t}parse(e,t){var r,o;const{html:n,text:i}=this.extractContent(e);if(!n)throw new Error("No HTML content found in Copilot response");let s=n;const l=null!==(r=null==t?void 0:t.removeHeader)&&void 0!==r&&r,a=null!==(o=null==t?void 0:t.removeFooter)&&void 0!==o&&o;return s=this.sanitizeHtml(s),l&&(s=this.removeHeader(s)),a&&(s=this.removeFooter(s)),(null==t?void 0:t.removeSidebar)&&(s=this.removeSidebar(s)),(null==t?void 0:t.removeLinks)&&(s=this.removeLinks(s)),s=this.injectStyles(s,{baseUrl:this.baseUrl,customCSS:""}),{provider:this.name,html:s,text:i,metadata:{isFullDocument:this.isFullDocument(s),headerRemoved:l,footerRemoved:a,sidebarRemoved:(null==t?void 0:t.removeSidebar)||!1,linksRemoved:(null==t?void 0:t.removeLinks)||!1}}}}class s extends t{constructor(){super(...arguments),this.name="AIOVERVIEW",this.baseUrl="https://www.google.com"}extractContent(e){let t="",r=[],o=e;return e.result&&(o=e.result),o.aioverview&&o.aioverview.sources&&(r=o.aioverview.sources),"string"==typeof o?o.trim().startsWith("<")&&o.includes(">")&&(t=o):"object"==typeof o&&null!==o&&(o.html?t=o.html:o.content&&o.content.trim().startsWith("<")&&(t=o.content)),{html:t,sources:r}}removeHeader(e){return e}removeFooter(e){return e}removeSidebar(e){return e}parse(e,t){var r,o;const{html:n,sources:i}=this.extractContent(e);if(!n)throw new Error("No HTML content found in AI Overview response");let s=n;const l=null===(r=null==t?void 0:t.removeHeader)||void 0===r||r,a=null===(o=null==t?void 0:t.removeFooter)||void 0===o||o;s=this.sanitizeHtml(s),l&&(s=this.removeHeader(s)),a&&(s=this.removeFooter(s)),(null==t?void 0:t.removeSidebar)&&(s=this.removeSidebar(s)),(null==t?void 0:t.removeLinks)&&(s=this.removeLinks(s));let d="";return(null==t?void 0:t.invertColors)?d+="\n /* Dark theme */\n html, body, main, article, footer, form {\n background-color: #131314 !important;\n color: #e3e3e3 !important;\n }\n ":d+='\n /* Light theme - force all backgrounds to white */\n *, div, span, p, a, li, td, th, section, article, main, aside, nav, header, footer {\n background-color: #ffffff !important;\n }\n\n html, body, main, article, footer, form {\n background-color: #ffffff !important;\n }\n\n /* Force dark text color on all text elements */\n *, p, span, div, h1, h2, h3, h4, h5, h6, li, td, th, strong, b, em, i, a {\n color: #1a1a1a !important;\n }\n\n /* Force borders and dividers to be visible */\n hr, [class*="border"], [class*="divider"], [class*="separator"],\n [class*="border-t"], [class*="border-b"], [class*="border-l"], [class*="border-r"],\n table, tr, td, th {\n border-color: #d4d4d4 !important;\n }\n ',l&&(d+='\n /* Header hiding */\n header, #header, #searchform, .sfbg, #appbar,\n div[role="navigation"], #leftnav, #sidetogether,\n [role="banner"], .Fgvgjc, #hdtb, .hdtb-msb,\n .DZ13He, .wYq63b, .eT9Cje, .bNg8Rb, .S6VXfe, .Lu57id {\n display: none !important;\n }\n '),(null==t?void 0:t.removeSidebar)&&(d+="\n /* Sidebar hiding */\n #leftnav, #sidetogether {\n display: none !important;\n }\n "),a&&(d+='\n /* Footer hiding */\n footer, #footer, .fbar,\n .pdp-nav, [aria-label="Main menu"], .gb_Td, .gb_L {\n display: none !important;\n }\n '),s=this.injectStyles(s,{baseUrl:this.baseUrl,customCSS:d}),{provider:this.name,html:s,sources:i,metadata:{isFullDocument:this.isFullDocument(s),headerRemoved:l,footerRemoved:a,sidebarRemoved:(null==t?void 0:t.removeSidebar)||!1,linksRemoved:(null==t?void 0:t.removeLinks)||!1,colorsInverted:(null==t?void 0:t.invertColors)||!1}}}}class l extends t{constructor(){super(...arguments),this.name="AIMODE",this.baseUrl="https://www.google.com"}extractContent(e){let t="",r="",o=e;return e.result&&(o=e.result),"string"==typeof o?o.trim().startsWith("<")&&o.includes(">")?t=o:r=o:"object"==typeof o&&null!==o&&(o.html?t=o.html:o.content?o.content.trim().startsWith("<")?t=o.content:r=o.content:o.text&&(r=o.text)),{html:t,text:r}}removeHeader(e){let t=e;return t=t.replace(/<div[^>]*jsname="oEQ3x"[^>]*class="[^"]*DZ13He[^"]*"[^>]*>.*?<hr class="e9c7U">.*?<\/div><\/div><\/div><\/div><\/div>/gis,""),t}removeFooter(e){let t=e;return t=t.replace(/<div[^>]*data-xid="aim-mars-input-plate"[^>]*>[\s\S]*?<\/div><\/div><\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*jscontroller="P5gZDb"[^>]*>[\s\S]*?<\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*t0ITR hh3ttd[^"]*"[^>]*>[\s\S]*?<\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*y4VEUd vve6Ce[^"]*"[^>]*>[\s\S]*?<\/div><\/div>/gis,""),t}removeSidebar(e){let t=e;return t=t.replace(/<div[^>]*class="[^"]*ho072b[^"]*"[^>]*aria-label="AI Mode history"[^>]*>[\s\S]*?<\/div><\/div><\/div><\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*jsname="NlVIob"[^>]*class="[^"]*qEn1od[^"]*"[^>]*>[\s\S]*?<\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*OEwhSe[^"]*"[^>]*>[\s\S]*?<\/div><\/div>/gis,""),t=t.replace(/<button[^>]*aria-label="Start new search"[^>]*>[\s\S]*?<\/button>/gis,""),t=t.replace(/<button[^>]*aria-label="AI Mode history"[^>]*>[\s\S]*?<\/button>/gis,""),t}parse(e,t){var r,o;const{html:n,text:i}=this.extractContent(e);if(!n)throw new Error("No HTML content found in AI Mode response");let s=n;const l=null===(r=null==t?void 0:t.removeHeader)||void 0===r||r,a=null===(o=null==t?void 0:t.removeFooter)||void 0===o||o;s=this.sanitizeHtml(s),l&&(s=this.removeHeader(s)),a&&(s=this.removeFooter(s)),(null==t?void 0:t.removeSidebar)&&(s=this.removeSidebar(s)),(null==t?void 0:t.removeLinks)&&(s=this.removeLinks(s));let d="";return d+="",(null==t?void 0:t.invertColors)?d+="\n /* Dark theme */\n html, body, main, article, footer, form {\n background-color: #131314 !important;\n color: #e3e3e3 !important;\n }\n ":d+='\n /* Light theme - force all backgrounds to white */\n *, div, span, p, a, li, td, th, section, article, main, aside, nav, header, footer {\n background-color: #ffffff !important;\n }\n\n html, body, main, article, footer, form {\n background-color: #ffffff !important;\n }\n\n /* Force dark text color on all text elements */\n *, p, span, div, h1, h2, h3, h4, h5, h6, li, td, th, strong, b, em, i, a {\n color: #1a1a1a !important;\n }\n\n /* Force borders and dividers to be visible */\n hr, [class*="border"], [class*="divider"], [class*="separator"],\n [class*="border-t"], [class*="border-b"], [class*="border-l"], [class*="border-r"],\n table, tr, td, th {\n border-color: #d4d4d4 !important;\n }\n ',l&&(d+='\n /* Header hiding */\n header, #header, #searchform, .sfbg, #appbar,\n div[role="navigation"], #leftnav, #sidetogether,\n [role="banner"], .Fgvgjc, #hdtb, .hdtb-msb,\n .DZ13He, .wYq63b, .eT9Cje, .bNg8Rb, .S6VXfe, .Lu57id {\n display: none !important;\n }\n '),(null==t?void 0:t.removeSidebar)&&(d+="\n /* Sidebar hiding */\n #leftnav, #sidetogether {\n display: none !important;\n }\n "),a&&(d+='\n /* Footer hiding */\n footer, #footer, .fbar,\n .pdp-nav, [aria-label="Main menu"], .gb_Td, .gb_L {\n display: none !important;\n }\n '),s=this.injectStyles(s,{baseUrl:this.baseUrl,customCSS:d}),{provider:this.name,html:s,text:i,metadata:{isFullDocument:this.isFullDocument(s),headerRemoved:l,footerRemoved:a,sidebarRemoved:(null==t?void 0:t.removeSidebar)||!1,linksRemoved:(null==t?void 0:t.removeLinks)||!1,colorsInverted:(null==t?void 0:t.invertColors)||!1}}}}class a{constructor(){this.providers=new Map,this.providers.set("CHATGPT",new r),this.providers.set("GEMINI",new o),this.providers.set("PERPLEXITY",new n),this.providers.set("COPILOT",new i),this.providers.set("AIOVERVIEW",new s),this.providers.set("AIMODE",new l)}parse(t,r){const o=e.detect(t);if(!o)return this.parseGeneric(t,r);const n=this.providers.get(o.provider);if(!n)return null;try{const e=n.parse(t,r);return{...e,metadata:{...e.metadata,detectionConfidence:o.confidence}}}catch(e){return console.error(`Failed to parse response with ${o.provider}:`,e),null}}parseWithProvider(e,t,r){const o=this.providers.get(t);if(!o)throw new Error(`Unknown provider: ${t}`);try{return o.parse(e,r)}catch(e){return console.error(`Failed to parse response with ${t}:`,e),null}}detectProvider(t){const r=e.detect(t);return(null==r?void 0:r.provider)||null}detectAllProviders(t){return e.getAllProviders(t)}parseGeneric(e,t){let r="",o="";let n=e;var i;return e.result&&(n=e.result),"string"==typeof(i=n)?i.trim().startsWith("<")&&i.includes(">")?r=i:o=i:"object"==typeof i&&null!==i&&(i.html?r=i.html:i.content?i.content.trim().startsWith("<")?r=i.content:o=i.content:i.text&&(o=i.text)),r||o?(r&&(r=r.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gim,""),r=r.replace(/<noscript[\s\S]*?<\/noscript>/gi,"")),{provider:"CHATGPT",html:r,text:o,metadata:{isGeneric:!0}}):null}getSupportedProviders(){return Array.from(this.providers.keys())}registerProvider(e,t){this.providers.set(e,t)}}const d=new a,c=(e,t)=>d.parse(e,t),v=e=>d.detectProvider(e);export{l as AIModeProvider,s as AIOverviewProvider,a as AIResponseParser,t as BaseProvider,r as ChatGPTProvider,i as CopilotProvider,o as GeminiProvider,n as PerplexityProvider,e as ProviderDetector,v as detectProvider,c as parseAiResponse,d as parser};
2
2
  //# sourceMappingURL=index.esm.js.map