@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.
- package/README.md +107 -50
- package/dist/core/types.d.ts +5 -6
- package/dist/core/types.d.ts.map +1 -1
- package/dist/index.d.ts +78 -13
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/providers/ai-mode.d.ts +14 -3
- package/dist/providers/ai-mode.d.ts.map +1 -1
- package/dist/providers/ai-overview.d.ts +14 -3
- package/dist/providers/ai-overview.d.ts.map +1 -1
- package/dist/providers/base-provider.d.ts +4 -1
- package/dist/providers/base-provider.d.ts.map +1 -1
- package/dist/providers/chatgpt.d.ts +15 -3
- package/dist/providers/chatgpt.d.ts.map +1 -1
- package/dist/providers/copilot.d.ts +12 -1
- package/dist/providers/copilot.d.ts.map +1 -1
- package/dist/providers/gemini.d.ts +12 -1
- package/dist/providers/gemini.d.ts.map +1 -1
- package/dist/providers/perplexity.d.ts +10 -3
- package/dist/providers/perplexity.d.ts.map +1 -1
- package/dist/react/components/AiResponseRenderer.d.ts +2 -2
- package/dist/react/components/AiResponseRenderer.d.ts.map +1 -1
- package/dist/react/components/ResponseRenderer.d.ts +24 -0
- package/dist/react/components/ResponseRenderer.d.ts.map +1 -0
- package/dist/react/core/types.d.ts +5 -6
- package/dist/react/core/types.d.ts.map +1 -1
- package/dist/react/hooks/useAiResponse.d.ts.map +1 -1
- package/dist/react/hooks/useResponse.d.ts +19 -0
- package/dist/react/hooks/useResponse.d.ts.map +1 -0
- package/dist/react/index.d.ts +13 -14
- package/dist/react/index.esm.js +1 -1
- package/dist/react/index.esm.js.map +1 -1
- package/dist/react/index.js +1 -1
- package/dist/react/index.js.map +1 -1
- package/dist/react/providers/ai-mode.d.ts +14 -3
- package/dist/react/providers/ai-mode.d.ts.map +1 -1
- package/dist/react/providers/ai-overview.d.ts +14 -3
- package/dist/react/providers/ai-overview.d.ts.map +1 -1
- package/dist/react/providers/base-provider.d.ts +4 -1
- package/dist/react/providers/base-provider.d.ts.map +1 -1
- package/dist/react/providers/chatgpt.d.ts +15 -3
- package/dist/react/providers/chatgpt.d.ts.map +1 -1
- package/dist/react/providers/copilot.d.ts +12 -1
- package/dist/react/providers/copilot.d.ts.map +1 -1
- package/dist/react/providers/gemini.d.ts +12 -1
- package/dist/react/providers/gemini.d.ts.map +1 -1
- package/dist/react/providers/perplexity.d.ts +10 -3
- package/dist/react/providers/perplexity.d.ts.map +1 -1
- package/dist/react/react/components/AiResponseRenderer.d.ts +2 -2
- package/dist/react/react/components/AiResponseRenderer.d.ts.map +1 -1
- package/dist/react/react/components/ResponseRenderer.d.ts +24 -0
- package/dist/react/react/components/ResponseRenderer.d.ts.map +1 -0
- package/dist/react/react/hooks/useAiResponse.d.ts.map +1 -1
- package/dist/react/react/hooks/useResponse.d.ts +19 -0
- package/dist/react/react/hooks/useResponse.d.ts.map +1 -0
- package/dist/react/react/index.d.ts +6 -6
- package/dist/react/react/index.d.ts.map +1 -1
- 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
|
-
- 🎨 **
|
|
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
|
|
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
|
|
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 {
|
|
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
|
-
<
|
|
50
|
+
<ResponseRenderer
|
|
51
51
|
response={aiResponse}
|
|
52
|
-
|
|
52
|
+
removeLinks={false}
|
|
53
|
+
invertColors={false}
|
|
53
54
|
autoDetect
|
|
54
55
|
className="w-full h-96"
|
|
55
56
|
iframeProps={{
|
|
56
|
-
sandbox:
|
|
57
|
+
sandbox: "allow-popups",
|
|
57
58
|
}}
|
|
58
|
-
onProviderDetected={(provider) => console.log(
|
|
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
|
-
|
|
74
|
-
- `
|
|
75
|
-
- `
|
|
76
|
-
- `
|
|
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
|
-
#### `<
|
|
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
|
-
#### `
|
|
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
|
|
121
|
-
|
|
122
|
-
| ChatGPT
|
|
123
|
-
| Gemini
|
|
124
|
-
| Perplexity
|
|
125
|
-
| Copilot
|
|
126
|
-
| AI Overview | ✅
|
|
127
|
-
| AI Mode
|
|
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
|
-
###
|
|
153
|
+
### Remove Hyperlinks
|
|
132
154
|
|
|
133
155
|
```typescript
|
|
134
|
-
import { parseAiResponse } from
|
|
156
|
+
import { parseAiResponse } from "@cloro-dev/response-parser";
|
|
135
157
|
|
|
136
158
|
const parsed = parseAiResponse(response, {
|
|
137
|
-
|
|
138
|
-
theme: 'dark'
|
|
159
|
+
removeLinks: true, // Removes all <a> tags, keeps text
|
|
139
160
|
});
|
|
140
161
|
```
|
|
141
162
|
|
|
142
|
-
###
|
|
163
|
+
### Dark Mode
|
|
143
164
|
|
|
144
165
|
```tsx
|
|
145
|
-
<
|
|
166
|
+
<ResponseRenderer
|
|
146
167
|
response={response}
|
|
147
|
-
|
|
148
|
-
|
|
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
|
-
<
|
|
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 ©
|
|
252
|
+
MIT © cloro
|
package/dist/core/types.d.ts
CHANGED
|
@@ -7,22 +7,21 @@ export interface ParsedResponse {
|
|
|
7
7
|
metadata?: Record<string, any>;
|
|
8
8
|
}
|
|
9
9
|
export interface ParseOptions {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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;
|
package/dist/core/types.d.ts.map
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|