@cloro-dev/response-parser 0.1.1 → 0.1.3
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 +70 -39
- package/dist/core/types.d.ts +2 -5
- package/dist/core/types.d.ts.map +1 -1
- package/dist/index.d.ts +7 -6
- 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/base-provider.d.ts +4 -0
- package/dist/providers/base-provider.d.ts.map +1 -1
- package/dist/providers/perplexity.d.ts +3 -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 +2 -5
- 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 +10 -13
- package/dist/react/index.esm.js +1 -10
- package/dist/react/index.esm.js.map +1 -1
- package/dist/react/index.js +1 -10
- package/dist/react/index.js.map +1 -1
- package/dist/react/providers/base-provider.d.ts +4 -0
- package/dist/react/providers/base-provider.d.ts.map +1 -1
- package/dist/react/providers/perplexity.d.ts +3 -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 +10 -11
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 '@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
|
|
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,15 +41,16 @@ 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={{
|
|
@@ -70,10 +71,8 @@ function MyComponent() {
|
|
|
70
71
|
Parse an AI response with auto-detected provider.
|
|
71
72
|
|
|
72
73
|
**Options:**
|
|
73
|
-
- `
|
|
74
|
-
- `
|
|
75
|
-
- `sanitize`: Remove scripts (default: `true`)
|
|
76
|
-
- `includeStyles`: Inject provider-specific styles (default: `true`)
|
|
74
|
+
- `removeLinks`: `boolean` - Remove all hyperlinks from HTML (default: `false`)
|
|
75
|
+
- `invertColors`: `boolean` - Apply color inversion for dark mode, primarily for Perplexity (default: `false`)
|
|
77
76
|
|
|
78
77
|
**Returns:** `ParsedResponse | null`
|
|
79
78
|
|
|
@@ -85,27 +84,38 @@ Detect the AI provider from a response.
|
|
|
85
84
|
|
|
86
85
|
### React Components
|
|
87
86
|
|
|
88
|
-
#### `<
|
|
87
|
+
#### `<ResponseRenderer />`
|
|
89
88
|
|
|
90
89
|
Main React component for rendering AI responses.
|
|
91
90
|
|
|
92
91
|
**Props:**
|
|
93
92
|
- `response`: The AI response object
|
|
94
|
-
- `theme`: Light or dark mode
|
|
95
93
|
- `autoDetect`: Auto-detect provider (default: `true`)
|
|
96
94
|
- `provider`: Explicitly specify provider
|
|
95
|
+
- `removeLinks`: Remove all hyperlinks (default: `false`)
|
|
96
|
+
- `invertColors`: Apply color inversion (default: `false`)
|
|
97
97
|
- `className`: CSS class for container
|
|
98
98
|
- `iframeProps`: Additional props for iframe
|
|
99
99
|
- `loadingComponent`: Custom loading component
|
|
100
100
|
- `errorComponent`: Custom error component
|
|
101
|
+
- `fallbackComponent`: Custom fallback component
|
|
102
|
+
- `onRenderComplete`: Callback when rendering completes
|
|
101
103
|
- `onProviderDetected`: Callback when provider is detected
|
|
102
104
|
|
|
103
105
|
### Hooks
|
|
104
106
|
|
|
105
|
-
#### `
|
|
107
|
+
#### `useResponse(response, options?)`
|
|
106
108
|
|
|
107
109
|
React hook for parsing AI responses.
|
|
108
110
|
|
|
111
|
+
**Options:**
|
|
112
|
+
- `autoDetect`: Auto-detect provider (default: `true`)
|
|
113
|
+
- `provider`: Explicitly specify provider
|
|
114
|
+
- `removeLinks`: Remove all hyperlinks (default: `false`)
|
|
115
|
+
- `invertColors`: Apply color inversion (default: `false`)
|
|
116
|
+
- `onProviderDetected`: Callback when provider is detected
|
|
117
|
+
- `onError`: Callback when error occurs
|
|
118
|
+
|
|
109
119
|
**Returns:**
|
|
110
120
|
- `parsed`: Parsed response object
|
|
111
121
|
- `provider`: Detected provider
|
|
@@ -113,6 +123,7 @@ React hook for parsing AI responses.
|
|
|
113
123
|
- `error`: Error object
|
|
114
124
|
- `html`: HTML string
|
|
115
125
|
- `text`: Plain text string
|
|
126
|
+
- `sources`: Sources array (if available)
|
|
116
127
|
- `reparse`: Function to re-parse with new options
|
|
117
128
|
|
|
118
129
|
## Supported Providers
|
|
@@ -121,39 +132,43 @@ React hook for parsing AI responses.
|
|
|
121
132
|
|----------|--------|----------|
|
|
122
133
|
| ChatGPT | ✅ | Dark mode, sidebar hiding |
|
|
123
134
|
| Gemini | ✅ | Material Design overrides |
|
|
124
|
-
| Perplexity | ✅ | Color inversion for dark mode |
|
|
135
|
+
| Perplexity | ✅ | Color inversion for dark mode, link removal |
|
|
125
136
|
| Copilot | ✅ | UI element hiding |
|
|
126
137
|
| AI Overview | ✅ | WIZ data extraction |
|
|
127
138
|
| AI Mode | ✅ | Google UI hiding |
|
|
128
139
|
|
|
129
140
|
## Examples
|
|
130
141
|
|
|
131
|
-
###
|
|
142
|
+
### Remove Hyperlinks (Perplexity)
|
|
132
143
|
|
|
133
144
|
```typescript
|
|
134
|
-
import { parseAiResponse } from '
|
|
145
|
+
import { parseAiResponse } from '@cloro-dev/response-parser';
|
|
135
146
|
|
|
136
147
|
const parsed = parseAiResponse(response, {
|
|
137
|
-
|
|
138
|
-
theme: 'dark'
|
|
148
|
+
removeLinks: true // Removes all <a> tags, keeps text
|
|
139
149
|
});
|
|
140
150
|
```
|
|
141
151
|
|
|
142
|
-
###
|
|
152
|
+
### Dark Mode for Perplexity
|
|
143
153
|
|
|
144
154
|
```tsx
|
|
145
|
-
<
|
|
146
|
-
response={
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
onRenderComplete={(html) => console.log('Rendered', html)}
|
|
150
|
-
iframeProps={{
|
|
151
|
-
className: 'custom-iframe',
|
|
152
|
-
style: { border: 'none', borderRadius: '8px' }
|
|
153
|
-
}}
|
|
155
|
+
<ResponseRenderer
|
|
156
|
+
response={perplexityResponse}
|
|
157
|
+
invertColors={true} // Apply CSS filter for dark mode
|
|
158
|
+
removeLinks={true} // Optionally remove links
|
|
154
159
|
/>
|
|
155
160
|
```
|
|
156
161
|
|
|
162
|
+
### Manual Provider Specification
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
import { parseAiResponse, AIProvider } from '@cloro-dev/response-parser';
|
|
166
|
+
|
|
167
|
+
const parsed = parseAiResponse(response, {
|
|
168
|
+
provider: 'CHATGPT'
|
|
169
|
+
});
|
|
170
|
+
```
|
|
171
|
+
|
|
157
172
|
### Error Handling
|
|
158
173
|
|
|
159
174
|
```tsx
|
|
@@ -164,12 +179,32 @@ const ErrorComponent = ({ error, retry }) => (
|
|
|
164
179
|
</div>
|
|
165
180
|
);
|
|
166
181
|
|
|
167
|
-
<
|
|
182
|
+
<ResponseRenderer
|
|
168
183
|
response={response}
|
|
169
184
|
errorComponent={ErrorComponent}
|
|
170
185
|
/>
|
|
171
186
|
```
|
|
172
187
|
|
|
188
|
+
## What's Changed in v0.1.3
|
|
189
|
+
|
|
190
|
+
### Simplified API
|
|
191
|
+
- ✅ **Always sanitizes** HTML by default (removes scripts for security)
|
|
192
|
+
- ✅ **Always includes** provider-specific styles
|
|
193
|
+
- ✅ **Always uses** provider's base URL for relative links
|
|
194
|
+
- ❌ **Removed** `theme` option (styles are provider-specific)
|
|
195
|
+
- ❌ **Removed** `sanitize` option (always enabled)
|
|
196
|
+
- ❌ **Removed** `includeStyles` option (always enabled)
|
|
197
|
+
- ❌ **Removed** `baseUrl` option (uses provider default)
|
|
198
|
+
|
|
199
|
+
### Remaining Options
|
|
200
|
+
Only two options remain for simple usage:
|
|
201
|
+
- `removeLinks`: Remove all hyperlinks from HTML
|
|
202
|
+
- `invertColors`: Apply color inversion (mainly for Perplexity)
|
|
203
|
+
|
|
204
|
+
### Component Renaming
|
|
205
|
+
- `AiResponseRenderer` → `ResponseRenderer`
|
|
206
|
+
- `useAiResponse` → `useResponse`
|
|
207
|
+
|
|
173
208
|
## Development
|
|
174
209
|
|
|
175
210
|
```bash
|
|
@@ -186,10 +221,6 @@ pnpm test
|
|
|
186
221
|
pnpm dev
|
|
187
222
|
```
|
|
188
223
|
|
|
189
|
-
## Contributing
|
|
190
|
-
|
|
191
|
-
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
192
|
-
|
|
193
224
|
## License
|
|
194
225
|
|
|
195
|
-
MIT ©
|
|
226
|
+
MIT © cloro
|
package/dist/core/types.d.ts
CHANGED
|
@@ -7,10 +7,8 @@ export interface ParsedResponse {
|
|
|
7
7
|
metadata?: Record<string, any>;
|
|
8
8
|
}
|
|
9
9
|
export interface ParseOptions {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
sanitize?: boolean;
|
|
13
|
-
includeStyles?: boolean;
|
|
10
|
+
removeLinks?: boolean;
|
|
11
|
+
invertColors?: boolean;
|
|
14
12
|
}
|
|
15
13
|
export interface ProviderConfig {
|
|
16
14
|
name: AIProvider;
|
|
@@ -22,7 +20,6 @@ export interface DetectedProvider {
|
|
|
22
20
|
confidence: number;
|
|
23
21
|
}
|
|
24
22
|
export interface StyleOptions {
|
|
25
|
-
theme?: 'light' | 'dark';
|
|
26
23
|
customCSS?: string;
|
|
27
24
|
hideUI?: boolean;
|
|
28
25
|
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;CACxB;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,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,10 +7,8 @@ interface ParsedResponse {
|
|
|
7
7
|
metadata?: Record<string, any>;
|
|
8
8
|
}
|
|
9
9
|
interface ParseOptions {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
sanitize?: boolean;
|
|
13
|
-
includeStyles?: boolean;
|
|
10
|
+
removeLinks?: boolean;
|
|
11
|
+
invertColors?: boolean;
|
|
14
12
|
}
|
|
15
13
|
interface ProviderConfig {
|
|
16
14
|
name: AIProvider;
|
|
@@ -22,7 +20,6 @@ interface DetectedProvider {
|
|
|
22
20
|
confidence: number;
|
|
23
21
|
}
|
|
24
22
|
interface StyleOptions {
|
|
25
|
-
theme?: 'light' | 'dark';
|
|
26
23
|
customCSS?: string;
|
|
27
24
|
hideUI?: boolean;
|
|
28
25
|
baseUrl?: string;
|
|
@@ -112,6 +109,10 @@ declare abstract class BaseProvider {
|
|
|
112
109
|
* Check if content is a full HTML document
|
|
113
110
|
*/
|
|
114
111
|
isFullDocument(html: string): boolean;
|
|
112
|
+
/**
|
|
113
|
+
* Remove all links from HTML, keeping the text content
|
|
114
|
+
*/
|
|
115
|
+
removeLinks(html: string): string;
|
|
115
116
|
/**
|
|
116
117
|
* Wrap HTML fragment in a document
|
|
117
118
|
*/
|
|
@@ -137,7 +138,7 @@ declare class GeminiProvider extends BaseProvider {
|
|
|
137
138
|
declare class PerplexityProvider extends BaseProvider {
|
|
138
139
|
readonly name: AIProvider;
|
|
139
140
|
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
|
|
141
|
+
readonly defaultStyles = "\n html {\n filter: invert(1) hue-rotate(180deg);\n background-color: white !important;\n }\n ";
|
|
141
142
|
extractContent(response: any): ContentExtraction;
|
|
142
143
|
parse(response: any, options?: ParseOptions): ParsedResponse;
|
|
143
144
|
}
|
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 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)||"";return r&&n.includes("<head>")?n=n.replace("<head>",`<head><style>${r}</style>`):r&&(n=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)}removeLinks(t){return t.replace(/<a\b[^>]*>([\s\S]*?)<\/a>/gim,"$1")}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,{baseUrl:this.baseUrl,customCSS:this.defaultStyles}),{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,{baseUrl:this.baseUrl,customCSS:this.defaultStyles}),{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 "}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.sanitizeHtml(o),(null==e?void 0:e.removeLinks)&&(o=this.removeLinks(o)),o=this.injectStyles(o,{baseUrl:this.baseUrl,customCSS:(null==e?void 0:e.invertColors)?this.defaultStyles:""}),{provider:this.name,html:o,text:r,metadata:{isFullDocument:this.isFullDocument(o),linksRemoved:(null==e?void 0:e.removeLinks)||!1,colorsInverted:(null==e?void 0:e.invertColors)||!1}}}}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=this.sanitizeHtml(o),o=this.injectStyles(o,{baseUrl:this.baseUrl,customCSS:this.defaultStyles}),{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="${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,{baseUrl:this.baseUrl,hideUI:!0,customCSS:this.defaultStyles});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,{baseUrl:this.baseUrl,hideUI:!0,customCSS:this.defaultStyles}),{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};
|
|
2
2
|
//# sourceMappingURL=index.esm.js.map
|