@cloro-dev/response-parser 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/README.md +195 -0
  2. package/dist/core/detector.d.ts +17 -0
  3. package/dist/core/detector.d.ts.map +1 -0
  4. package/dist/core/parser.d.ts +40 -0
  5. package/dist/core/parser.d.ts.map +1 -0
  6. package/dist/core/types.d.ts +35 -0
  7. package/dist/core/types.d.ts.map +1 -0
  8. package/dist/index.d.ts +170 -0
  9. package/dist/index.d.ts.map +1 -0
  10. package/dist/index.esm.js +2 -0
  11. package/dist/index.esm.js.map +1 -0
  12. package/dist/index.js +2 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/providers/ai-mode.d.ts +10 -0
  15. package/dist/providers/ai-mode.d.ts.map +1 -0
  16. package/dist/providers/ai-overview.d.ts +10 -0
  17. package/dist/providers/ai-overview.d.ts.map +1 -0
  18. package/dist/providers/base-provider.d.ts +31 -0
  19. package/dist/providers/base-provider.d.ts.map +1 -0
  20. package/dist/providers/chatgpt.d.ts +10 -0
  21. package/dist/providers/chatgpt.d.ts.map +1 -0
  22. package/dist/providers/copilot.d.ts +10 -0
  23. package/dist/providers/copilot.d.ts.map +1 -0
  24. package/dist/providers/gemini.d.ts +10 -0
  25. package/dist/providers/gemini.d.ts.map +1 -0
  26. package/dist/providers/perplexity.d.ts +10 -0
  27. package/dist/providers/perplexity.d.ts.map +1 -0
  28. package/dist/react/components/AiResponseRenderer.d.ts +24 -0
  29. package/dist/react/components/AiResponseRenderer.d.ts.map +1 -0
  30. package/dist/react/components/IframeRenderer.d.ts +12 -0
  31. package/dist/react/components/IframeRenderer.d.ts.map +1 -0
  32. package/dist/react/core/detector.d.ts +17 -0
  33. package/dist/react/core/detector.d.ts.map +1 -0
  34. package/dist/react/core/parser.d.ts +40 -0
  35. package/dist/react/core/parser.d.ts.map +1 -0
  36. package/dist/react/core/types.d.ts +35 -0
  37. package/dist/react/core/types.d.ts.map +1 -0
  38. package/dist/react/hooks/useAiResponse.d.ts +19 -0
  39. package/dist/react/hooks/useAiResponse.d.ts.map +1 -0
  40. package/dist/react/index.d.ts +87 -0
  41. package/dist/react/index.d.ts.map +1 -0
  42. package/dist/react/index.esm.js +11 -0
  43. package/dist/react/index.esm.js.map +1 -0
  44. package/dist/react/index.js +11 -0
  45. package/dist/react/index.js.map +1 -0
  46. package/dist/react/providers/ai-mode.d.ts +10 -0
  47. package/dist/react/providers/ai-mode.d.ts.map +1 -0
  48. package/dist/react/providers/ai-overview.d.ts +10 -0
  49. package/dist/react/providers/ai-overview.d.ts.map +1 -0
  50. package/dist/react/providers/base-provider.d.ts +31 -0
  51. package/dist/react/providers/base-provider.d.ts.map +1 -0
  52. package/dist/react/providers/chatgpt.d.ts +10 -0
  53. package/dist/react/providers/chatgpt.d.ts.map +1 -0
  54. package/dist/react/providers/copilot.d.ts +10 -0
  55. package/dist/react/providers/copilot.d.ts.map +1 -0
  56. package/dist/react/providers/gemini.d.ts +10 -0
  57. package/dist/react/providers/gemini.d.ts.map +1 -0
  58. package/dist/react/providers/perplexity.d.ts +10 -0
  59. package/dist/react/providers/perplexity.d.ts.map +1 -0
  60. package/dist/react/react/components/AiResponseRenderer.d.ts +24 -0
  61. package/dist/react/react/components/AiResponseRenderer.d.ts.map +1 -0
  62. package/dist/react/react/components/IframeRenderer.d.ts +12 -0
  63. package/dist/react/react/components/IframeRenderer.d.ts.map +1 -0
  64. package/dist/react/react/hooks/useAiResponse.d.ts +19 -0
  65. package/dist/react/react/hooks/useAiResponse.d.ts.map +1 -0
  66. package/dist/react/react/index.d.ts +7 -0
  67. package/dist/react/react/index.d.ts.map +1 -0
  68. package/dist/react/styles/index.d.ts +1 -0
  69. package/dist/react/styles/index.d.ts.map +1 -0
  70. package/dist/react/utils/helpers.d.ts +28 -0
  71. package/dist/react/utils/helpers.d.ts.map +1 -0
  72. package/dist/styles/index.d.ts +1 -0
  73. package/dist/styles/index.d.ts.map +1 -0
  74. package/dist/utils/helpers.d.ts +28 -0
  75. package/dist/utils/helpers.d.ts.map +1 -0
  76. package/package.json +85 -0
package/README.md ADDED
@@ -0,0 +1,195 @@
1
+ # @cloro/response-parser
2
+
3
+ A powerful TypeScript library for parsing and rendering AI model responses from ChatGPT, Gemini, Perplexity, Copilot, and Google AI Overview/Mode.
4
+
5
+ ## Features
6
+
7
+ - 🤖 **Multi-Provider Support**: ChatGPT, Gemini, Perplexity, Copilot, AI Overview, AI Mode
8
+ - 🔍 **Auto-Detection**: Automatically detects the AI provider from response structure
9
+ - 🎨 **Theme Support**: Built-in dark and light mode styling
10
+ - ⚡ **React Components**: Ready-to-use React components for rendering
11
+ - 🔒 **Secure**: Sandboxed rendering with script sanitization
12
+ - 📦 **TypeScript**: Full TypeScript support with comprehensive types
13
+ - 🎯 **Lightweight**: No runtime dependencies for core parsing
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install @cloro/response-parser
19
+ # or
20
+ yarn add @cloro/response-parser
21
+ # or
22
+ pnpm add @cloro/response-parser
23
+ ```
24
+
25
+ ## Quick Start
26
+
27
+ ### Basic Parsing
28
+
29
+ ```typescript
30
+ import { parseAiResponse, detectProvider } from '@cloro/response-parser';
31
+
32
+ // Auto-detect provider and parse
33
+ const response = await fetchAIResponse();
34
+ const parsed = parseAiResponse(response, { theme: 'dark' });
35
+
36
+ console.log(parsed.provider); // 'CHATGPT' | 'GEMINI' | etc.
37
+ console.log(parsed.html); // Sanitized HTML ready for rendering
38
+ console.log(parsed.text); // Plain text version
39
+ ```
40
+
41
+ ### React Component
42
+
43
+ ```tsx
44
+ import { AiResponseRenderer } from '@cloro/response-parser/react';
45
+
46
+ function MyComponent() {
47
+ const [aiResponse, setAiResponse] = useState(null);
48
+
49
+ return (
50
+ <AiResponseRenderer
51
+ response={aiResponse}
52
+ theme="dark"
53
+ autoDetect
54
+ className="w-full h-96"
55
+ iframeProps={{
56
+ sandbox: 'allow-popups'
57
+ }}
58
+ onProviderDetected={(provider) => console.log('Detected:', provider)}
59
+ />
60
+ );
61
+ }
62
+ ```
63
+
64
+ ## API Reference
65
+
66
+ ### Core Functions
67
+
68
+ #### `parseAiResponse(response, options?)`
69
+
70
+ Parse an AI response with auto-detected provider.
71
+
72
+ **Options:**
73
+ - `theme`: `'light' | 'dark'` (default: `'dark'`)
74
+ - `baseUrl`: Base URL for relative links
75
+ - `sanitize`: Remove scripts (default: `true`)
76
+ - `includeStyles`: Inject provider-specific styles (default: `true`)
77
+
78
+ **Returns:** `ParsedResponse | null`
79
+
80
+ #### `detectProvider(response)`
81
+
82
+ Detect the AI provider from a response.
83
+
84
+ **Returns:** `AIProvider | null`
85
+
86
+ ### React Components
87
+
88
+ #### `<AiResponseRenderer />`
89
+
90
+ Main React component for rendering AI responses.
91
+
92
+ **Props:**
93
+ - `response`: The AI response object
94
+ - `theme`: Light or dark mode
95
+ - `autoDetect`: Auto-detect provider (default: `true`)
96
+ - `provider`: Explicitly specify provider
97
+ - `className`: CSS class for container
98
+ - `iframeProps`: Additional props for iframe
99
+ - `loadingComponent`: Custom loading component
100
+ - `errorComponent`: Custom error component
101
+ - `onProviderDetected`: Callback when provider is detected
102
+
103
+ ### Hooks
104
+
105
+ #### `useAiResponse(response, options?)`
106
+
107
+ React hook for parsing AI responses.
108
+
109
+ **Returns:**
110
+ - `parsed`: Parsed response object
111
+ - `provider`: Detected provider
112
+ - `isLoading`: Loading state
113
+ - `error`: Error object
114
+ - `html`: HTML string
115
+ - `text`: Plain text string
116
+ - `reparse`: Function to re-parse with new options
117
+
118
+ ## Supported Providers
119
+
120
+ | Provider | Status | Features |
121
+ |----------|--------|----------|
122
+ | ChatGPT | ✅ | Dark mode, sidebar hiding |
123
+ | Gemini | ✅ | Material Design overrides |
124
+ | Perplexity | ✅ | Color inversion for dark mode |
125
+ | Copilot | ✅ | UI element hiding |
126
+ | AI Overview | ✅ | WIZ data extraction |
127
+ | AI Mode | ✅ | Google UI hiding |
128
+
129
+ ## Examples
130
+
131
+ ### Manual Provider Specification
132
+
133
+ ```typescript
134
+ import { parseAiResponse } from 'ai-response-parser';
135
+
136
+ const parsed = parseAiResponse(response, {
137
+ provider: 'CHATGPT',
138
+ theme: 'dark'
139
+ });
140
+ ```
141
+
142
+ ### Advanced Usage with Custom Styles
143
+
144
+ ```tsx
145
+ <AiResponseRenderer
146
+ response={response}
147
+ theme="dark"
148
+ onError={(error) => console.error(error)}
149
+ onRenderComplete={(html) => console.log('Rendered', html)}
150
+ iframeProps={{
151
+ className: 'custom-iframe',
152
+ style: { border: 'none', borderRadius: '8px' }
153
+ }}
154
+ />
155
+ ```
156
+
157
+ ### Error Handling
158
+
159
+ ```tsx
160
+ const ErrorComponent = ({ error, retry }) => (
161
+ <div className="error">
162
+ <p>Failed to load: {error.message}</p>
163
+ <button onClick={retry}>Retry</button>
164
+ </div>
165
+ );
166
+
167
+ <AiResponseRenderer
168
+ response={response}
169
+ errorComponent={ErrorComponent}
170
+ />
171
+ ```
172
+
173
+ ## Development
174
+
175
+ ```bash
176
+ # Install dependencies
177
+ pnpm install
178
+
179
+ # Build
180
+ pnpm build
181
+
182
+ # Test
183
+ pnpm test
184
+
185
+ # Development mode
186
+ pnpm dev
187
+ ```
188
+
189
+ ## Contributing
190
+
191
+ Contributions are welcome! Please feel free to submit a Pull Request.
192
+
193
+ ## License
194
+
195
+ MIT © [Your Name](https://github.com/yourusername)
@@ -0,0 +1,17 @@
1
+ import { AIProvider, DetectedProvider } from './types';
2
+ export declare class ProviderDetector {
3
+ private static readonly PROVIDER_PATTERNS;
4
+ /**
5
+ * Detect the AI provider from the response
6
+ */
7
+ static detect(response: any): DetectedProvider | null;
8
+ /**
9
+ * Get all possible providers with their confidence scores
10
+ */
11
+ static getAllProviders(response: any): DetectedProvider[];
12
+ /**
13
+ * Validate if a detected provider is likely correct
14
+ */
15
+ static validate(response: any, provider: AIProvider): boolean;
16
+ }
17
+ //# sourceMappingURL=detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detector.d.ts","sourceRoot":"","sources":["../../src/core/detector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEvD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CA0DvC;IAEF;;OAEG;IACH,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,GAAG,gBAAgB,GAAG,IAAI;IA2CrD;;OAEG;IACH,MAAM,CAAC,eAAe,CAAC,QAAQ,EAAE,GAAG,GAAG,gBAAgB,EAAE;IA2BzD;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE,UAAU,GAAG,OAAO;CAI9D"}
@@ -0,0 +1,40 @@
1
+ import { AIProvider, ParsedResponse, ParseOptions } from './types';
2
+ export declare class AIResponseParser {
3
+ private providers;
4
+ constructor();
5
+ /**
6
+ * Parse an AI response with auto-detected provider
7
+ */
8
+ parse(response: any, options?: ParseOptions): ParsedResponse | null;
9
+ /**
10
+ * Parse with explicit provider specification
11
+ */
12
+ parseWithProvider(response: any, provider: AIProvider, options?: ParseOptions): ParsedResponse | null;
13
+ /**
14
+ * Detect the provider from a response
15
+ */
16
+ detectProvider(response: any): AIProvider | null;
17
+ /**
18
+ * Get all possible providers with confidence scores
19
+ */
20
+ detectAllProviders(response: any): Array<{
21
+ provider: AIProvider;
22
+ confidence: number;
23
+ }>;
24
+ /**
25
+ * Parse as generic HTML when no specific provider is detected
26
+ */
27
+ private parseGeneric;
28
+ /**
29
+ * Get list of supported providers
30
+ */
31
+ getSupportedProviders(): AIProvider[];
32
+ /**
33
+ * Register a custom provider
34
+ */
35
+ registerProvider(provider: AIProvider, instance: any): void;
36
+ }
37
+ export declare const parser: AIResponseParser;
38
+ export declare const parseAiResponse: (response: any, options?: ParseOptions) => ParsedResponse | null;
39
+ export declare const detectProvider: (response: any) => AIProvider | null;
40
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/core/parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AASnE,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,SAAS,CAAmC;;IAWpD;;OAEG;IACH,KAAK,CAAC,QAAQ,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,cAAc,GAAG,IAAI;IA4BnE;;OAEG;IACH,iBAAiB,CACf,QAAQ,EAAE,GAAG,EACb,QAAQ,EAAE,UAAU,EACpB,OAAO,CAAC,EAAE,YAAY,GACrB,cAAc,GAAG,IAAI;IAcxB;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,GAAG,GAAG,UAAU,GAAG,IAAI;IAKhD;;OAEG;IACH,kBAAkB,CAAC,QAAQ,EAAE,GAAG,GAAG,KAAK,CAAC;QAAE,QAAQ,EAAE,UAAU,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAItF;;OAEG;IACH,OAAO,CAAC,YAAY;IAuDpB;;OAEG;IACH,qBAAqB,IAAI,UAAU,EAAE;IAIrC;;OAEG;IACH,gBAAgB,CAAC,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,GAAG,IAAI;CAG5D;AAGD,eAAO,MAAM,MAAM,kBAAyB,CAAC;AAG7C,eAAO,MAAM,eAAe,GAAI,UAAU,GAAG,EAAE,UAAU,YAAY,0BACpC,CAAC;AAElC,eAAO,MAAM,cAAc,GAAI,UAAU,GAAG,sBACX,CAAC"}
@@ -0,0 +1,35 @@
1
+ export type AIProvider = 'CHATGPT' | 'GEMINI' | 'PERPLEXITY' | 'COPILOT' | 'AIOVERVIEW' | 'AIMODE';
2
+ export interface ParsedResponse {
3
+ provider: AIProvider;
4
+ html: string;
5
+ text?: string;
6
+ sources?: any[];
7
+ metadata?: Record<string, any>;
8
+ }
9
+ export interface ParseOptions {
10
+ theme?: 'light' | 'dark';
11
+ baseUrl?: string;
12
+ sanitize?: boolean;
13
+ includeStyles?: boolean;
14
+ }
15
+ export interface ProviderConfig {
16
+ name: AIProvider;
17
+ baseUrl: string;
18
+ defaultStyles: string;
19
+ }
20
+ export interface DetectedProvider {
21
+ provider: AIProvider;
22
+ confidence: number;
23
+ }
24
+ export interface StyleOptions {
25
+ theme?: 'light' | 'dark';
26
+ customCSS?: string;
27
+ hideUI?: boolean;
28
+ baseUrl?: string;
29
+ }
30
+ export type ContentExtraction = {
31
+ html?: string;
32
+ text?: string;
33
+ sources?: any[];
34
+ };
35
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAClB,SAAS,GACT,QAAQ,GACR,YAAY,GACZ,SAAS,GACT,YAAY,GACZ,QAAQ,CAAC;AAEb,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,UAAU,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,UAAU,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,UAAU,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC;CACjB,CAAC"}
@@ -0,0 +1,170 @@
1
+ type AIProvider = 'CHATGPT' | 'GEMINI' | 'PERPLEXITY' | 'COPILOT' | 'AIOVERVIEW' | 'AIMODE';
2
+ interface ParsedResponse {
3
+ provider: AIProvider;
4
+ html: string;
5
+ text?: string;
6
+ sources?: any[];
7
+ metadata?: Record<string, any>;
8
+ }
9
+ interface ParseOptions {
10
+ theme?: 'light' | 'dark';
11
+ baseUrl?: string;
12
+ sanitize?: boolean;
13
+ includeStyles?: boolean;
14
+ }
15
+ interface ProviderConfig {
16
+ name: AIProvider;
17
+ baseUrl: string;
18
+ defaultStyles: string;
19
+ }
20
+ interface DetectedProvider {
21
+ provider: AIProvider;
22
+ confidence: number;
23
+ }
24
+ interface StyleOptions {
25
+ theme?: 'light' | 'dark';
26
+ customCSS?: string;
27
+ hideUI?: boolean;
28
+ baseUrl?: string;
29
+ }
30
+ type ContentExtraction = {
31
+ html?: string;
32
+ text?: string;
33
+ sources?: any[];
34
+ };
35
+
36
+ declare class AIResponseParser {
37
+ private providers;
38
+ constructor();
39
+ /**
40
+ * Parse an AI response with auto-detected provider
41
+ */
42
+ parse(response: any, options?: ParseOptions): ParsedResponse | null;
43
+ /**
44
+ * Parse with explicit provider specification
45
+ */
46
+ parseWithProvider(response: any, provider: AIProvider, options?: ParseOptions): ParsedResponse | null;
47
+ /**
48
+ * Detect the provider from a response
49
+ */
50
+ detectProvider(response: any): AIProvider | null;
51
+ /**
52
+ * Get all possible providers with confidence scores
53
+ */
54
+ detectAllProviders(response: any): Array<{
55
+ provider: AIProvider;
56
+ confidence: number;
57
+ }>;
58
+ /**
59
+ * Parse as generic HTML when no specific provider is detected
60
+ */
61
+ private parseGeneric;
62
+ /**
63
+ * Get list of supported providers
64
+ */
65
+ getSupportedProviders(): AIProvider[];
66
+ /**
67
+ * Register a custom provider
68
+ */
69
+ registerProvider(provider: AIProvider, instance: any): void;
70
+ }
71
+ declare const parser: AIResponseParser;
72
+ declare const parseAiResponse: (response: any, options?: ParseOptions) => ParsedResponse | null;
73
+ declare const detectProvider: (response: any) => AIProvider | null;
74
+
75
+ declare class ProviderDetector {
76
+ private static readonly PROVIDER_PATTERNS;
77
+ /**
78
+ * Detect the AI provider from the response
79
+ */
80
+ static detect(response: any): DetectedProvider | null;
81
+ /**
82
+ * Get all possible providers with their confidence scores
83
+ */
84
+ static getAllProviders(response: any): DetectedProvider[];
85
+ /**
86
+ * Validate if a detected provider is likely correct
87
+ */
88
+ static validate(response: any, provider: AIProvider): boolean;
89
+ }
90
+
91
+ declare abstract class BaseProvider {
92
+ abstract readonly name: AIProvider;
93
+ abstract readonly baseUrl: string;
94
+ abstract readonly defaultStyles: string;
95
+ /**
96
+ * Parse an AI response and return structured content
97
+ */
98
+ abstract parse(response: any, options?: ParseOptions): ParsedResponse;
99
+ /**
100
+ * Extract content from the response object
101
+ */
102
+ abstract extractContent(response: any): ContentExtraction;
103
+ /**
104
+ * Inject provider-specific styles into HTML
105
+ */
106
+ injectStyles(html: string, options?: StyleOptions): string;
107
+ /**
108
+ * Sanitize HTML content
109
+ */
110
+ sanitizeHtml(html: string): string;
111
+ /**
112
+ * Check if content is a full HTML document
113
+ */
114
+ isFullDocument(html: string): boolean;
115
+ /**
116
+ * Wrap HTML fragment in a document
117
+ */
118
+ wrapFragment(html: string): string;
119
+ }
120
+
121
+ declare class ChatGPTProvider extends BaseProvider {
122
+ readonly name: AIProvider;
123
+ 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
+ extractContent(response: any): ContentExtraction;
126
+ parse(response: any, options?: ParseOptions): ParsedResponse;
127
+ }
128
+
129
+ declare class GeminiProvider extends BaseProvider {
130
+ readonly name: AIProvider;
131
+ 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
+ extractContent(response: any): ContentExtraction;
134
+ parse(response: any, options?: ParseOptions): ParsedResponse;
135
+ }
136
+
137
+ declare class PerplexityProvider extends BaseProvider {
138
+ readonly name: AIProvider;
139
+ 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
+ extractContent(response: any): ContentExtraction;
142
+ parse(response: any, options?: ParseOptions): ParsedResponse;
143
+ }
144
+
145
+ declare class CopilotProvider extends BaseProvider {
146
+ readonly name: AIProvider;
147
+ 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
+ extractContent(response: any): ContentExtraction;
150
+ parse(response: any, options?: ParseOptions): ParsedResponse;
151
+ }
152
+
153
+ declare class AIOverviewProvider extends BaseProvider {
154
+ readonly name: AIProvider;
155
+ 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
+ extractContent(response: any): ContentExtraction;
158
+ parse(response: any, options?: ParseOptions): ParsedResponse;
159
+ }
160
+
161
+ declare class AIModeProvider extends BaseProvider {
162
+ readonly name: AIProvider;
163
+ 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
+ extractContent(response: any): ContentExtraction;
166
+ parse(response: any, options?: ParseOptions): ParsedResponse;
167
+ }
168
+
169
+ export { AIModeProvider, AIOverviewProvider, AIResponseParser, BaseProvider, ChatGPTProvider, CopilotProvider, GeminiProvider, PerplexityProvider, ProviderDetector, detectProvider, parseAiResponse, parser };
170
+ export type { AIProvider, ContentExtraction, DetectedProvider, ParseOptions, ParsedResponse, ProviderConfig, StyleOptions };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC1F,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGnD,YAAY,EACV,UAAU,EACV,cAAc,EACd,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,YAAY,EACZ,iBAAiB,GAClB,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC"}
@@ -0,0 +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};
2
+ //# sourceMappingURL=index.esm.js.map