csv-charts-ai 1.9.0 → 1.10.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.
package/README.md CHANGED
@@ -10,22 +10,36 @@ AI-powered CSV analysis, chart generation, and interactive visualization. Built
10
10
  pnpm add csv-charts-ai
11
11
  ```
12
12
 
13
- All AI SDKs (`ai`, `zod`, `@ai-sdk/openai`, `@ai-sdk/anthropic`, `@ai-sdk/google`, `@ai-sdk/mistral`) and `read-excel-file` are bundled — no extra installs needed.
13
+ Then install **only the AI provider(s) you need**:
14
+
15
+ ```bash
16
+ # Pick one or more
17
+ pnpm add @ai-sdk/openai # OpenAI / OpenAI-compatible (Ollama, vLLM, LM Studio…)
18
+ pnpm add @ai-sdk/anthropic # Anthropic
19
+ pnpm add @ai-sdk/google # Google Generative AI
20
+ pnpm add @ai-sdk/mistral # Mistral
21
+ ```
22
+
23
+ Core dependencies (`ai`, `zod`, `read-excel-file`) are bundled. AI provider SDKs are **optional peer dependencies** — you only install what you use.
14
24
 
15
25
  **Optional peer dependencies** (only for React chart components): `react`, `recharts`, `lucide-react`.
16
26
 
17
27
  ## Quick Start
18
28
 
19
29
  ```ts
20
- import { parseCSV, analyzeData, suggestQuestions } from "csv-charts-ai";
30
+ import { registerProvider, fromSDK, parseCSV, analyzeData, suggestQuestions } from "csv-charts-ai";
31
+ import { createOpenAI } from "@ai-sdk/openai";
32
+
33
+ // 1. Register your provider(s) — once, at app startup
34
+ registerProvider("openai", fromSDK(createOpenAI));
21
35
 
22
- // 1. Parse CSV string into structured data
36
+ // 2. Parse CSV string into structured data
23
37
  const data = parseCSV(`name,age,city,salary
24
38
  Alice,30,Paris,75000
25
39
  Bob,25,London,62000
26
40
  Charlie,35,Berlin,88000`);
27
41
 
28
- // 2. Run full AI analysis (summary + anomalies + charts) in parallel
42
+ // 3. Run full AI analysis (summary + anomalies + charts) in parallel
29
43
  const result = await analyzeData({
30
44
  model: { apiKey: "sk-...", model: "gpt-4o" },
31
45
  data,
@@ -35,7 +49,7 @@ console.log(result.summary.keyInsights);
35
49
  console.log(`Found ${result.anomalies.length} anomalies`);
36
50
  console.log(`Generated ${result.charts.length} chart suggestions`);
37
51
 
38
- // 3. Suggest questions the user could ask
52
+ // 4. Suggest questions the user could ask
39
53
  const questions = await suggestQuestions({
40
54
  model: { apiKey: "sk-...", model: "gpt-4o" },
41
55
  data,
@@ -43,6 +57,56 @@ const questions = await suggestQuestions({
43
57
  questions.forEach(q => console.log(`[${q.category}] ${q.question}`));
44
58
  ```
45
59
 
60
+ ## Provider Setup
61
+
62
+ Register AI providers **once** at app startup, before calling any AI function. You only install and register the providers you need.
63
+
64
+ ### Using `@ai-sdk/*` packages
65
+
66
+ The `fromSDK()` helper wraps any `@ai-sdk/*` creator into the format the library expects:
67
+
68
+ ```ts
69
+ import { registerProvider, fromSDK } from "csv-charts-ai";
70
+ import { createOpenAI } from "@ai-sdk/openai";
71
+ import { createAnthropic } from "@ai-sdk/anthropic";
72
+ import { createGoogleGenerativeAI } from "@ai-sdk/google";
73
+ import { createMistral } from "@ai-sdk/mistral";
74
+
75
+ registerProvider("openai", fromSDK(createOpenAI));
76
+ registerProvider("anthropic", fromSDK(createAnthropic));
77
+ registerProvider("google", fromSDK(createGoogleGenerativeAI));
78
+ registerProvider("mistral", fromSDK(createMistral));
79
+ ```
80
+
81
+ ### Custom / self-hosted providers
82
+
83
+ For full control, pass a `ProviderFactory` directly — a function that receives `{ apiKey, model, baseURL?, headers? }` and returns a `LanguageModel`:
84
+
85
+ ```ts
86
+ import { registerProvider } from "csv-charts-ai";
87
+
88
+ registerProvider("my-llm", (config) => {
89
+ return myCustomSDK.createModel(config.apiKey, config.model);
90
+ });
91
+ ```
92
+
93
+ ### Batch registration
94
+
95
+ ```ts
96
+ import { registerProviders, fromSDK } from "csv-charts-ai";
97
+ import { createOpenAI } from "@ai-sdk/openai";
98
+ import { createAnthropic } from "@ai-sdk/anthropic";
99
+
100
+ registerProviders({
101
+ openai: fromSDK(createOpenAI),
102
+ anthropic: fromSDK(createAnthropic),
103
+ });
104
+ ```
105
+
106
+ ### Aliases
107
+
108
+ npm package names are resolved automatically — `"@ai-sdk/openai"` and `"openai"` map to the same slot. So `createModel({ provider: "openai" })` and `createAppModel({ providerNpm: "@ai-sdk/openai" })` both work after a single registration.
109
+
46
110
  ## CSV Parsing
47
111
 
48
112
  Parse CSV strings into the `TabularData` format with automatic delimiter detection and column type inference.
@@ -105,13 +169,13 @@ All AI functions accept either a simple config object or a pre-built `LanguageMo
105
169
  ```ts
106
170
  import { suggestCharts } from "csv-charts-ai";
107
171
 
108
- // Simple — OpenAI
172
+ // Simple — OpenAI (provider must be registered, see Provider Setup)
109
173
  const charts = await suggestCharts({
110
174
  model: { apiKey: "sk-...", model: "gpt-4o" },
111
175
  data,
112
176
  });
113
177
 
114
- // Custom endpoint — Ollama / vLLM / LM Studio
178
+ // Custom endpoint — Ollama / vLLM / LM Studio (uses the "openai" provider)
115
179
  const charts = await suggestCharts({
116
180
  model: { apiKey: "", model: "llama3", baseURL: "http://localhost:11434/v1" },
117
181
  data,
@@ -123,8 +187,9 @@ const charts = await suggestCharts({
123
187
  data,
124
188
  });
125
189
 
126
- // Advanced — any LanguageModel instance
127
- import { anthropic } from "@ai-sdk/anthropic";
190
+ // Advanced — any LanguageModel instance (no registration needed)
191
+ import { createAnthropic } from "@ai-sdk/anthropic";
192
+ const anthropic = createAnthropic({ apiKey: "sk-ant-..." });
128
193
  const charts = await suggestCharts({
129
194
  model: anthropic("claude-sonnet-4-20250514"),
130
195
  data,
@@ -349,9 +414,12 @@ You can also pass `className` to any component to add classes alongside the buil
349
414
  The core entry point (`csv-charts-ai`) works without React — use it in Node.js scripts, APIs, or CLI tools:
350
415
 
351
416
  ```ts
352
- import { parseCSV, analyzeData } from "csv-charts-ai";
417
+ import { registerProvider, fromSDK, parseCSV, analyzeData } from "csv-charts-ai";
418
+ import { createOpenAI } from "@ai-sdk/openai";
353
419
  import { readFileSync } from "fs";
354
420
 
421
+ registerProvider("openai", fromSDK(createOpenAI));
422
+
355
423
  const csv = readFileSync("sales.csv", "utf-8");
356
424
  const data = parseCSV(csv);
357
425
 
@@ -387,6 +455,17 @@ console.log(result.summary.keyInsights);
387
455
  | `suggestQuestions(options)` | Suggest interesting questions to ask about the data |
388
456
  | `analyzeData(options)` | Full pipeline: summary + anomalies + charts in parallel |
389
457
 
458
+ ## Provider Registry Reference
459
+
460
+ | Export | Description |
461
+ |--------|-------------|
462
+ | `registerProvider(name, factory)` | Register a provider by name |
463
+ | `registerProviders(map)` | Register multiple providers at once |
464
+ | `fromSDK(creator)` | Wrap an `@ai-sdk/*` creator into a `ProviderFactory` |
465
+ | `getProvider(name)` | Get a registered provider (or `undefined`) |
466
+ | `hasProvider(name)` | Check if a provider is registered |
467
+ | `clearProviders()` | Remove all registered providers (for testing) |
468
+
390
469
  ## Utilities Reference
391
470
 
392
471
  | Export | Description |
@@ -443,16 +522,17 @@ Match modes: `"index"` (positional), `"key"` (by column value), `"content"` (ful
443
522
 
444
523
  ## Provider Support
445
524
 
446
- All provider SDKs are bundled no extra installs needed.
447
-
448
- | Provider | Config |
449
- |----------|--------|
450
- | OpenAI | `{ apiKey, model }` |
451
- | Anthropic | `{ provider: "anthropic", apiKey, model }` |
452
- | Google | `{ provider: "google", apiKey, model }` |
453
- | Mistral | `{ provider: "mistral", apiKey, model }` |
454
- | Ollama / vLLM / LM Studio | `{ apiKey: "", model, baseURL }` |
455
- | Any LanguageModel | Pass instance directly |
525
+ Install only the provider(s) you need and register them at startup (see [Provider Setup](#provider-setup)).
526
+
527
+ | Provider | Install | Config |
528
+ |----------|---------|--------|
529
+ | OpenAI | `@ai-sdk/openai` | `{ apiKey, model }` |
530
+ | Anthropic | `@ai-sdk/anthropic` | `{ provider: "anthropic", apiKey, model }` |
531
+ | Google | `@ai-sdk/google` | `{ provider: "google", apiKey, model }` |
532
+ | Mistral | `@ai-sdk/mistral` | `{ provider: "mistral", apiKey, model }` |
533
+ | Ollama / vLLM / LM Studio | `@ai-sdk/openai` | `{ apiKey: "", model, baseURL }` |
534
+ | Custom provider | | `registerProvider("name", factory)` |
535
+ | Any LanguageModel | — | Pass instance directly |
456
536
 
457
537
  ## License
458
538
 
package/dist/index.d.ts CHANGED
@@ -1,10 +1,85 @@
1
+ import { LanguageModel } from 'ai';
1
2
  import { T as TabularData, C as ChartConfig } from './constants-hUsrIT8W.js';
2
3
  export { A as AggregationType, a as COLORS, b as ChartDataPoint, c as ChartTheme, d as ChartType, P as ProcessedChartResult, S as SortOrder, e as defaultDarkTheme, f as defaultLightTheme, p as processChartData, g as processChartDataMultiSeries } from './constants-hUsrIT8W.js';
3
- import { LanguageModel } from 'ai';
4
4
  import { z } from 'zod';
5
5
 
6
6
  declare const VERSION: string;
7
7
 
8
+ /** Configuration passed to a provider factory when creating a model. */
9
+ interface ProviderConfig {
10
+ apiKey: string;
11
+ model: string;
12
+ baseURL?: string;
13
+ headers?: Record<string, string>;
14
+ }
15
+ /** A function that creates a LanguageModel from configuration. */
16
+ type ProviderFactory = (config: ProviderConfig) => LanguageModel;
17
+ /**
18
+ * Register a provider factory under a given name.
19
+ *
20
+ * The name can be a simple identifier (`"openai"`) or an npm package name
21
+ * (`"@ai-sdk/openai"`) — aliases are resolved automatically so both map
22
+ * to the same slot.
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * import { registerProvider, fromSDK } from "csv-charts-ai";
27
+ * import { createOpenAI } from "@ai-sdk/openai";
28
+ * import { createAnthropic } from "@ai-sdk/anthropic";
29
+ *
30
+ * registerProvider("openai", fromSDK(createOpenAI));
31
+ * registerProvider("anthropic", fromSDK(createAnthropic));
32
+ *
33
+ * // Custom provider with full control
34
+ * registerProvider("my-llm", (config) => {
35
+ * return myCustomSDK.createModel(config.apiKey, config.model);
36
+ * });
37
+ * ```
38
+ */
39
+ declare function registerProvider(name: string, factory: ProviderFactory): void;
40
+ /**
41
+ * Register multiple providers at once.
42
+ *
43
+ * @example
44
+ * ```ts
45
+ * registerProviders({
46
+ * openai: fromSDK(createOpenAI),
47
+ * anthropic: fromSDK(createAnthropic),
48
+ * google: fromSDK(createGoogleGenerativeAI),
49
+ * });
50
+ * ```
51
+ */
52
+ declare function registerProviders(providers: Record<string, ProviderFactory>): void;
53
+ /**
54
+ * Wrap an AI SDK provider creator into a {@link ProviderFactory}.
55
+ *
56
+ * All `@ai-sdk/*` packages export a creator following the pattern:
57
+ * ```
58
+ * createXxx(options) → provider(modelName) → LanguageModel
59
+ * ```
60
+ *
61
+ * This helper adapts that two-step pattern into a single-step
62
+ * `ProviderFactory`.
63
+ *
64
+ * @example
65
+ * ```ts
66
+ * import { createOpenAI } from "@ai-sdk/openai";
67
+ * import { fromSDK, registerProvider } from "csv-charts-ai";
68
+ *
69
+ * registerProvider("openai", fromSDK(createOpenAI));
70
+ * ```
71
+ */
72
+ declare function fromSDK(creator: (options: any) => any): ProviderFactory;
73
+ /** Get a provider by name, or `undefined` if not registered. */
74
+ declare function getProvider(name: string): ProviderFactory | undefined;
75
+ /** Check whether a provider is registered. */
76
+ declare function hasProvider(name: string): boolean;
77
+ /**
78
+ * Remove all registered providers.
79
+ * Useful for testing — not intended for production use.
80
+ */
81
+ declare function clearProviders(): void;
82
+
8
83
  interface ParseCSVOptions {
9
84
  /** Column delimiter. Auto-detected if omitted (supports , ; \t |). */
10
85
  delimiter?: string;
@@ -107,12 +182,7 @@ declare const AIConfigSchema: z.ZodObject<{
107
182
  apiKey: z.ZodString;
108
183
  model: z.ZodString;
109
184
  baseURL: z.ZodOptional<z.ZodString>;
110
- provider: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
111
- openai: "openai";
112
- anthropic: "anthropic";
113
- google: "google";
114
- mistral: "mistral";
115
- }>>>;
185
+ provider: z.ZodDefault<z.ZodOptional<z.ZodString>>;
116
186
  }, z.core.$strip>;
117
187
  type AIConfig = z.infer<typeof AIConfigSchema>;
118
188
  /** Zod schema for TabularData validation */
@@ -146,6 +216,8 @@ interface AppModelConfig {
146
216
  customEndpoint?: string;
147
217
  /** Custom model name (takes priority over model) */
148
218
  customModel?: string;
219
+ /** Custom headers to pass to the provider (e.g. Anthropic browser access header) */
220
+ headers?: Record<string, string>;
149
221
  }
150
222
  /** Model input: either a simple config object, an app config, or a pre-built LanguageModel */
151
223
  type ModelInput = AIConfig | AppModelConfig | LanguageModel;
@@ -172,20 +244,26 @@ declare function summarizeTabularData(data: TabularData): string;
172
244
  declare function generateDataSummary(data: TabularData): string;
173
245
  /**
174
246
  * Create a LanguageModel from an AIConfig.
175
- * All provider SDKs are bundled no dynamic imports needed.
247
+ * The provider must be registered beforehand via {@link registerProvider}.
176
248
  *
177
249
  * @example
178
250
  * ```ts
251
+ * import { registerProvider, fromSDK, createModel } from "csv-charts-ai";
252
+ * import { createOpenAI } from "@ai-sdk/openai";
253
+ *
254
+ * registerProvider("openai", fromSDK(createOpenAI));
255
+ *
179
256
  * const model = createModel({ apiKey: "sk-...", model: "gpt-4o" });
180
- * const charts1 = await suggestCharts({ model, data, dataSummary });
181
- * const charts2 = await suggestCustomChart({ model, data, dataSummary, prompt: "..." });
182
257
  * ```
183
258
  */
184
259
  declare function createModel(config: AIConfig): LanguageModel;
185
260
  /**
186
261
  * Create a LanguageModel from an AppModelConfig.
187
- * Handles multi-provider apps with providerNpm-based routing,
188
- * custom endpoints, and Anthropic browser headers.
262
+ * Handles multi-provider apps with providerNpm-based routing and
263
+ * custom endpoints.
264
+ *
265
+ * The provider identified by `providerNpm` (or `"openai"` by default)
266
+ * must be registered beforehand via {@link registerProvider}.
189
267
  *
190
268
  * @example
191
269
  * ```ts
@@ -512,4 +590,4 @@ interface SuggestedQuestion {
512
590
  */
513
591
  declare function suggestQuestions(options: SuggestQuestionsOptions): Promise<SuggestedQuestion[]>;
514
592
 
515
- export { type AIConfig, AIConfigSchema, type AnalysisResult, type AnalyzeOptions, type AnomalyResult, type AppModelConfig, type AskAboutDataOptions, ChartConfig, type DataSummaryResult, type DetectAnomaliesOptions, type DiffCounts, type DiffOptions, type DiffResult, type DiffRow, type DiffStatus, type MatchMode, type ModelInput, type ParseCSVOptions, type ParseXLSXOptions, type RepairChartOptions, type StreamAskAboutDataOptions, type SuggestChartsOptions, type SuggestCustomChartOptions, type SuggestQuestionsOptions, type SuggestedQuestion, type SummarizeDataOptions, TabularData, TabularDataSchema, VERSION, analyzeData, askAboutData, computeDiff, convertXLSXRows, createAppModel, createModel, detectAnomalies, generateDataSummary, getAIErrorMessage, parseCSV, parseXLSX, repairChart, resolveModel, streamAskAboutData, suggestCharts, suggestCustomChart, suggestQuestions, summarizeData, summarizeTabularData };
593
+ export { type AIConfig, AIConfigSchema, type AnalysisResult, type AnalyzeOptions, type AnomalyResult, type AppModelConfig, type AskAboutDataOptions, ChartConfig, type DataSummaryResult, type DetectAnomaliesOptions, type DiffCounts, type DiffOptions, type DiffResult, type DiffRow, type DiffStatus, type MatchMode, type ModelInput, type ParseCSVOptions, type ParseXLSXOptions, type ProviderConfig, type ProviderFactory, type RepairChartOptions, type StreamAskAboutDataOptions, type SuggestChartsOptions, type SuggestCustomChartOptions, type SuggestQuestionsOptions, type SuggestedQuestion, type SummarizeDataOptions, TabularData, TabularDataSchema, VERSION, analyzeData, askAboutData, clearProviders, computeDiff, convertXLSXRows, createAppModel, createModel, detectAnomalies, fromSDK, generateDataSummary, getAIErrorMessage, getProvider, hasProvider, parseCSV, parseXLSX, registerProvider, registerProviders, repairChart, resolveModel, streamAskAboutData, suggestCharts, suggestCustomChart, suggestQuestions, summarizeData, summarizeTabularData };
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // package.json
2
2
  var package_default = {
3
3
  name: "csv-charts-ai",
4
- version: "1.9.0",
4
+ version: "1.10.0",
5
5
  description: "AI-powered CSV analysis, chart generation, and interactive visualization. Parse CSV, detect anomalies, suggest charts, and ask questions about your data using any LLM provider.",
6
6
  type: "module",
7
7
  license: "MIT",
@@ -54,7 +54,11 @@ var package_default = {
54
54
  peerDependencies: {
55
55
  react: "^18.0.0 || ^19.0.0",
56
56
  recharts: "^3.0.0",
57
- "lucide-react": ">=0.400.0"
57
+ "lucide-react": ">=0.400.0",
58
+ "@ai-sdk/openai": "^3.0.0",
59
+ "@ai-sdk/anthropic": "^3.0.0",
60
+ "@ai-sdk/google": "^3.0.0",
61
+ "@ai-sdk/mistral": "^3.0.0"
58
62
  },
59
63
  peerDependenciesMeta: {
60
64
  react: {
@@ -65,15 +69,23 @@ var package_default = {
65
69
  },
66
70
  "lucide-react": {
67
71
  optional: true
72
+ },
73
+ "@ai-sdk/openai": {
74
+ optional: true
75
+ },
76
+ "@ai-sdk/anthropic": {
77
+ optional: true
78
+ },
79
+ "@ai-sdk/google": {
80
+ optional: true
81
+ },
82
+ "@ai-sdk/mistral": {
83
+ optional: true
68
84
  }
69
85
  },
70
86
  dependencies: {
71
87
  ai: "^6.0.134",
72
88
  zod: "^4.1.13",
73
- "@ai-sdk/openai": "^3.0.47",
74
- "@ai-sdk/anthropic": "^3.0.63",
75
- "@ai-sdk/google": "^3.0.52",
76
- "@ai-sdk/mistral": "^3.0.27",
77
89
  "read-excel-file": "^7.0.2"
78
90
  },
79
91
  devDependencies: {
@@ -94,6 +106,72 @@ var package_default = {
94
106
  // src/version.ts
95
107
  var VERSION = package_default.version;
96
108
 
109
+ // src/providers.ts
110
+ var registry = /* @__PURE__ */ new Map();
111
+ var ALIASES = {
112
+ "@ai-sdk/openai": "openai",
113
+ "@ai-sdk/anthropic": "anthropic",
114
+ "@ai-sdk/google": "google",
115
+ "@ai-sdk/mistral": "mistral"
116
+ };
117
+ function resolveAlias(name) {
118
+ return ALIASES[name] ?? name;
119
+ }
120
+ function registerProvider(name, factory) {
121
+ const resolved = resolveAlias(name);
122
+ registry.set(resolved, factory);
123
+ }
124
+ function registerProviders(providers) {
125
+ for (const [name, factory] of Object.entries(providers)) {
126
+ registerProvider(name, factory);
127
+ }
128
+ }
129
+ function fromSDK(creator) {
130
+ return (config) => {
131
+ const provider = creator({
132
+ apiKey: config.apiKey,
133
+ ...config.baseURL && { baseURL: config.baseURL },
134
+ ...config.headers && { headers: config.headers }
135
+ });
136
+ return provider(config.model);
137
+ };
138
+ }
139
+ function getProvider(name) {
140
+ return registry.get(resolveAlias(name));
141
+ }
142
+ function hasProvider(name) {
143
+ return registry.has(resolveAlias(name));
144
+ }
145
+ function clearProviders() {
146
+ registry.clear();
147
+ }
148
+ function requireProvider(name) {
149
+ const resolved = resolveAlias(name);
150
+ const factory = registry.get(resolved);
151
+ if (!factory) {
152
+ const npmHint = {
153
+ openai: "@ai-sdk/openai",
154
+ anthropic: "@ai-sdk/anthropic",
155
+ google: "@ai-sdk/google",
156
+ mistral: "@ai-sdk/mistral"
157
+ };
158
+ const pkg = npmHint[resolved];
159
+ const example = pkg ? ` import { registerProvider, fromSDK } from "csv-charts-ai";
160
+ import { create... } from "${pkg}";
161
+ registerProvider("${resolved}", fromSDK(create...));` : ` import { registerProvider } from "csv-charts-ai";
162
+ registerProvider("${resolved}", (config) => /* your LanguageModel */);`;
163
+ throw new Error(
164
+ `Provider "${resolved}" is not registered.
165
+
166
+ Register it before calling AI functions:
167
+
168
+ ${example}
169
+ `
170
+ );
171
+ }
172
+ return factory;
173
+ }
174
+
97
175
  // src/csv-parser.ts
98
176
  function parseCSV(csv, options = {}) {
99
177
  const { hasHeader = true, skipEmpty = true } = options;
@@ -592,10 +670,6 @@ var defaultLightTheme = {
592
670
  // src/ai.ts
593
671
  import { generateObject } from "ai";
594
672
  import { z } from "zod";
595
- import { createOpenAI } from "@ai-sdk/openai";
596
- import { createAnthropic } from "@ai-sdk/anthropic";
597
- import { createGoogleGenerativeAI } from "@ai-sdk/google";
598
- import { createMistral } from "@ai-sdk/mistral";
599
673
  var AIConfigSchema = z.object({
600
674
  /** API key for authentication */
601
675
  apiKey: z.string(),
@@ -603,8 +677,8 @@ var AIConfigSchema = z.object({
603
677
  model: z.string(),
604
678
  /** Custom base URL for non-OpenAI providers (Ollama, vLLM, Mistral, etc.) */
605
679
  baseURL: z.string().optional(),
606
- /** Provider hintused to dynamically load the right SDK. Defaults to "openai". */
607
- provider: z.enum(["openai", "anthropic", "google", "mistral"]).optional().default("openai")
680
+ /** Provider namemust match a registered provider. Defaults to "openai". */
681
+ provider: z.string().optional().default("openai")
608
682
  });
609
683
  var TabularDataSchema = z.object({
610
684
  headers: z.array(z.string()).min(1, "Data must have at least one column"),
@@ -737,64 +811,32 @@ function isLanguageModel(input) {
737
811
  }
738
812
  function createModel(config) {
739
813
  const parsed = AIConfigSchema.parse(config);
740
- if (parsed.baseURL || parsed.provider === "openai") {
741
- const openai = createOpenAI({
742
- apiKey: parsed.apiKey,
743
- ...parsed.baseURL && { baseURL: parsed.baseURL }
744
- });
745
- return openai(parsed.model);
746
- }
747
- switch (parsed.provider) {
748
- case "anthropic": {
749
- return createAnthropic({ apiKey: parsed.apiKey })(parsed.model);
750
- }
751
- case "google": {
752
- return createGoogleGenerativeAI({ apiKey: parsed.apiKey })(parsed.model);
753
- }
754
- case "mistral": {
755
- return createMistral({ apiKey: parsed.apiKey })(parsed.model);
756
- }
757
- default: {
758
- const openai = createOpenAI({
759
- apiKey: parsed.apiKey
760
- });
761
- return openai(parsed.model);
762
- }
763
- }
814
+ const factory = requireProvider(parsed.provider);
815
+ return factory({
816
+ apiKey: parsed.apiKey,
817
+ model: parsed.model,
818
+ ...parsed.baseURL && { baseURL: parsed.baseURL }
819
+ });
764
820
  }
765
821
  function createAppModel(config) {
766
822
  const modelName = config.customModel ?? config.model ?? "";
767
823
  if (config.customEndpoint) {
768
- const openai = createOpenAI({
824
+ const factory2 = requireProvider("openai");
825
+ return factory2({
769
826
  apiKey: config.apiKey || "",
770
- baseURL: config.customEndpoint
827
+ model: config.customModel ?? modelName,
828
+ baseURL: config.customEndpoint,
829
+ ...config.headers && { headers: config.headers }
771
830
  });
772
- return openai(config.customModel ?? modelName);
773
- }
774
- switch (config.providerNpm) {
775
- case "@ai-sdk/anthropic": {
776
- const anthropic = createAnthropic({
777
- apiKey: config.apiKey,
778
- headers: { "anthropic-dangerous-direct-browser-access": "true" }
779
- });
780
- return anthropic(modelName);
781
- }
782
- case "@ai-sdk/google": {
783
- const google = createGoogleGenerativeAI({ apiKey: config.apiKey });
784
- return google(modelName);
785
- }
786
- case "@ai-sdk/mistral": {
787
- const mistral = createMistral({ apiKey: config.apiKey });
788
- return mistral(modelName);
789
- }
790
- default: {
791
- const openai = createOpenAI({
792
- apiKey: config.apiKey,
793
- baseURL: config.providerApi
794
- });
795
- return openai(modelName);
796
- }
797
831
  }
832
+ const providerName = config.providerNpm ?? "openai";
833
+ const factory = requireProvider(providerName);
834
+ return factory({
835
+ apiKey: config.apiKey,
836
+ model: modelName,
837
+ ...config.providerApi && { baseURL: config.providerApi },
838
+ ...config.headers && { headers: config.headers }
839
+ });
798
840
  }
799
841
  function isAppModelConfig(input) {
800
842
  if (typeof input !== "object" || input === null) return false;
@@ -1354,6 +1396,7 @@ export {
1354
1396
  VERSION,
1355
1397
  analyzeData,
1356
1398
  askAboutData,
1399
+ clearProviders,
1357
1400
  computeDiff,
1358
1401
  convertXLSXRows,
1359
1402
  createAppModel,
@@ -1361,12 +1404,17 @@ export {
1361
1404
  defaultDarkTheme,
1362
1405
  defaultLightTheme,
1363
1406
  detectAnomalies,
1407
+ fromSDK,
1364
1408
  generateDataSummary,
1365
1409
  getAIErrorMessage,
1410
+ getProvider,
1411
+ hasProvider,
1366
1412
  parseCSV,
1367
1413
  parseXLSX,
1368
1414
  processChartData,
1369
1415
  processChartDataMultiSeries,
1416
+ registerProvider,
1417
+ registerProviders,
1370
1418
  repairChart,
1371
1419
  resolveModel,
1372
1420
  streamAskAboutData,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../package.json","../src/version.ts","../src/csv-parser.ts","../src/xlsx-parser.ts","../src/processChartData.ts","../src/constants.ts","../src/types.ts","../src/ai.ts","../src/csv-diff.ts","../src/analyze.ts"],"sourcesContent":["{\n \"name\": \"csv-charts-ai\",\n \"version\": \"1.9.0\",\n \"description\": \"AI-powered CSV analysis, chart generation, and interactive visualization. Parse CSV, detect anomalies, suggest charts, and ask questions about your data using any LLM provider.\",\n \"type\": \"module\",\n \"license\": \"MIT\",\n \"author\": \"maxgfr\",\n \"homepage\": \"https://github.com/maxgfr/csv-ai-analyzer/tree/main/packages/csv-charts-ai#readme\",\n \"bugs\": {\n \"url\": \"https://github.com/maxgfr/csv-ai-analyzer/issues\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/maxgfr/csv-ai-analyzer\",\n \"directory\": \"packages/csv-charts-ai\"\n },\n \"keywords\": [\n \"csv\",\n \"ai\",\n \"charts\",\n \"data-analysis\",\n \"visualization\",\n \"llm\",\n \"openai\",\n \"anthropic\",\n \"recharts\",\n \"tabular-data\",\n \"anomaly-detection\",\n \"chart-generation\"\n ],\n \"main\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"import\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\"\n },\n \"./charts\": {\n \"import\": \"./dist/charts.js\",\n \"types\": \"./dist/charts.d.ts\"\n }\n },\n \"files\": [\n \"dist\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"test:coverage\": \"vitest run --coverage\"\n },\n \"peerDependencies\": {\n \"react\": \"^18.0.0 || ^19.0.0\",\n \"recharts\": \"^3.0.0\",\n \"lucide-react\": \">=0.400.0\"\n },\n \"peerDependenciesMeta\": {\n \"react\": {\n \"optional\": true\n },\n \"recharts\": {\n \"optional\": true\n },\n \"lucide-react\": {\n \"optional\": true\n }\n },\n \"dependencies\": {\n \"ai\": \"^6.0.134\",\n \"zod\": \"^4.1.13\",\n \"@ai-sdk/openai\": \"^3.0.47\",\n \"@ai-sdk/anthropic\": \"^3.0.63\",\n \"@ai-sdk/google\": \"^3.0.52\",\n \"@ai-sdk/mistral\": \"^3.0.27\",\n \"read-excel-file\": \"^7.0.2\"\n },\n \"devDependencies\": {\n \"@types/react\": \"^19.2.7\",\n \"@vitest/coverage-v8\": \"^4.1.0\",\n \"lucide-react\": \"^0.556.0\",\n \"react\": \"^19.2.4\",\n \"recharts\": \"^3.5.1\",\n \"tsup\": \"^8.5.0\",\n \"typescript\": \"^5.9.3\",\n \"vitest\": \"^4.1.0\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n }\n}\n","// Read version from package.json at build time (inlined by tsup)\nimport pkg from \"../package.json\" with { type: \"json\" };\nexport const VERSION: string = pkg.version;\n","import type { TabularData } from \"./types\";\n\nexport interface ParseCSVOptions {\n /** Column delimiter. Auto-detected if omitted (supports , ; \\t |). */\n delimiter?: string;\n /** Whether the first row is a header row (default: true). */\n hasHeader?: boolean;\n /** Skip empty lines (default: true). */\n skipEmpty?: boolean;\n}\n\n/**\n * Parse a CSV string into TabularData with automatic delimiter detection\n * and column type inference.\n *\n * Handles quoted fields (RFC 4180), escaped quotes, and mixed line endings.\n *\n * @example\n * ```ts\n * import { parseCSV } from \"csv-charts-ai\";\n *\n * const data = parseCSV(`name,age,city\n * Alice,30,\"New York\"\n * Bob,25,Paris`);\n *\n * console.log(data.headers); // [\"name\", \"age\", \"city\"]\n * console.log(data.rowCount); // 2\n * console.log(data.columns); // [{ name: \"name\", type: \"string\", ... }, ...]\n * ```\n *\n * @example\n * ```ts\n * // Auto-detects semicolon delimiter\n * const data = parseCSV(\"nom;age;ville\\nAlice;30;Paris\");\n *\n * // Explicit delimiter\n * const data = parseCSV(tsv, { delimiter: \"\\t\" });\n *\n * // No header row\n * const data = parseCSV(raw, { hasHeader: false });\n * ```\n *\n * For very complex CSV files (multi-line quoted fields with nested newlines,\n * exotic encodings), consider using PapaParse and passing the result as\n * TabularData directly to the AI functions.\n */\nexport function parseCSV(\n csv: string,\n options: ParseCSVOptions = {},\n): TabularData {\n const { hasHeader = true, skipEmpty = true } = options;\n\n // Normalize line endings and strip BOM\n const normalized = csv\n .replace(/^\\uFEFF/, \"\")\n .replace(/\\r\\n/g, \"\\n\")\n .replace(/\\r/g, \"\\n\")\n .trim();\n\n if (normalized.length === 0) {\n return { headers: [], rows: [], columns: [], rowCount: 0 };\n }\n\n const delimiter = options.delimiter ?? detectDelimiter(normalized);\n const allRows = parseRows(normalized, delimiter, skipEmpty);\n\n if (allRows.length === 0) {\n return { headers: [], rows: [], columns: [], rowCount: 0 };\n }\n\n // Normalize row lengths to match the first row\n const expectedCols = allRows[0]!.length;\n const normalizedRows = allRows.map((row) => {\n if (row.length < expectedCols) {\n return [...row, ...Array<string>(expectedCols - row.length).fill(\"\")];\n }\n return row.slice(0, expectedCols);\n });\n\n const headers = hasHeader\n ? normalizedRows[0]!\n : normalizedRows[0]!.map((_, i) => `Column ${i + 1}`);\n const dataRows = hasHeader ? normalizedRows.slice(1) : normalizedRows;\n\n const columns = headers.map((name, index) => ({\n name: name.trim(),\n type: inferColumnType(dataRows, index),\n index,\n }));\n\n return {\n headers: headers.map((h) => h.trim()),\n rows: dataRows,\n columns,\n rowCount: dataRows.length,\n };\n}\n\n// ============ Delimiter Detection ============\n\nfunction detectDelimiter(csv: string): string {\n const firstLines = csv.split(\"\\n\").slice(0, 5);\n const candidates: Record<string, number[]> = {\n \",\": [],\n \";\": [],\n \"\\t\": [],\n \"|\": [],\n };\n\n for (const line of firstLines) {\n let inQuotes = false;\n const counts: Record<string, number> = { \",\": 0, \";\": 0, \"\\t\": 0, \"|\": 0 };\n for (const char of line) {\n if (char === '\"') {\n inQuotes = !inQuotes;\n } else if (!inQuotes && char in counts) {\n counts[char]!++;\n }\n }\n for (const [delim, count] of Object.entries(counts)) {\n candidates[delim]!.push(count);\n }\n }\n\n // Best delimiter: consistent count across lines AND highest count\n let best = \",\";\n let bestScore = -1;\n\n for (const [delim, counts] of Object.entries(candidates)) {\n if (counts.length === 0 || counts[0] === 0) continue;\n\n const allSame = counts.every((c) => c === counts[0]);\n const avgCount = counts.reduce((a, b) => a + b, 0) / counts.length;\n // Prefer consistency, then count\n const score = (allSame ? 1000 : 0) + avgCount;\n\n if (score > bestScore) {\n bestScore = score;\n best = delim;\n }\n }\n\n return best;\n}\n\n// ============ Row Parsing (RFC 4180) ============\n\nfunction parseRows(\n csv: string,\n delimiter: string,\n skipEmpty: boolean,\n): string[][] {\n const rows: string[][] = [];\n let current: string[] = [];\n let field = \"\";\n let inQuotes = false;\n\n for (let i = 0; i < csv.length; i++) {\n const char = csv[i]!;\n\n if (inQuotes) {\n if (char === '\"') {\n if (i + 1 < csv.length && csv[i + 1] === '\"') {\n field += '\"';\n i++; // skip escaped quote\n } else {\n inQuotes = false;\n }\n } else {\n field += char;\n }\n } else {\n if (char === '\"') {\n inQuotes = true;\n } else if (char === delimiter) {\n current.push(field);\n field = \"\";\n } else if (char === \"\\n\") {\n current.push(field);\n if (!skipEmpty || current.some((c) => c.trim() !== \"\")) {\n rows.push(current);\n }\n current = [];\n field = \"\";\n } else {\n field += char;\n }\n }\n }\n\n // Last field/row\n current.push(field);\n if (!skipEmpty || current.some((c) => c.trim() !== \"\")) {\n rows.push(current);\n }\n\n return rows;\n}\n\n// ============ Type Inference ============\n\nconst BOOLEAN_VALUES = new Set([\n \"true\",\n \"false\",\n \"yes\",\n \"no\",\n \"vrai\",\n \"faux\",\n \"oui\",\n \"non\",\n]);\n\nconst DATE_PATTERNS = [\n /^\\d{4}-\\d{2}-\\d{2}$/, // 2024-01-15\n /^\\d{2}\\/\\d{2}\\/\\d{4}$/, // 01/15/2024\n /^\\d{2}-\\d{2}-\\d{4}$/, // 01-15-2024\n /^\\d{4}\\/\\d{2}\\/\\d{2}$/, // 2024/01/15\n /^\\d{4}-\\d{2}-\\d{2}T/, // ISO 8601\n /^\\d{2}\\.\\d{2}\\.\\d{4}$/, // 15.01.2024\n /^\\w{3,9}\\s\\d{1,2},?\\s\\d{4}$/, // Jan 15, 2024 / January 15, 2024\n];\n\nfunction inferColumnType(\n rows: string[][],\n colIndex: number,\n): \"string\" | \"number\" | \"date\" | \"boolean\" {\n const sampleSize = Math.min(rows.length, 100);\n let numbers = 0;\n let dates = 0;\n let booleans = 0;\n let total = 0;\n\n for (let i = 0; i < sampleSize; i++) {\n const value = rows[i]?.[colIndex]?.trim() ?? \"\";\n if (value === \"\") continue;\n total++;\n\n if (BOOLEAN_VALUES.has(value.toLowerCase())) {\n booleans++;\n }\n\n // Check number (handle \"1,234.56\" and \"1 234.56\" formats)\n const cleaned = value.replace(/[\\s,]/g, \"\");\n if (cleaned !== \"\" && !isNaN(Number(cleaned))) {\n numbers++;\n }\n\n if (DATE_PATTERNS.some((p) => p.test(value))) {\n dates++;\n }\n }\n\n if (total === 0) return \"string\";\n\n const threshold = 0.8;\n // Check booleans first (only if NOT also numbers)\n if (booleans / total >= threshold && numbers / total < 0.5) return \"boolean\";\n if (dates / total >= threshold) return \"date\";\n if (numbers / total >= threshold) return \"number\";\n return \"string\";\n}\n","import type { TabularData } from \"./types\";\n\nexport interface ParseXLSXOptions {\n /** Whether the first row is a header row (default: true). */\n hasHeader?: boolean;\n /** Skip empty lines (default: true). */\n skipEmpty?: boolean;\n}\n\n// ============ Type Inference (shared with csv-parser) ============\n\nconst BOOLEAN_VALUES = new Set([\n \"true\",\n \"false\",\n \"yes\",\n \"no\",\n \"vrai\",\n \"faux\",\n \"oui\",\n \"non\",\n]);\n\nconst DATE_PATTERNS = [\n /^\\d{4}-\\d{2}-\\d{2}$/,\n /^\\d{2}\\/\\d{2}\\/\\d{4}$/,\n /^\\d{2}-\\d{2}-\\d{4}$/,\n /^\\d{4}\\/\\d{2}\\/\\d{2}$/,\n /^\\d{4}-\\d{2}-\\d{2}T/,\n /^\\d{2}\\.\\d{2}\\.\\d{4}$/,\n /^\\w{3,9}\\s\\d{1,2},?\\s\\d{4}$/,\n];\n\nfunction inferColumnType(\n rows: string[][],\n colIndex: number,\n): \"string\" | \"number\" | \"date\" | \"boolean\" {\n const sampleSize = Math.min(rows.length, 100);\n let numbers = 0;\n let dates = 0;\n let booleans = 0;\n let total = 0;\n\n for (let i = 0; i < sampleSize; i++) {\n const value = rows[i]?.[colIndex]?.trim() ?? \"\";\n if (value === \"\") continue;\n total++;\n\n if (BOOLEAN_VALUES.has(value.toLowerCase())) booleans++;\n\n const cleaned = value.replace(/[\\s,]/g, \"\");\n if (cleaned !== \"\" && !isNaN(Number(cleaned))) numbers++;\n\n if (DATE_PATTERNS.some((p) => p.test(value))) dates++;\n }\n\n if (total === 0) return \"string\";\n const threshold = 0.8;\n if (booleans / total >= threshold && numbers / total < 0.5) return \"boolean\";\n if (dates / total >= threshold) return \"date\";\n if (numbers / total >= threshold) return \"number\";\n return \"string\";\n}\n\n// ============ Core conversion (universal, no dependencies) ============\n\n/**\n * Convert raw XLSX rows (as returned by `read-excel-file`) into TabularData.\n *\n * This function is **universal** — it works in Node.js, browsers, and web workers.\n * You read the file yourself with `read-excel-file` (or any other XLSX parser)\n * and pass the resulting rows here.\n *\n * @example\n * ```ts\n * // Node.js\n * import readXlsxFile from \"read-excel-file/node\";\n * import { convertXLSXRows } from \"csv-charts-ai\";\n *\n * const rows = await readXlsxFile(\"data.xlsx\");\n * const data = convertXLSXRows(rows);\n * ```\n *\n * @example\n * ```ts\n * // Browser\n * import readXlsxFile from \"read-excel-file/browser\";\n * import { convertXLSXRows } from \"csv-charts-ai\";\n *\n * const rows = await readXlsxFile(file);\n * const data = convertXLSXRows(rows);\n * ```\n */\nexport function convertXLSXRows(\n rawRows: (string | number | boolean | Date | null)[][],\n options: ParseXLSXOptions = {},\n): TabularData {\n const { hasHeader = true, skipEmpty = true } = options;\n\n // Convert all cells to strings\n let rows = rawRows.map((row) =>\n row.map((cell) => (cell != null ? String(cell) : \"\")),\n );\n\n if (skipEmpty) {\n rows = rows.filter((row) => row.some((cell) => cell.trim() !== \"\"));\n }\n\n if (rows.length === 0) {\n return { headers: [], rows: [], columns: [], rowCount: 0 };\n }\n\n const firstRow = rows[0]!;\n const headers = hasHeader\n ? firstRow.map((h, i) => h.trim() || `Column ${i + 1}`)\n : firstRow.map((_, i) => `Column ${i + 1}`);\n\n const dataRows = hasHeader ? rows.slice(1) : rows;\n\n // Normalize: ensure every row has exactly `headers.length` cells\n const normalizedRows = dataRows.map((row) =>\n headers.map((_, i) => row[i] ?? \"\"),\n );\n\n const columns = headers.map((name, index) => ({\n name,\n type: inferColumnType(normalizedRows, index),\n index,\n }));\n\n return { headers, rows: normalizedRows, columns, rowCount: normalizedRows.length };\n}\n\n// ============ Browser convenience ============\n\n/**\n * Parse an Excel (.xlsx) file into TabularData. **Browser only.**\n *\n * `read-excel-file` is bundled — no extra install needed.\n * Always reads the first sheet.\n *\n * @example\n * ```tsx\n * import { parseXLSX } from \"csv-charts-ai\";\n *\n * const handleFile = async (file: File) => {\n * const data = await parseXLSX(file);\n * console.log(data.headers, data.rowCount);\n * };\n * ```\n */\nexport async function parseXLSX(\n file: File,\n options: ParseXLSXOptions = {},\n): Promise<TabularData> {\n const mod = await import(\"read-excel-file/browser\");\n const result = await mod.default(file);\n const rawRows = result as (string | number | boolean | Date | null)[][];\n return convertXLSXRows(rawRows, options);\n}\n","import type {\n TabularData,\n ChartConfig,\n SortOrder,\n ChartDataPoint,\n} from \"./types\";\n\nexport interface ProcessedChartResult {\n data: ChartDataPoint[];\n seriesKeys: string[];\n yKey: string;\n}\n\nexport const processChartData = (\n data: TabularData,\n chart: ChartConfig,\n sortOrder: SortOrder = \"none\",\n limit = 20,\n): ChartDataPoint[] => {\n const result = processChartDataMultiSeries(data, chart, sortOrder, limit);\n return result.data;\n};\n\nexport const processChartDataMultiSeries = (\n data: TabularData,\n chart: ChartConfig,\n sortOrder: SortOrder = \"none\",\n limit = 20,\n): ProcessedChartResult => {\n let result: ChartDataPoint[] = [];\n\n // Find actual columns (case-insensitive match)\n const xColDef = data.columns.find(\n (c) => c.name.toLowerCase() === chart.xAxis.toLowerCase(),\n );\n const yColDef = data.columns.find(\n (c) => c.name.toLowerCase() === chart.yAxis.toLowerCase(),\n );\n const groupColDef = chart.groupBy\n ? data.columns.find(\n (c) => c.name.toLowerCase() === chart.groupBy!.toLowerCase(),\n )\n : undefined;\n\n if (!xColDef) return { data: [], seriesKeys: [], yKey: chart.yAxis };\n\n const xCol = xColDef.name;\n const xIdx = xColDef.index;\n\n // For count aggregation, we don't need a valid Y column - we just count occurrences\n const isCountMode = chart.aggregation === \"count\";\n const yCol = yColDef?.name ?? \"count\";\n const yIdx = yColDef?.index ?? -1;\n\n // GroupBy mode: create multi-series data (not supported for pie/scatter)\n const supportsGroupBy =\n chart.type !== \"pie\" && chart.type !== \"scatter\";\n if (\n supportsGroupBy &&\n groupColDef &&\n chart.aggregation &&\n chart.aggregation !== \"none\"\n ) {\n const groupIdx = groupColDef.index;\n const allGroups = new Set<string>();\n\n // Nested grouping: xVal -> groupVal -> stats\n const grouped = new Map<\n string,\n Map<string, { sum: number; count: number; min: number; max: number }>\n >();\n\n data.rows.forEach((row) => {\n const xVal = String(row[xIdx] ?? \"\").trim();\n const groupVal = String(row[groupIdx] ?? \"\").trim();\n if (!xVal || !groupVal) return;\n\n allGroups.add(groupVal);\n\n if (!grouped.has(xVal)) grouped.set(xVal, new Map());\n const xGroup = grouped.get(xVal)!;\n\n if (isCountMode) {\n const current = xGroup.get(groupVal) ?? {\n sum: 0,\n count: 0,\n min: 0,\n max: 0,\n };\n xGroup.set(groupVal, { ...current, count: current.count + 1 });\n } else if (yIdx >= 0) {\n const yVal = parseFloat(String(row[yIdx] ?? \"0\"));\n if (!isNaN(yVal)) {\n const current = xGroup.get(groupVal) ?? {\n sum: 0,\n count: 0,\n min: Infinity,\n max: -Infinity,\n };\n xGroup.set(groupVal, {\n sum: current.sum + yVal,\n count: current.count + 1,\n min: Math.min(current.min, yVal),\n max: Math.max(current.max, yVal),\n });\n }\n }\n });\n\n const seriesKeys = Array.from(allGroups).slice(0, 8); // max 8 series\n\n grouped.forEach((groupMap, xKey) => {\n const point: ChartDataPoint = { [xCol]: xKey };\n seriesKeys.forEach((groupKey) => {\n const stats = groupMap.get(groupKey);\n if (stats) {\n let value: number;\n switch (chart.aggregation) {\n case \"sum\":\n value = stats.sum;\n break;\n case \"avg\":\n value = stats.count > 0 ? stats.sum / stats.count : 0;\n break;\n case \"count\":\n value = stats.count;\n break;\n case \"min\":\n value = stats.min === Infinity ? 0 : stats.min;\n break;\n case \"max\":\n value = stats.max === -Infinity ? 0 : stats.max;\n break;\n default:\n value = stats.sum;\n }\n point[groupKey] = Math.round(value * 100) / 100;\n } else {\n point[groupKey] = 0;\n }\n });\n result.push(point);\n });\n\n // Sort by first series value or alphabetically\n if (sortOrder !== \"none\" && seriesKeys[0]) {\n const firstKey = seriesKeys[0];\n result.sort((a, b) => {\n const aVal = (a[firstKey] as number) ?? 0;\n const bVal = (b[firstKey] as number) ?? 0;\n return sortOrder === \"desc\" ? bVal - aVal : aVal - bVal;\n });\n }\n\n return {\n data: result.slice(0, limit),\n seriesKeys,\n yKey: yCol,\n };\n }\n\n // Standard single-series mode (existing logic)\n if (chart.aggregation && chart.aggregation !== \"none\") {\n const groups = new Map<\n string,\n { sum: number; count: number; min: number; max: number }\n >();\n\n data.rows.forEach((row) => {\n const xVal = String(row[xIdx] ?? \"\").trim();\n if (!xVal) return;\n\n if (isCountMode) {\n const current = groups.get(xVal) ?? {\n sum: 0,\n count: 0,\n min: 0,\n max: 0,\n };\n groups.set(xVal, {\n ...current,\n count: current.count + 1,\n });\n } else if (yIdx >= 0) {\n const yVal = parseFloat(String(row[yIdx] ?? \"0\"));\n if (!isNaN(yVal)) {\n const current = groups.get(xVal) ?? {\n sum: 0,\n count: 0,\n min: Infinity,\n max: -Infinity,\n };\n groups.set(xVal, {\n sum: current.sum + yVal,\n count: current.count + 1,\n min: Math.min(current.min, yVal),\n max: Math.max(current.max, yVal),\n });\n }\n }\n });\n\n groups.forEach((stats, key) => {\n let value: number;\n switch (chart.aggregation) {\n case \"sum\":\n value = stats.sum;\n break;\n case \"avg\":\n value = stats.count > 0 ? stats.sum / stats.count : 0;\n break;\n case \"count\":\n value = stats.count;\n break;\n case \"min\":\n value = stats.min === Infinity ? 0 : stats.min;\n break;\n case \"max\":\n value = stats.max === -Infinity ? 0 : stats.max;\n break;\n default:\n value = stats.sum;\n }\n result.push({ [xCol]: key, [yCol]: Math.round(value * 100) / 100 });\n });\n } else if (yIdx >= 0) {\n result = data.rows\n .slice(0, Math.min(limit * 2, data.rows.length))\n .map((row) => ({\n [xCol]: row[xIdx] ?? \"\",\n [yCol]: parseFloat(String(row[yIdx] ?? \"0\")),\n }))\n .filter((item) => !isNaN(item[yCol] as number));\n }\n\n // Apply sorting\n if (sortOrder !== \"none\") {\n result.sort((a, b) => {\n const aVal = a[yCol] as number;\n const bVal = b[yCol] as number;\n return sortOrder === \"desc\" ? bVal - aVal : aVal - bVal;\n });\n }\n\n return {\n data: result.slice(0, limit),\n seriesKeys: [],\n yKey: yCol,\n };\n};\n","export const COLORS = [\n \"#8b5cf6\", // Violet 500\n \"#06b6d4\", // Cyan 500\n \"#f43f5e\", // Rose 500\n \"#eab308\", // Yellow 500\n \"#10b981\", // Emerald 500\n \"#3b82f6\", // Blue 500\n \"#d946ef\", // Fuchsia 500\n \"#f97316\", // Orange 500\n];\n","export type ChartType = \"bar\" | \"line\" | \"pie\" | \"scatter\" | \"area\";\nexport type AggregationType =\n | \"sum\"\n | \"avg\"\n | \"count\"\n | \"min\"\n | \"max\"\n | \"none\";\n\nexport interface TabularData {\n headers: string[];\n rows: string[][];\n columns: {\n name: string;\n type: \"string\" | \"number\" | \"date\" | \"boolean\";\n index: number;\n }[];\n rowCount: number;\n}\n\nexport interface ChartConfig {\n id: string;\n type: ChartType;\n title: string;\n description: string;\n xAxis: string;\n yAxis: string;\n groupBy?: string;\n aggregation: AggregationType;\n dataConfig?: {\n xColumn: string;\n yColumn: string;\n groupColumn?: string;\n };\n}\n\nexport type SortOrder = \"none\" | \"asc\" | \"desc\";\nexport type ChartDataPoint = Record<string, string | number>;\n\n// Theme types\nexport interface ChartTheme {\n colors: string[];\n background: string;\n cardBackground: string;\n border: string;\n text: string;\n textMuted: string;\n textDimmed: string;\n gridStroke: string;\n tooltipBackground: string;\n tooltipBorder: string;\n accentPrimary: string;\n accentSecondary: string;\n accentSuccess: string;\n accentDanger: string;\n}\n\nexport const defaultDarkTheme: ChartTheme = {\n colors: [\n \"#8b5cf6\",\n \"#06b6d4\",\n \"#f43f5e\",\n \"#eab308\",\n \"#10b981\",\n \"#3b82f6\",\n \"#d946ef\",\n \"#f97316\",\n ],\n background: \"rgba(15, 23, 42, 0.5)\",\n cardBackground: \"rgba(255, 255, 255, 0.05)\",\n border: \"rgba(255, 255, 255, 0.1)\",\n text: \"#ffffff\",\n textMuted: \"#9ca3af\",\n textDimmed: \"#6b7280\",\n gridStroke: \"#374151\",\n tooltipBackground: \"#1f2937\",\n tooltipBorder: \"1px solid #374151\",\n accentPrimary: \"#8b5cf6\",\n accentSecondary: \"#06b6d4\",\n accentSuccess: \"#10b981\",\n accentDanger: \"#ef4444\",\n};\n\nexport const defaultLightTheme: ChartTheme = {\n colors: [\n \"#7c3aed\",\n \"#0891b2\",\n \"#e11d48\",\n \"#ca8a04\",\n \"#059669\",\n \"#2563eb\",\n \"#c026d3\",\n \"#ea580c\",\n ],\n background: \"#ffffff\",\n cardBackground: \"#f8fafc\",\n border: \"#e2e8f0\",\n text: \"#0f172a\",\n textMuted: \"#64748b\",\n textDimmed: \"#94a3b8\",\n gridStroke: \"#e2e8f0\",\n tooltipBackground: \"#ffffff\",\n tooltipBorder: \"1px solid #e2e8f0\",\n accentPrimary: \"#7c3aed\",\n accentSecondary: \"#0891b2\",\n accentSuccess: \"#059669\",\n accentDanger: \"#dc2626\",\n};\n","import { generateObject, type LanguageModel } from \"ai\";\nimport { z } from \"zod\";\nimport { createOpenAI } from \"@ai-sdk/openai\";\nimport { createAnthropic } from \"@ai-sdk/anthropic\";\nimport { createGoogleGenerativeAI } from \"@ai-sdk/google\";\nimport { createMistral } from \"@ai-sdk/mistral\";\nimport type { ChartConfig, TabularData } from \"./types\";\n\n// ============ Input Validation Schemas ============\n\n/** Zod schema for simple API config (OpenAI-compatible endpoints) */\nexport const AIConfigSchema = z.object({\n /** API key for authentication */\n apiKey: z.string(),\n /** Model identifier (e.g. \"gpt-4o\", \"llama3\", \"mistral-large\") */\n model: z.string(),\n /** Custom base URL for non-OpenAI providers (Ollama, vLLM, Mistral, etc.) */\n baseURL: z.string().optional(),\n /** Provider hint — used to dynamically load the right SDK. Defaults to \"openai\". */\n provider: z\n .enum([\"openai\", \"anthropic\", \"google\", \"mistral\"])\n .optional()\n .default(\"openai\"),\n});\n\nexport type AIConfig = z.infer<typeof AIConfigSchema>;\n\n/** Zod schema for TabularData validation */\nexport const TabularDataSchema = z.object({\n headers: z.array(z.string()).min(1, \"Data must have at least one column\"),\n rows: z.array(z.array(z.string())),\n columns: z.array(\n z.object({\n name: z.string(),\n type: z.enum([\"string\", \"number\", \"date\", \"boolean\"]),\n index: z.number(),\n }),\n ),\n rowCount: z.number(),\n});\n\n/**\n * Extended config for multi-provider apps.\n * Supports provider selection via npm package name (e.g. \"@ai-sdk/anthropic\").\n */\nexport interface AppModelConfig {\n apiKey: string;\n model?: string;\n /** Provider npm package name (e.g. \"@ai-sdk/anthropic\", \"@ai-sdk/google\") */\n providerNpm?: string;\n /** Provider base API URL (for OpenAI-compatible endpoints) */\n providerApi?: string;\n /** Custom endpoint URL (takes priority over providerNpm) */\n customEndpoint?: string;\n /** Custom model name (takes priority over model) */\n customModel?: string;\n}\n\n/** Model input: either a simple config object, an app config, or a pre-built LanguageModel */\nexport type ModelInput = AIConfig | AppModelConfig | LanguageModel;\n\n// ============ Chart Output Schemas ============\n\nconst ChartSuggestionSchema = z.object({\n type: z.enum([\"bar\", \"line\", \"pie\", \"scatter\", \"area\"]),\n title: z.string(),\n description: z\n .string()\n .optional()\n .default(\"\")\n .describe(\"Short description of what the chart shows\"),\n xColumn: z\n .string()\n .describe(\"The EXACT column name to use for X axis (categories/labels)\"),\n yColumn: z\n .string()\n .describe(\"The EXACT column name to use for Y axis (values)\"),\n groupColumn: z\n .string()\n .optional()\n .describe(\"Optional column to group/segment the data\"),\n aggregation: z\n .enum([\"sum\", \"avg\", \"count\", \"min\", \"max\", \"none\"])\n .optional()\n .default(\"none\")\n .describe(\"How to aggregate Y values when there are duplicates in X\"),\n reasoning: z\n .string()\n .optional()\n .default(\"\")\n .describe(\"Brief explanation of why this chart is useful for this data\"),\n});\n\nconst ChartSuggestionsResponseSchema = z.object({\n charts: z.array(ChartSuggestionSchema),\n});\n\nconst SingleChartResponseSchema = z.object({\n chart: ChartSuggestionSchema,\n});\n\n// ============ Error Handling ============\n\n/**\n * Extracts a user-friendly error message from AI provider errors.\n * Exported so consumers can use it in their own error handling.\n */\nexport function getAIErrorMessage(error: unknown): string {\n // Handle Zod validation errors\n if (\n error instanceof Error &&\n error.name === \"ZodError\" &&\n \"issues\" in error\n ) {\n const issues = (error as { issues: Array<{ message: string }> }).issues;\n return `Invalid data: ${issues.map((i) => i.message).join(\", \")}`;\n }\n\n if (error instanceof Error) {\n const message = error.message.toLowerCase();\n\n if (message.includes(\"rate limit\") || message.includes(\"429\")) {\n return \"Rate limit exceeded. Please wait a moment and try again.\";\n }\n if (\n message.includes(\"unauthorized\") ||\n message.includes(\"401\") ||\n message.includes(\"invalid api key\") ||\n message.includes(\"invalid_api_key\")\n ) {\n return \"Invalid API key. Please check your API key configuration.\";\n }\n if (\n message.includes(\"quota\") ||\n message.includes(\"insufficient_quota\") ||\n message.includes(\"billing\")\n ) {\n return \"API quota exceeded or billing issue. Please check your account status.\";\n }\n if (\n message.includes(\"network\") ||\n message.includes(\"timeout\") ||\n message.includes(\"econnrefused\") ||\n message.includes(\"fetch failed\")\n ) {\n return \"Network error. Please check your internet connection and try again.\";\n }\n if (\n message.includes(\"model\") &&\n (message.includes(\"not found\") || message.includes(\"does not exist\"))\n ) {\n return \"Model not available. Please select a different model.\";\n }\n\n return error.message;\n }\n\n return \"An unexpected error occurred. Please try again.\";\n}\n\n// ============ Data Summary Generation ============\n\n/**\n * Generate a text summary of tabular data for AI consumption.\n * If the consumer doesn't provide a `dataSummary`, this is used automatically.\n */\nexport function summarizeTabularData(data: TabularData): string {\n const lines: string[] = [];\n lines.push(`Dataset: ${data.rowCount} rows, ${data.headers.length} columns`);\n lines.push(`Columns: ${data.headers.join(\", \")}`);\n lines.push(\"\");\n\n for (const col of data.columns) {\n const idx = col.index;\n const values = data.rows.map((r) => r[idx] ?? \"\").filter((v) => v !== \"\");\n\n if (col.type === \"number\") {\n const nums = values.map(Number).filter((n) => !isNaN(n));\n if (nums.length > 0) {\n const min = nums.reduce((a, b) => (b < a ? b : a), nums[0]!);\n const max = nums.reduce((a, b) => (b > a ? b : a), nums[0]!);\n const avg = nums.reduce((a, b) => a + b, 0) / nums.length;\n lines.push(\n `- ${col.name} (${col.type}): min=${min}, max=${max}, avg=${avg.toFixed(2)}, ${nums.length} values`,\n );\n } else {\n lines.push(`- ${col.name} (${col.type}): no valid numeric values`);\n }\n } else {\n const distinct = new Set(values).size;\n const sample = values.slice(0, 5).join(\", \");\n lines.push(\n `- ${col.name} (${col.type}): ${distinct} distinct values, sample: [${sample}]`,\n );\n }\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Generate a detailed human-readable summary of tabular data,\n * including column statistics and sample rows.\n *\n * @example\n * ```ts\n * const summary = generateDataSummary(data);\n * // \"Dataset with 150 rows and 4 columns.\\n\\nColumns:\\n- name (text): 120 unique values...\"\n * ```\n */\nexport function generateDataSummary(data: TabularData): string {\n const summary: string[] = [];\n\n summary.push(\n `Dataset with ${data.rowCount} rows and ${data.columns.length} columns.`,\n );\n summary.push(\"\\nColumns:\");\n\n data.columns.forEach((col) => {\n const values = data.rows.map((row) => row[col.index] ?? \"\");\n const nonEmpty = values.filter((v) => v.trim() !== \"\");\n\n if (col.type === \"number\") {\n const numbers = nonEmpty\n .map((v) => parseFloat(v.replace(/[\\s,]/g, \"\").replace(\",\", \".\")))\n .filter((n) => !isNaN(n));\n\n if (numbers.length > 0) {\n const min = Math.min(...numbers);\n const max = Math.max(...numbers);\n const avg = numbers.reduce((a, b) => a + b, 0) / numbers.length;\n summary.push(\n `- ${col.name} (number): min=${min.toFixed(2)}, max=${max.toFixed(2)}, avg=${avg.toFixed(2)}, ${numbers.length} values`,\n );\n } else {\n summary.push(`- ${col.name} (number): no valid values`);\n }\n } else if (col.type === \"string\") {\n const uniqueValues = new Set(nonEmpty);\n const uniqueCount = uniqueValues.size;\n const sampleValues = Array.from(uniqueValues).slice(0, 5).join(\", \");\n summary.push(\n `- ${col.name} (text): ${uniqueCount} unique values, examples: ${sampleValues}`,\n );\n } else if (col.type === \"date\") {\n summary.push(`- ${col.name} (date): ${nonEmpty.length} values`);\n } else if (col.type === \"boolean\") {\n summary.push(`- ${col.name} (boolean): ${nonEmpty.length} values`);\n }\n });\n\n // Add sample rows\n summary.push(\"\\nFirst 5 rows sample:\");\n const sampleRows = data.rows.slice(0, 5);\n sampleRows.forEach((row, i) => {\n const rowData = data.columns\n .map((col) => `${col.name}: ${row[col.index] ?? \"N/A\"}`)\n .join(\", \");\n summary.push(`Row ${i + 1}: ${rowData}`);\n });\n\n return summary.join(\"\\n\");\n}\n\n// ============ Model Resolution ============\n\nfunction isLanguageModel(input: unknown): input is LanguageModel {\n return (\n typeof input === \"object\" &&\n input !== null &&\n \"doGenerate\" in input &&\n typeof (input as Record<string, unknown>).doGenerate === \"function\"\n );\n}\n\n/**\n * Create a LanguageModel from an AIConfig.\n * All provider SDKs are bundled — no dynamic imports needed.\n *\n * @example\n * ```ts\n * const model = createModel({ apiKey: \"sk-...\", model: \"gpt-4o\" });\n * const charts1 = await suggestCharts({ model, data, dataSummary });\n * const charts2 = await suggestCustomChart({ model, data, dataSummary, prompt: \"...\" });\n * ```\n */\nexport function createModel(config: AIConfig): LanguageModel {\n const parsed = AIConfigSchema.parse(config);\n\n if (parsed.baseURL || parsed.provider === \"openai\") {\n const openai = createOpenAI({\n apiKey: parsed.apiKey,\n ...(parsed.baseURL && { baseURL: parsed.baseURL }),\n }) as unknown as (model: string) => LanguageModel;\n return openai(parsed.model);\n }\n\n switch (parsed.provider) {\n case \"anthropic\": {\n return createAnthropic({ apiKey: parsed.apiKey })(parsed.model);\n }\n case \"google\": {\n return createGoogleGenerativeAI({ apiKey: parsed.apiKey })(parsed.model);\n }\n case \"mistral\": {\n return createMistral({ apiKey: parsed.apiKey })(parsed.model);\n }\n default: {\n const openai = createOpenAI({\n apiKey: parsed.apiKey,\n }) as unknown as (model: string) => LanguageModel;\n return openai(parsed.model);\n }\n }\n}\n\n/**\n * Create a LanguageModel from an AppModelConfig.\n * Handles multi-provider apps with providerNpm-based routing,\n * custom endpoints, and Anthropic browser headers.\n *\n * @example\n * ```ts\n * const model = createAppModel({\n * apiKey: \"sk-...\",\n * model: \"claude-haiku-4-5\",\n * providerNpm: \"@ai-sdk/anthropic\",\n * });\n * ```\n */\nexport function createAppModel(config: AppModelConfig): LanguageModel {\n const modelName = config.customModel ?? config.model ?? \"\";\n\n if (config.customEndpoint) {\n const openai = createOpenAI({\n apiKey: config.apiKey || \"\",\n baseURL: config.customEndpoint,\n }) as unknown as (model: string) => LanguageModel;\n return openai(config.customModel ?? modelName);\n }\n\n switch (config.providerNpm) {\n case \"@ai-sdk/anthropic\": {\n const anthropic = createAnthropic({\n apiKey: config.apiKey,\n headers: { \"anthropic-dangerous-direct-browser-access\": \"true\" },\n });\n return anthropic(modelName);\n }\n case \"@ai-sdk/google\": {\n const google = createGoogleGenerativeAI({ apiKey: config.apiKey });\n return google(modelName);\n }\n case \"@ai-sdk/mistral\": {\n const mistral = createMistral({ apiKey: config.apiKey });\n return mistral(modelName);\n }\n default: {\n const openai = createOpenAI({\n apiKey: config.apiKey,\n baseURL: config.providerApi,\n }) as unknown as (model: string) => LanguageModel;\n return openai(modelName);\n }\n }\n}\n\nfunction isAppModelConfig(input: unknown): input is AppModelConfig {\n if (typeof input !== \"object\" || input === null) return false;\n if (\"doGenerate\" in input) return false; // LanguageModel\n // AppModelConfig is identified by its unique fields (providerNpm, providerApi, customEndpoint, customModel)\n // This avoids misrouting AIConfig objects (which have provider/baseURL) through createAppModel\n return (\n \"providerNpm\" in input ||\n \"providerApi\" in input ||\n \"customEndpoint\" in input ||\n \"customModel\" in input\n );\n}\n\nexport function resolveModel(input: ModelInput): LanguageModel {\n if (isLanguageModel(input)) return input;\n if (isAppModelConfig(input)) return createAppModel(input);\n return createModel(input as AIConfig);\n}\n\n// ============ Prompts ============\n\nconst getChartSystemPrompt = (\n columns: string[],\n language?: string,\n) => `You are a data visualization expert.${language ? ` Respond in ${language}.` : \"\"}\n\nYou will analyze CSV data and suggest the best charts to visualize it.\n\nAVAILABLE COLUMNS (use these EXACT names):\n${columns.map((c) => `- \"${c}\"`).join(\"\\n\")}\n\nCRITICAL RULES:\n1. xColumn and yColumn MUST be exact column names from the list above\n2. For numeric analysis, yColumn should be a numeric column\n3. For categorical comparisons, xColumn should be a categorical column\n4. Only suggest charts that make sense for the data types\n5. Use aggregation when there are multiple rows per category:\n - \"sum\" for totals (sales, revenue)\n - \"avg\" for averages (ratings, scores)\n - \"count\" for frequencies\n - \"none\" for unique values or time series\n6. Suggest 2-4 charts maximum, focusing on the most insightful ones\n\nCHART TYPE GUIDELINES:\n- bar: Compare categories (xColumn=category, yColumn=numeric)\n- line: Show trends over time (xColumn=date/time, yColumn=numeric)\n- pie: Show proportions (xColumn=category, yColumn=numeric with sum/count)\n- scatter: Show correlations (xColumn=numeric, yColumn=numeric, aggregation=none)\n- area: Show cumulative trends (xColumn=date/time, yColumn=numeric)`;\n\nconst getCustomChartPrompt = (\n columns: string[],\n language?: string,\n) => `You are a data visualization expert.${language ? ` Respond in ${language}.` : \"\"}\n\nCreate a chart configuration based on the user's request.\n\nAVAILABLE COLUMNS (use these EXACT names):\n${columns.map((c) => `- \"${c}\"`).join(\"\\n\")}\n\nIMPORTANT: Column names MUST exactly match the list above.`;\n\n// ============ Helpers ============\n\nfunction mapChartResult(\n raw: z.infer<typeof ChartSuggestionSchema>,\n id: string,\n): ChartConfig {\n return {\n id,\n type: raw.type,\n title: raw.title,\n description: raw.description,\n xAxis: raw.xColumn,\n yAxis: raw.yColumn,\n groupBy: raw.groupColumn,\n aggregation: raw.aggregation,\n dataConfig: {\n xColumn: raw.xColumn,\n yColumn: raw.yColumn,\n groupColumn: raw.groupColumn,\n },\n };\n}\n\n// ============ Options ============\n\nexport interface SuggestChartsOptions {\n /** The AI model — either a simple config or a LanguageModel instance */\n model: ModelInput;\n /** The tabular data to analyze */\n data: TabularData;\n /** A text summary of the data. If omitted, auto-generated from `data`. */\n dataSummary?: string;\n /** Language for AI responses (e.g. \"English\", \"French\") */\n language?: string;\n /** Temperature for AI generation (default: 0.5) */\n temperature?: number;\n /** AbortSignal to cancel the request */\n signal?: AbortSignal;\n}\n\nexport interface SuggestCustomChartOptions {\n /** The AI model — either a simple config or a LanguageModel instance */\n model: ModelInput;\n /** The tabular data */\n data: TabularData;\n /** A text summary of the data. If omitted, auto-generated from `data`. */\n dataSummary?: string;\n /** The user's chart request (e.g. \"show sales by month\") */\n prompt: string;\n /** Language for AI responses */\n language?: string;\n /** Temperature (default: 0.5) */\n temperature?: number;\n /** AbortSignal to cancel the request */\n signal?: AbortSignal;\n}\n\nexport interface RepairChartOptions {\n /** The AI model — either a simple config or a LanguageModel instance */\n model: ModelInput;\n /** The chart configuration that failed */\n failedChart: ChartConfig;\n /** Available column names */\n columns: string[];\n /** Description of why the chart failed */\n errorContext: string;\n /** Language for AI responses */\n language?: string;\n /** Temperature (default: 0.3) */\n temperature?: number;\n /** AbortSignal to cancel the request */\n signal?: AbortSignal;\n}\n\n// ============ Public API ============\n\n/**\n * Generate chart suggestions from tabular data using AI.\n *\n * @example\n * ```ts\n * import { suggestCharts } from \"csv-charts-ai\";\n *\n * // Minimal — auto-generates dataSummary from the data\n * const charts = await suggestCharts({\n * model: { apiKey: \"sk-...\", model: \"gpt-4o\" },\n * data: myData,\n * });\n *\n * // Custom endpoint — Ollama\n * const charts = await suggestCharts({\n * model: { apiKey: \"\", model: \"llama3\", baseURL: \"http://localhost:11434/v1\" },\n * data: myData,\n * });\n *\n * // Advanced — any LanguageModel from the ai SDK\n * import { anthropic } from \"@ai-sdk/anthropic\";\n * const charts = await suggestCharts({\n * model: anthropic(\"claude-sonnet-4-20250514\"),\n * data: myData,\n * language: \"French\",\n * });\n * ```\n */\nexport async function suggestCharts(\n options: SuggestChartsOptions,\n): Promise<ChartConfig[]> {\n const { data, language, temperature = 0.5, signal } = options;\n const dataSummary = options.dataSummary ?? summarizeTabularData(data);\n\n try {\n TabularDataSchema.parse(data);\n const model = resolveModel(options.model);\n\n const { object } = await generateObject({\n model,\n schema: ChartSuggestionsResponseSchema,\n system: getChartSystemPrompt(data.headers, language),\n prompt: `Analyze this CSV data and suggest the best charts:\\n\\n${dataSummary}`,\n temperature,\n ...(signal && { abortSignal: signal }),\n });\n\n return object.charts.map((s, i) =>\n mapChartResult(s, `chart-${i}-${Date.now()}`),\n );\n } catch (error) {\n throw new Error(getAIErrorMessage(error));\n }\n}\n\n/**\n * Generate a single chart from a user's text prompt.\n *\n * @example\n * ```ts\n * const chart = await suggestCustomChart({\n * model: { apiKey: \"sk-...\", model: \"gpt-4o\" },\n * data: myData,\n * prompt: \"Show me a bar chart of sales by category\",\n * });\n * ```\n */\nexport async function suggestCustomChart(\n options: SuggestCustomChartOptions,\n): Promise<ChartConfig | null> {\n const { data, prompt, language, temperature = 0.5, signal } = options;\n const dataSummary = options.dataSummary ?? summarizeTabularData(data);\n\n try {\n TabularDataSchema.parse(data);\n const model = resolveModel(options.model);\n\n const { object } = await generateObject({\n model,\n schema: SingleChartResponseSchema,\n system: getCustomChartPrompt(data.headers, language),\n prompt: `Data summary:\\n${dataSummary}\\n\\nUser request: ${prompt}`,\n temperature,\n ...(signal && { abortSignal: signal }),\n });\n\n return mapChartResult(object.chart, `chart-custom-${Date.now()}`);\n } catch (error) {\n throw new Error(getAIErrorMessage(error));\n }\n}\n\n/**\n * Repair a chart configuration that failed to render.\n *\n * @example\n * ```ts\n * const fixed = await repairChart({\n * model: { apiKey: \"sk-...\", model: \"gpt-4o\" },\n * failedChart: brokenChart,\n * columns: [\"name\", \"sales\", \"date\"],\n * errorContext: \"Column 'revenue' does not exist\",\n * });\n * ```\n */\nexport async function repairChart(\n options: RepairChartOptions,\n): Promise<ChartConfig | null> {\n const {\n failedChart,\n columns,\n errorContext,\n language,\n temperature = 0.3,\n signal,\n } = options;\n\n try {\n const model = resolveModel(options.model);\n\n const { object } = await generateObject({\n model,\n schema: SingleChartResponseSchema,\n system: getCustomChartPrompt(columns, language),\n prompt: `The following chart configuration failed to render:\\n${JSON.stringify(failedChart, null, 2)}\\n\\nError context: ${errorContext}\\n\\nPlease fix the configuration to use valid columns and aggregation. Available columns: ${columns.join(\", \")}`,\n temperature,\n ...(signal && { abortSignal: signal }),\n });\n\n return mapChartResult(object.chart, failedChart.id);\n } catch (error) {\n throw new Error(getAIErrorMessage(error));\n }\n}\n","import type { TabularData } from \"./types\";\n\n/* ── Types ── */\n\nexport type MatchMode = \"index\" | \"key\" | \"content\";\nexport type DiffStatus = \"same\" | \"changed\" | \"added\" | \"removed\";\n\nexport interface DiffRow {\n indexA: number | null;\n indexB: number | null;\n status: DiffStatus;\n rowA: (string | number)[] | null;\n rowB: (string | number)[] | null;\n changedCols: Set<string>;\n}\n\nexport interface DiffCounts {\n same: number;\n changed: number;\n added: number;\n removed: number;\n}\n\nexport interface DiffResult {\n commonHeaders: string[];\n onlyInA: string[];\n onlyInB: string[];\n rows: DiffRow[];\n counts: DiffCounts;\n}\n\nexport interface DiffOptions {\n matchMode: MatchMode;\n keyColumn?: string;\n}\n\n/* ── Diff computation ── */\n\nexport function computeDiff(\n primaryData: TabularData,\n compareData: TabularData,\n options: DiffOptions,\n): DiffResult {\n const { matchMode, keyColumn = \"\" } = options;\n\n const commonHeaders = primaryData.headers.filter((h) =>\n compareData.headers.includes(h),\n );\n const onlyInA = primaryData.headers.filter(\n (h) => !compareData.headers.includes(h),\n );\n const onlyInB = compareData.headers.filter(\n (h) => !primaryData.headers.includes(h),\n );\n\n const rows: DiffRow[] = [];\n\n const getChangedCols = (\n a: (string | number)[],\n b: (string | number)[],\n ): Set<string> => {\n const changed = new Set<string>();\n for (const h of commonHeaders) {\n const aIdx = primaryData.headers.indexOf(h);\n const bIdx = compareData.headers.indexOf(h);\n if (String(a[aIdx] ?? \"\") !== String(b[bIdx] ?? \"\")) {\n changed.add(h);\n }\n }\n return changed;\n };\n\n // Determine effective match mode\n const effectiveMode =\n matchMode === \"content\"\n ? \"content\"\n : matchMode === \"key\" && keyColumn && commonHeaders.includes(keyColumn)\n ? \"key\"\n : \"index\";\n\n if (effectiveMode === \"content\") {\n const makeKey = (row: (string | number)[], headers: string[]) =>\n commonHeaders\n .map((h) => String(row[headers.indexOf(h)] ?? \"\"))\n .join(\"\\0\");\n\n const aMap = new Map<string, { row: (string | number)[]; idx: number }[]>();\n for (let i = 0; i < primaryData.rows.length; i++) {\n const key = makeKey(primaryData.rows[i]!, primaryData.headers);\n const list = aMap.get(key) ?? [];\n list.push({ row: primaryData.rows[i]!, idx: i });\n aMap.set(key, list);\n }\n\n const matchedAIndices = new Set<number>();\n\n for (let i = 0; i < compareData.rows.length; i++) {\n const key = makeKey(compareData.rows[i]!, compareData.headers);\n const candidates = aMap.get(key);\n\n if (candidates) {\n const match = candidates.find((c) => !matchedAIndices.has(c.idx));\n if (match) {\n matchedAIndices.add(match.idx);\n rows.push({\n indexA: match.idx,\n indexB: i,\n status: \"same\",\n rowA: match.row,\n rowB: compareData.rows[i]!,\n changedCols: new Set(),\n });\n } else {\n rows.push({\n indexA: null,\n indexB: i,\n status: \"added\",\n rowA: null,\n rowB: compareData.rows[i]!,\n changedCols: new Set(),\n });\n }\n } else {\n rows.push({\n indexA: null,\n indexB: i,\n status: \"added\",\n rowA: null,\n rowB: compareData.rows[i]!,\n changedCols: new Set(),\n });\n }\n }\n\n for (let i = 0; i < primaryData.rows.length; i++) {\n if (!matchedAIndices.has(i)) {\n rows.push({\n indexA: i,\n indexB: null,\n status: \"removed\",\n rowA: primaryData.rows[i]!,\n rowB: null,\n changedCols: new Set(),\n });\n }\n }\n } else if (effectiveMode === \"index\") {\n const maxLen = Math.max(primaryData.rows.length, compareData.rows.length);\n for (let i = 0; i < maxLen; i++) {\n const a = i < primaryData.rows.length ? primaryData.rows[i]! : null;\n const b = i < compareData.rows.length ? compareData.rows[i]! : null;\n\n if (!a) {\n rows.push({\n indexA: null,\n indexB: i,\n status: \"added\",\n rowA: null,\n rowB: b,\n changedCols: new Set(),\n });\n } else if (!b) {\n rows.push({\n indexA: i,\n indexB: null,\n status: \"removed\",\n rowA: a,\n rowB: null,\n changedCols: new Set(),\n });\n } else {\n const changedCols = getChangedCols(a, b);\n rows.push({\n indexA: i,\n indexB: i,\n status: changedCols.size > 0 ? \"changed\" : \"same\",\n rowA: a,\n rowB: b,\n changedCols,\n });\n }\n }\n } else {\n // Key-based matching\n const keyIdxA = primaryData.headers.indexOf(keyColumn);\n const keyIdxB = compareData.headers.indexOf(keyColumn);\n\n const aMap = new Map<string, { row: (string | number)[]; idx: number }>();\n const bMap = new Map<string, { row: (string | number)[]; idx: number }>();\n\n for (let i = 0; i < primaryData.rows.length; i++) {\n const key = String(primaryData.rows[i]![keyIdxA] ?? \"\");\n if (!aMap.has(key)) aMap.set(key, { row: primaryData.rows[i]!, idx: i });\n }\n for (let i = 0; i < compareData.rows.length; i++) {\n const key = String(compareData.rows[i]![keyIdxB] ?? \"\");\n if (!bMap.has(key)) bMap.set(key, { row: compareData.rows[i]!, idx: i });\n }\n\n const processedBKeys = new Set<string>();\n\n for (const [key, aEntry] of aMap) {\n const bEntry = bMap.get(key);\n if (bEntry) {\n processedBKeys.add(key);\n const changedCols = getChangedCols(aEntry.row, bEntry.row);\n rows.push({\n indexA: aEntry.idx,\n indexB: bEntry.idx,\n status: changedCols.size > 0 ? \"changed\" : \"same\",\n rowA: aEntry.row,\n rowB: bEntry.row,\n changedCols,\n });\n } else {\n rows.push({\n indexA: aEntry.idx,\n indexB: null,\n status: \"removed\",\n rowA: aEntry.row,\n rowB: null,\n changedCols: new Set(),\n });\n }\n }\n\n for (const [key, bEntry] of bMap) {\n if (!processedBKeys.has(key)) {\n rows.push({\n indexA: null,\n indexB: bEntry.idx,\n status: \"added\",\n rowA: null,\n rowB: bEntry.row,\n changedCols: new Set(),\n });\n }\n }\n }\n\n const counts: DiffCounts = {\n same: rows.filter((r) => r.status === \"same\").length,\n changed: rows.filter((r) => r.status === \"changed\").length,\n added: rows.filter((r) => r.status === \"added\").length,\n removed: rows.filter((r) => r.status === \"removed\").length,\n };\n\n return { commonHeaders, onlyInA, onlyInB, rows, counts };\n}\n","import { generateObject, generateText, streamText } from \"ai\";\nimport { z } from \"zod\";\nimport type { TabularData, ChartConfig } from \"./types\";\nimport type { ModelInput } from \"./ai\";\nimport { summarizeTabularData, getAIErrorMessage, resolveModel } from \"./ai\";\nimport { suggestCharts } from \"./ai\";\n\n// ============ Schemas ============\n\nconst DataSummarySchema = z.object({\n summary: z.string(),\n keyInsights: z.array(z.string()),\n dataQuality: z.string(),\n});\n\nconst AnomalySchema = z.object({\n row: z.number(),\n column: z.string(),\n value: z.string(),\n issue: z.string(),\n severity: z.enum([\"low\", \"medium\", \"high\"]),\n});\n\nconst AnomaliesResponseSchema = z.object({\n anomalies: z.array(AnomalySchema),\n});\n\n// ============ Result Types ============\n\nexport interface DataSummaryResult {\n summary: string;\n keyInsights: string[];\n dataQuality: string;\n}\n\nexport interface AnomalyResult {\n row: number;\n column: string;\n value: string;\n issue: string;\n severity: \"low\" | \"medium\" | \"high\";\n}\n\nexport interface AnalysisResult {\n summary: DataSummaryResult;\n anomalies: AnomalyResult[];\n charts: ChartConfig[];\n}\n\n// ============ Prompts ============\n\nconst summarySystemPrompt = (\n language?: string,\n) => `You are a data analyst.${language ? ` Respond in ${language}.` : \"\"}\n\nAnalyze the provided CSV data summary and provide:\n1. A comprehensive summary of what this dataset represents (2-3 sentences)\n2. 3-5 key insights or patterns you notice\n3. An assessment of data quality (completeness, consistency)`;\n\nconst anomalySystemPrompt = (\n language?: string,\n) => `You are a data quality expert.${language ? ` Respond in ${language}.` : \"\"}\n\nAnalyze the provided CSV data and identify anomalies, outliers, or suspicious data points.\n\nFor each anomaly found, provide:\n1. Row number (1-indexed, excluding header)\n2. Column name\n3. The problematic value\n4. Description of the issue\n5. Severity (low, medium, high)\n\nLook for:\n- Missing or empty values where data is expected\n- Values that don't match the expected type\n- Outliers (extremely high or low values)\n- Inconsistent formatting\n- Invalid dates or formats\n\nAnalyze ALL rows provided. Return empty array if no anomalies found.`;\n\nconst questionSystemPrompt = (\n language?: string,\n) =>\n `You are a data analysis expert.${language ? ` Respond in ${language}.` : \"\"}\\n\\nThe user will ask questions about a CSV dataset. Respond clearly and precisely.`;\n\n// ============ Helper ============\n\nfunction escapeCSVField(value: string): string {\n if (\n value.includes(\",\") ||\n value.includes('\"') ||\n value.includes(\"\\n\") ||\n value.includes(\"\\r\")\n ) {\n return `\"${value.replace(/\"/g, '\"\"')}\"`;\n }\n return value;\n}\n\nfunction buildSampleCSV(data: TabularData, maxRows = 50): string {\n const header = data.headers.map(escapeCSVField).join(\",\");\n const rows = data.rows\n .slice(0, maxRows)\n .map((row) => row.map(escapeCSVField).join(\",\"))\n .join(\"\\n\");\n return `${header}\\n${rows}`;\n}\n\n// ============ Individual Functions ============\n\nexport interface SummarizeDataOptions {\n model: ModelInput;\n data: TabularData;\n dataSummary?: string;\n language?: string;\n temperature?: number;\n /** AbortSignal to cancel the request */\n signal?: AbortSignal;\n}\n\n/**\n * Generate an AI summary of tabular data.\n *\n * @example\n * ```ts\n * const result = await summarizeData({\n * model: { apiKey: \"sk-...\", model: \"gpt-4o\" },\n * data: myData,\n * });\n * console.log(result.summary);\n * console.log(result.keyInsights);\n * console.log(result.dataQuality);\n * ```\n */\nexport async function summarizeData(\n options: SummarizeDataOptions,\n): Promise<DataSummaryResult> {\n const { data, language, temperature = 0.5, signal } = options;\n const dataSummary = options.dataSummary ?? summarizeTabularData(data);\n\n try {\n const model = resolveModel(options.model);\n\n const { object } = await generateObject({\n model,\n schema: DataSummarySchema,\n system: summarySystemPrompt(language),\n prompt: `Here is the data to analyze:\\n\\n${dataSummary}`,\n temperature,\n ...(signal && { abortSignal: signal }),\n });\n\n return {\n summary: object.summary,\n keyInsights: object.keyInsights,\n dataQuality: object.dataQuality,\n };\n } catch (error) {\n throw new Error(getAIErrorMessage(error));\n }\n}\n\nexport interface DetectAnomaliesOptions {\n model: ModelInput;\n data: TabularData;\n dataSummary?: string;\n /** Max rows to send for analysis (default: 50) */\n maxRows?: number;\n language?: string;\n temperature?: number;\n /** AbortSignal to cancel the request */\n signal?: AbortSignal;\n}\n\n/**\n * Detect anomalies in tabular data using AI.\n *\n * @example\n * ```ts\n * const anomalies = await detectAnomalies({\n * model: { apiKey: \"sk-...\", model: \"gpt-4o\" },\n * data: myData,\n * });\n * anomalies.forEach(a => console.log(`Row ${a.row}: ${a.issue}`));\n * ```\n */\nexport async function detectAnomalies(\n options: DetectAnomaliesOptions,\n): Promise<AnomalyResult[]> {\n const { data, maxRows = 50, language, temperature = 0.3, signal } = options;\n const dataSummary = options.dataSummary ?? summarizeTabularData(data);\n const sampleCSV = buildSampleCSV(data, maxRows);\n\n try {\n const model = resolveModel(options.model);\n\n const { object } = await generateObject({\n model,\n schema: AnomaliesResponseSchema,\n system: anomalySystemPrompt(language),\n prompt: `Data summary:\\n${dataSummary}\\n\\nData to analyze (CSV format):\\n${sampleCSV}`,\n temperature,\n ...(signal && { abortSignal: signal }),\n });\n\n return object.anomalies;\n } catch (error) {\n throw new Error(getAIErrorMessage(error));\n }\n}\n\nexport interface AskAboutDataOptions {\n model: ModelInput;\n data: TabularData;\n question: string;\n dataSummary?: string;\n /** Previous conversation messages for context */\n history?: Array<{ prompt: string; response: string }>;\n language?: string;\n temperature?: number;\n /** AbortSignal to cancel the request */\n signal?: AbortSignal;\n}\n\n/**\n * Ask a question about the data and get a text response.\n *\n * @example\n * ```ts\n * const answer = await askAboutData({\n * model: { apiKey: \"sk-...\", model: \"gpt-4o\" },\n * data: myData,\n * question: \"What is the average revenue by category?\",\n * });\n * console.log(answer);\n * ```\n */\nexport async function askAboutData(\n options: AskAboutDataOptions,\n): Promise<string> {\n const { data, question, history = [], language, temperature = 0.5, signal } = options;\n const dataSummary = options.dataSummary ?? summarizeTabularData(data);\n\n try {\n const model = resolveModel(options.model);\n\n const historyText = history\n .map((item) => `User: ${item.prompt}\\nAI: ${item.response}`)\n .join(\"\\n\\n\");\n const contextPrompt = historyText\n ? `Previous conversation history:\\n${historyText}\\n\\n`\n : \"\";\n\n const { text } = await generateText({\n model,\n system: questionSystemPrompt(language),\n prompt: `Here is the data:\\n\\n${dataSummary}\\n\\n${contextPrompt}User question: ${question}`,\n temperature,\n ...(signal && { abortSignal: signal }),\n });\n\n return text;\n } catch (error) {\n throw new Error(getAIErrorMessage(error));\n }\n}\n\nexport interface StreamAskAboutDataOptions extends Omit<AskAboutDataOptions, \"signal\"> {\n onChunk: (chunk: string) => void;\n onComplete: (fullText: string) => void;\n /** AbortSignal to cancel the stream */\n signal?: AbortSignal;\n}\n\n/**\n * Ask a question with streaming response.\n *\n * @example\n * ```ts\n * await streamAskAboutData({\n * model: { apiKey: \"sk-...\", model: \"gpt-4o\" },\n * data: myData,\n * question: \"What trends do you see?\",\n * onChunk: (chunk) => process.stdout.write(chunk),\n * onComplete: (full) => console.log(\"\\nDone:\", full.length, \"chars\"),\n * });\n * ```\n */\nexport async function streamAskAboutData(\n options: StreamAskAboutDataOptions,\n): Promise<void> {\n const {\n data,\n question,\n history = [],\n language,\n temperature = 0.5,\n signal,\n onChunk,\n onComplete,\n } = options;\n const dataSummary = options.dataSummary ?? summarizeTabularData(data);\n\n try {\n const model = resolveModel(options.model);\n\n const historyText = history\n .map((item) => `User: ${item.prompt}\\nAI: ${item.response}`)\n .join(\"\\n\\n\");\n const contextPrompt = historyText\n ? `Previous conversation history:\\n${historyText}\\n\\n`\n : \"\";\n\n let streamError: Error | null = null;\n\n const result = streamText({\n model,\n system: questionSystemPrompt(language),\n prompt: `Here is the data:\\n\\n${dataSummary}\\n\\n${contextPrompt}User question: ${question}`,\n temperature,\n ...(signal && { abortSignal: signal }),\n onError: ({ error }) => {\n streamError =\n error instanceof Error ? error : new Error(String(error));\n },\n });\n\n let fullText = \"\";\n\n for await (const textPart of result.textStream) {\n fullText += textPart;\n onChunk(textPart);\n }\n\n if (streamError) throw streamError;\n\n const finishReason = await result.finishReason;\n if (finishReason === \"error\") {\n throw new Error(\"The AI model encountered an error while generating the response.\");\n }\n\n onComplete(fullText);\n } catch (error) {\n throw new Error(getAIErrorMessage(error));\n }\n}\n\n// ============ Full Pipeline ============\n\nexport interface AnalyzeOptions {\n model: ModelInput;\n data: TabularData;\n dataSummary?: string;\n language?: string;\n /** Set to false to skip anomaly detection (default: true) */\n detectAnomalies?: boolean;\n /** Set to false to skip chart suggestions (default: true) */\n suggestCharts?: boolean;\n /** AbortSignal to cancel all parallel requests */\n signal?: AbortSignal;\n}\n\n/**\n * Run a complete AI analysis on tabular data in one call.\n * Returns summary, anomalies, and chart suggestions.\n *\n * @example\n * ```ts\n * import { analyzeData, ChartDisplay } from \"csv-charts-ai\";\n *\n * const result = await analyzeData({\n * model: { apiKey: \"sk-...\", model: \"gpt-4o\" },\n * data: myCSVData,\n * });\n *\n * console.log(result.summary.keyInsights);\n * console.log(`Found ${result.anomalies.length} anomalies`);\n *\n * // Render charts\n * <ChartDisplay data={myCSVData} charts={result.charts} />\n * ```\n */\nexport async function analyzeData(\n options: AnalyzeOptions,\n): Promise<AnalysisResult> {\n const {\n data,\n language,\n signal,\n detectAnomalies: runAnomalies = true,\n suggestCharts: runCharts = true,\n } = options;\n const dataSummary = options.dataSummary ?? summarizeTabularData(data);\n\n // Run all in parallel\n const [summary, anomalies, charts] = await Promise.all([\n summarizeData({ model: options.model, data, dataSummary, language, signal }),\n runAnomalies\n ? detectAnomalies({ model: options.model, data, dataSummary, language, signal })\n : Promise.resolve([]),\n runCharts\n ? suggestCharts({ model: options.model, data, dataSummary, language, signal })\n : Promise.resolve([]),\n ]);\n\n return { summary, anomalies, charts };\n}\n\n// ============ Question Suggestions ============\n\nconst questionsSystemPrompt = (\n language?: string,\n) => `You are a data analysis expert.${language ? ` Respond in ${language}.` : \"\"}\n\nGiven a dataset summary, suggest insightful questions that a user could ask to better understand their data. Focus on:\n- Trends and patterns\n- Comparisons and rankings\n- Correlations between columns\n- Outliers and anomalies\n- Actionable business insights\n\nEach question should be specific to the data columns available.`;\n\nconst QuestionsResponseSchema = z.object({\n questions: z\n .array(\n z.object({\n question: z.string().describe(\"The question to ask about the data\"),\n category: z\n .enum([\"trend\", \"comparison\", \"correlation\", \"anomaly\", \"insight\"])\n .describe(\"Category of the question\"),\n }),\n )\n .describe(\"5-8 suggested questions\"),\n});\n\nexport interface SuggestQuestionsOptions {\n model: ModelInput;\n data: TabularData;\n dataSummary?: string;\n language?: string;\n /** Number of questions to suggest (default: 6) */\n count?: number;\n temperature?: number;\n /** AbortSignal to cancel the request */\n signal?: AbortSignal;\n}\n\nexport interface SuggestedQuestion {\n question: string;\n category: \"trend\" | \"comparison\" | \"correlation\" | \"anomaly\" | \"insight\";\n}\n\n/**\n * Suggest interesting questions a user could ask about their data.\n * Great for onboarding users who don't know where to start with their dataset.\n *\n * @example\n * ```ts\n * const questions = await suggestQuestions({\n * model: { apiKey: \"sk-...\", model: \"gpt-4o\" },\n * data: myData,\n * });\n *\n * questions.forEach(q => console.log(`[${q.category}] ${q.question}`));\n * // [trend] How has revenue changed over the last 6 months?\n * // [comparison] Which product category generates the most revenue?\n * // [correlation] Is there a relationship between price and quantity sold?\n * ```\n */\nexport async function suggestQuestions(\n options: SuggestQuestionsOptions,\n): Promise<SuggestedQuestion[]> {\n const { data, language, count = 6, temperature = 0.7, signal } = options;\n const dataSummary = options.dataSummary ?? summarizeTabularData(data);\n\n try {\n const model = resolveModel(options.model);\n\n const { object } = await generateObject({\n model,\n schema: QuestionsResponseSchema,\n system: questionsSystemPrompt(language),\n prompt: `Here is the dataset to analyze:\\n\\n${dataSummary}\\n\\nSuggest ${count} insightful questions about this data.`,\n temperature,\n ...(signal && { abortSignal: signal }),\n });\n\n return object.questions.slice(0, count);\n } catch (error) {\n throw new Error(getAIErrorMessage(error));\n }\n}\n"],"mappings":"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","names":["BOOLEAN_VALUES","DATE_PATTERNS","inferColumnType","generateObject","z","z","generateObject"]}
1
+ {"version":3,"sources":["../package.json","../src/version.ts","../src/providers.ts","../src/csv-parser.ts","../src/xlsx-parser.ts","../src/processChartData.ts","../src/constants.ts","../src/types.ts","../src/ai.ts","../src/csv-diff.ts","../src/analyze.ts"],"sourcesContent":["{\n \"name\": \"csv-charts-ai\",\n \"version\": \"1.10.0\",\n \"description\": \"AI-powered CSV analysis, chart generation, and interactive visualization. Parse CSV, detect anomalies, suggest charts, and ask questions about your data using any LLM provider.\",\n \"type\": \"module\",\n \"license\": \"MIT\",\n \"author\": \"maxgfr\",\n \"homepage\": \"https://github.com/maxgfr/csv-ai-analyzer/tree/main/packages/csv-charts-ai#readme\",\n \"bugs\": {\n \"url\": \"https://github.com/maxgfr/csv-ai-analyzer/issues\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/maxgfr/csv-ai-analyzer\",\n \"directory\": \"packages/csv-charts-ai\"\n },\n \"keywords\": [\n \"csv\",\n \"ai\",\n \"charts\",\n \"data-analysis\",\n \"visualization\",\n \"llm\",\n \"openai\",\n \"anthropic\",\n \"recharts\",\n \"tabular-data\",\n \"anomaly-detection\",\n \"chart-generation\"\n ],\n \"main\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"import\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\"\n },\n \"./charts\": {\n \"import\": \"./dist/charts.js\",\n \"types\": \"./dist/charts.d.ts\"\n }\n },\n \"files\": [\n \"dist\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"test:coverage\": \"vitest run --coverage\"\n },\n \"peerDependencies\": {\n \"react\": \"^18.0.0 || ^19.0.0\",\n \"recharts\": \"^3.0.0\",\n \"lucide-react\": \">=0.400.0\",\n \"@ai-sdk/openai\": \"^3.0.0\",\n \"@ai-sdk/anthropic\": \"^3.0.0\",\n \"@ai-sdk/google\": \"^3.0.0\",\n \"@ai-sdk/mistral\": \"^3.0.0\"\n },\n \"peerDependenciesMeta\": {\n \"react\": {\n \"optional\": true\n },\n \"recharts\": {\n \"optional\": true\n },\n \"lucide-react\": {\n \"optional\": true\n },\n \"@ai-sdk/openai\": {\n \"optional\": true\n },\n \"@ai-sdk/anthropic\": {\n \"optional\": true\n },\n \"@ai-sdk/google\": {\n \"optional\": true\n },\n \"@ai-sdk/mistral\": {\n \"optional\": true\n }\n },\n \"dependencies\": {\n \"ai\": \"^6.0.134\",\n \"zod\": \"^4.1.13\",\n \"read-excel-file\": \"^7.0.2\"\n },\n \"devDependencies\": {\n \"@types/react\": \"^19.2.7\",\n \"@vitest/coverage-v8\": \"^4.1.0\",\n \"lucide-react\": \"^0.556.0\",\n \"react\": \"^19.2.4\",\n \"recharts\": \"^3.5.1\",\n \"tsup\": \"^8.5.0\",\n \"typescript\": \"^5.9.3\",\n \"vitest\": \"^4.1.0\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n }\n}\n","// Read version from package.json at build time (inlined by tsup)\nimport pkg from \"../package.json\" with { type: \"json\" };\nexport const VERSION: string = pkg.version;\n","import type { LanguageModel } from \"ai\";\n\n// ============ Types ============\n\n/** Configuration passed to a provider factory when creating a model. */\nexport interface ProviderConfig {\n apiKey: string;\n model: string;\n baseURL?: string;\n headers?: Record<string, string>;\n}\n\n/** A function that creates a LanguageModel from configuration. */\nexport type ProviderFactory = (config: ProviderConfig) => LanguageModel;\n\n// ============ Internal registry ============\n\nconst registry = new Map<string, ProviderFactory>();\n\n/** Known aliases: npm package names → simple provider names. */\nconst ALIASES: Record<string, string> = {\n \"@ai-sdk/openai\": \"openai\",\n \"@ai-sdk/anthropic\": \"anthropic\",\n \"@ai-sdk/google\": \"google\",\n \"@ai-sdk/mistral\": \"mistral\",\n};\n\nfunction resolveAlias(name: string): string {\n return ALIASES[name] ?? name;\n}\n\n// ============ Public API ============\n\n/**\n * Register a provider factory under a given name.\n *\n * The name can be a simple identifier (`\"openai\"`) or an npm package name\n * (`\"@ai-sdk/openai\"`) — aliases are resolved automatically so both map\n * to the same slot.\n *\n * @example\n * ```ts\n * import { registerProvider, fromSDK } from \"csv-charts-ai\";\n * import { createOpenAI } from \"@ai-sdk/openai\";\n * import { createAnthropic } from \"@ai-sdk/anthropic\";\n *\n * registerProvider(\"openai\", fromSDK(createOpenAI));\n * registerProvider(\"anthropic\", fromSDK(createAnthropic));\n *\n * // Custom provider with full control\n * registerProvider(\"my-llm\", (config) => {\n * return myCustomSDK.createModel(config.apiKey, config.model);\n * });\n * ```\n */\nexport function registerProvider(name: string, factory: ProviderFactory): void {\n const resolved = resolveAlias(name);\n registry.set(resolved, factory);\n}\n\n/**\n * Register multiple providers at once.\n *\n * @example\n * ```ts\n * registerProviders({\n * openai: fromSDK(createOpenAI),\n * anthropic: fromSDK(createAnthropic),\n * google: fromSDK(createGoogleGenerativeAI),\n * });\n * ```\n */\nexport function registerProviders(\n providers: Record<string, ProviderFactory>,\n): void {\n for (const [name, factory] of Object.entries(providers)) {\n registerProvider(name, factory);\n }\n}\n\n/**\n * Wrap an AI SDK provider creator into a {@link ProviderFactory}.\n *\n * All `@ai-sdk/*` packages export a creator following the pattern:\n * ```\n * createXxx(options) → provider(modelName) → LanguageModel\n * ```\n *\n * This helper adapts that two-step pattern into a single-step\n * `ProviderFactory`.\n *\n * @example\n * ```ts\n * import { createOpenAI } from \"@ai-sdk/openai\";\n * import { fromSDK, registerProvider } from \"csv-charts-ai\";\n *\n * registerProvider(\"openai\", fromSDK(createOpenAI));\n * ```\n */\nexport function fromSDK(\n // Intentionally loose: every @ai-sdk/* creator has a slightly different\n // type signature, but they all follow (options) => (model) => LanguageModel.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n creator: (options: any) => any,\n): ProviderFactory {\n return (config: ProviderConfig): LanguageModel => {\n const provider = creator({\n apiKey: config.apiKey,\n ...(config.baseURL && { baseURL: config.baseURL }),\n ...(config.headers && { headers: config.headers }),\n });\n return provider(config.model) as LanguageModel;\n };\n}\n\n/** Get a provider by name, or `undefined` if not registered. */\nexport function getProvider(name: string): ProviderFactory | undefined {\n return registry.get(resolveAlias(name));\n}\n\n/** Check whether a provider is registered. */\nexport function hasProvider(name: string): boolean {\n return registry.has(resolveAlias(name));\n}\n\n/**\n * Remove all registered providers.\n * Useful for testing — not intended for production use.\n */\nexport function clearProviders(): void {\n registry.clear();\n}\n\n/**\n * Get a registered provider or throw with a helpful error.\n * @internal used by `createModel` / `createAppModel`.\n */\nexport function requireProvider(name: string): ProviderFactory {\n const resolved = resolveAlias(name);\n const factory = registry.get(resolved);\n\n if (!factory) {\n const npmHint: Record<string, string> = {\n openai: \"@ai-sdk/openai\",\n anthropic: \"@ai-sdk/anthropic\",\n google: \"@ai-sdk/google\",\n mistral: \"@ai-sdk/mistral\",\n };\n\n const pkg = npmHint[resolved];\n const example = pkg\n ? ` import { registerProvider, fromSDK } from \"csv-charts-ai\";\\n` +\n ` import { create... } from \"${pkg}\";\\n` +\n ` registerProvider(\"${resolved}\", fromSDK(create...));`\n : ` import { registerProvider } from \"csv-charts-ai\";\\n` +\n ` registerProvider(\"${resolved}\", (config) => /* your LanguageModel */);`;\n\n throw new Error(\n `Provider \"${resolved}\" is not registered.\\n\\n` +\n `Register it before calling AI functions:\\n\\n${example}\\n`,\n );\n }\n\n return factory;\n}\n","import type { TabularData } from \"./types\";\n\nexport interface ParseCSVOptions {\n /** Column delimiter. Auto-detected if omitted (supports , ; \\t |). */\n delimiter?: string;\n /** Whether the first row is a header row (default: true). */\n hasHeader?: boolean;\n /** Skip empty lines (default: true). */\n skipEmpty?: boolean;\n}\n\n/**\n * Parse a CSV string into TabularData with automatic delimiter detection\n * and column type inference.\n *\n * Handles quoted fields (RFC 4180), escaped quotes, and mixed line endings.\n *\n * @example\n * ```ts\n * import { parseCSV } from \"csv-charts-ai\";\n *\n * const data = parseCSV(`name,age,city\n * Alice,30,\"New York\"\n * Bob,25,Paris`);\n *\n * console.log(data.headers); // [\"name\", \"age\", \"city\"]\n * console.log(data.rowCount); // 2\n * console.log(data.columns); // [{ name: \"name\", type: \"string\", ... }, ...]\n * ```\n *\n * @example\n * ```ts\n * // Auto-detects semicolon delimiter\n * const data = parseCSV(\"nom;age;ville\\nAlice;30;Paris\");\n *\n * // Explicit delimiter\n * const data = parseCSV(tsv, { delimiter: \"\\t\" });\n *\n * // No header row\n * const data = parseCSV(raw, { hasHeader: false });\n * ```\n *\n * For very complex CSV files (multi-line quoted fields with nested newlines,\n * exotic encodings), consider using PapaParse and passing the result as\n * TabularData directly to the AI functions.\n */\nexport function parseCSV(\n csv: string,\n options: ParseCSVOptions = {},\n): TabularData {\n const { hasHeader = true, skipEmpty = true } = options;\n\n // Normalize line endings and strip BOM\n const normalized = csv\n .replace(/^\\uFEFF/, \"\")\n .replace(/\\r\\n/g, \"\\n\")\n .replace(/\\r/g, \"\\n\")\n .trim();\n\n if (normalized.length === 0) {\n return { headers: [], rows: [], columns: [], rowCount: 0 };\n }\n\n const delimiter = options.delimiter ?? detectDelimiter(normalized);\n const allRows = parseRows(normalized, delimiter, skipEmpty);\n\n if (allRows.length === 0) {\n return { headers: [], rows: [], columns: [], rowCount: 0 };\n }\n\n // Normalize row lengths to match the first row\n const expectedCols = allRows[0]!.length;\n const normalizedRows = allRows.map((row) => {\n if (row.length < expectedCols) {\n return [...row, ...Array<string>(expectedCols - row.length).fill(\"\")];\n }\n return row.slice(0, expectedCols);\n });\n\n const headers = hasHeader\n ? normalizedRows[0]!\n : normalizedRows[0]!.map((_, i) => `Column ${i + 1}`);\n const dataRows = hasHeader ? normalizedRows.slice(1) : normalizedRows;\n\n const columns = headers.map((name, index) => ({\n name: name.trim(),\n type: inferColumnType(dataRows, index),\n index,\n }));\n\n return {\n headers: headers.map((h) => h.trim()),\n rows: dataRows,\n columns,\n rowCount: dataRows.length,\n };\n}\n\n// ============ Delimiter Detection ============\n\nfunction detectDelimiter(csv: string): string {\n const firstLines = csv.split(\"\\n\").slice(0, 5);\n const candidates: Record<string, number[]> = {\n \",\": [],\n \";\": [],\n \"\\t\": [],\n \"|\": [],\n };\n\n for (const line of firstLines) {\n let inQuotes = false;\n const counts: Record<string, number> = { \",\": 0, \";\": 0, \"\\t\": 0, \"|\": 0 };\n for (const char of line) {\n if (char === '\"') {\n inQuotes = !inQuotes;\n } else if (!inQuotes && char in counts) {\n counts[char]!++;\n }\n }\n for (const [delim, count] of Object.entries(counts)) {\n candidates[delim]!.push(count);\n }\n }\n\n // Best delimiter: consistent count across lines AND highest count\n let best = \",\";\n let bestScore = -1;\n\n for (const [delim, counts] of Object.entries(candidates)) {\n if (counts.length === 0 || counts[0] === 0) continue;\n\n const allSame = counts.every((c) => c === counts[0]);\n const avgCount = counts.reduce((a, b) => a + b, 0) / counts.length;\n // Prefer consistency, then count\n const score = (allSame ? 1000 : 0) + avgCount;\n\n if (score > bestScore) {\n bestScore = score;\n best = delim;\n }\n }\n\n return best;\n}\n\n// ============ Row Parsing (RFC 4180) ============\n\nfunction parseRows(\n csv: string,\n delimiter: string,\n skipEmpty: boolean,\n): string[][] {\n const rows: string[][] = [];\n let current: string[] = [];\n let field = \"\";\n let inQuotes = false;\n\n for (let i = 0; i < csv.length; i++) {\n const char = csv[i]!;\n\n if (inQuotes) {\n if (char === '\"') {\n if (i + 1 < csv.length && csv[i + 1] === '\"') {\n field += '\"';\n i++; // skip escaped quote\n } else {\n inQuotes = false;\n }\n } else {\n field += char;\n }\n } else {\n if (char === '\"') {\n inQuotes = true;\n } else if (char === delimiter) {\n current.push(field);\n field = \"\";\n } else if (char === \"\\n\") {\n current.push(field);\n if (!skipEmpty || current.some((c) => c.trim() !== \"\")) {\n rows.push(current);\n }\n current = [];\n field = \"\";\n } else {\n field += char;\n }\n }\n }\n\n // Last field/row\n current.push(field);\n if (!skipEmpty || current.some((c) => c.trim() !== \"\")) {\n rows.push(current);\n }\n\n return rows;\n}\n\n// ============ Type Inference ============\n\nconst BOOLEAN_VALUES = new Set([\n \"true\",\n \"false\",\n \"yes\",\n \"no\",\n \"vrai\",\n \"faux\",\n \"oui\",\n \"non\",\n]);\n\nconst DATE_PATTERNS = [\n /^\\d{4}-\\d{2}-\\d{2}$/, // 2024-01-15\n /^\\d{2}\\/\\d{2}\\/\\d{4}$/, // 01/15/2024\n /^\\d{2}-\\d{2}-\\d{4}$/, // 01-15-2024\n /^\\d{4}\\/\\d{2}\\/\\d{2}$/, // 2024/01/15\n /^\\d{4}-\\d{2}-\\d{2}T/, // ISO 8601\n /^\\d{2}\\.\\d{2}\\.\\d{4}$/, // 15.01.2024\n /^\\w{3,9}\\s\\d{1,2},?\\s\\d{4}$/, // Jan 15, 2024 / January 15, 2024\n];\n\nfunction inferColumnType(\n rows: string[][],\n colIndex: number,\n): \"string\" | \"number\" | \"date\" | \"boolean\" {\n const sampleSize = Math.min(rows.length, 100);\n let numbers = 0;\n let dates = 0;\n let booleans = 0;\n let total = 0;\n\n for (let i = 0; i < sampleSize; i++) {\n const value = rows[i]?.[colIndex]?.trim() ?? \"\";\n if (value === \"\") continue;\n total++;\n\n if (BOOLEAN_VALUES.has(value.toLowerCase())) {\n booleans++;\n }\n\n // Check number (handle \"1,234.56\" and \"1 234.56\" formats)\n const cleaned = value.replace(/[\\s,]/g, \"\");\n if (cleaned !== \"\" && !isNaN(Number(cleaned))) {\n numbers++;\n }\n\n if (DATE_PATTERNS.some((p) => p.test(value))) {\n dates++;\n }\n }\n\n if (total === 0) return \"string\";\n\n const threshold = 0.8;\n // Check booleans first (only if NOT also numbers)\n if (booleans / total >= threshold && numbers / total < 0.5) return \"boolean\";\n if (dates / total >= threshold) return \"date\";\n if (numbers / total >= threshold) return \"number\";\n return \"string\";\n}\n","import type { TabularData } from \"./types\";\n\nexport interface ParseXLSXOptions {\n /** Whether the first row is a header row (default: true). */\n hasHeader?: boolean;\n /** Skip empty lines (default: true). */\n skipEmpty?: boolean;\n}\n\n// ============ Type Inference (shared with csv-parser) ============\n\nconst BOOLEAN_VALUES = new Set([\n \"true\",\n \"false\",\n \"yes\",\n \"no\",\n \"vrai\",\n \"faux\",\n \"oui\",\n \"non\",\n]);\n\nconst DATE_PATTERNS = [\n /^\\d{4}-\\d{2}-\\d{2}$/,\n /^\\d{2}\\/\\d{2}\\/\\d{4}$/,\n /^\\d{2}-\\d{2}-\\d{4}$/,\n /^\\d{4}\\/\\d{2}\\/\\d{2}$/,\n /^\\d{4}-\\d{2}-\\d{2}T/,\n /^\\d{2}\\.\\d{2}\\.\\d{4}$/,\n /^\\w{3,9}\\s\\d{1,2},?\\s\\d{4}$/,\n];\n\nfunction inferColumnType(\n rows: string[][],\n colIndex: number,\n): \"string\" | \"number\" | \"date\" | \"boolean\" {\n const sampleSize = Math.min(rows.length, 100);\n let numbers = 0;\n let dates = 0;\n let booleans = 0;\n let total = 0;\n\n for (let i = 0; i < sampleSize; i++) {\n const value = rows[i]?.[colIndex]?.trim() ?? \"\";\n if (value === \"\") continue;\n total++;\n\n if (BOOLEAN_VALUES.has(value.toLowerCase())) booleans++;\n\n const cleaned = value.replace(/[\\s,]/g, \"\");\n if (cleaned !== \"\" && !isNaN(Number(cleaned))) numbers++;\n\n if (DATE_PATTERNS.some((p) => p.test(value))) dates++;\n }\n\n if (total === 0) return \"string\";\n const threshold = 0.8;\n if (booleans / total >= threshold && numbers / total < 0.5) return \"boolean\";\n if (dates / total >= threshold) return \"date\";\n if (numbers / total >= threshold) return \"number\";\n return \"string\";\n}\n\n// ============ Core conversion (universal, no dependencies) ============\n\n/**\n * Convert raw XLSX rows (as returned by `read-excel-file`) into TabularData.\n *\n * This function is **universal** — it works in Node.js, browsers, and web workers.\n * You read the file yourself with `read-excel-file` (or any other XLSX parser)\n * and pass the resulting rows here.\n *\n * @example\n * ```ts\n * // Node.js\n * import readXlsxFile from \"read-excel-file/node\";\n * import { convertXLSXRows } from \"csv-charts-ai\";\n *\n * const rows = await readXlsxFile(\"data.xlsx\");\n * const data = convertXLSXRows(rows);\n * ```\n *\n * @example\n * ```ts\n * // Browser\n * import readXlsxFile from \"read-excel-file/browser\";\n * import { convertXLSXRows } from \"csv-charts-ai\";\n *\n * const rows = await readXlsxFile(file);\n * const data = convertXLSXRows(rows);\n * ```\n */\nexport function convertXLSXRows(\n rawRows: (string | number | boolean | Date | null)[][],\n options: ParseXLSXOptions = {},\n): TabularData {\n const { hasHeader = true, skipEmpty = true } = options;\n\n // Convert all cells to strings\n let rows = rawRows.map((row) =>\n row.map((cell) => (cell != null ? String(cell) : \"\")),\n );\n\n if (skipEmpty) {\n rows = rows.filter((row) => row.some((cell) => cell.trim() !== \"\"));\n }\n\n if (rows.length === 0) {\n return { headers: [], rows: [], columns: [], rowCount: 0 };\n }\n\n const firstRow = rows[0]!;\n const headers = hasHeader\n ? firstRow.map((h, i) => h.trim() || `Column ${i + 1}`)\n : firstRow.map((_, i) => `Column ${i + 1}`);\n\n const dataRows = hasHeader ? rows.slice(1) : rows;\n\n // Normalize: ensure every row has exactly `headers.length` cells\n const normalizedRows = dataRows.map((row) =>\n headers.map((_, i) => row[i] ?? \"\"),\n );\n\n const columns = headers.map((name, index) => ({\n name,\n type: inferColumnType(normalizedRows, index),\n index,\n }));\n\n return { headers, rows: normalizedRows, columns, rowCount: normalizedRows.length };\n}\n\n// ============ Browser convenience ============\n\n/**\n * Parse an Excel (.xlsx) file into TabularData. **Browser only.**\n *\n * `read-excel-file` is bundled — no extra install needed.\n * Always reads the first sheet.\n *\n * @example\n * ```tsx\n * import { parseXLSX } from \"csv-charts-ai\";\n *\n * const handleFile = async (file: File) => {\n * const data = await parseXLSX(file);\n * console.log(data.headers, data.rowCount);\n * };\n * ```\n */\nexport async function parseXLSX(\n file: File,\n options: ParseXLSXOptions = {},\n): Promise<TabularData> {\n const mod = await import(\"read-excel-file/browser\");\n const result = await mod.default(file);\n const rawRows = result as (string | number | boolean | Date | null)[][];\n return convertXLSXRows(rawRows, options);\n}\n","import type {\n TabularData,\n ChartConfig,\n SortOrder,\n ChartDataPoint,\n} from \"./types\";\n\nexport interface ProcessedChartResult {\n data: ChartDataPoint[];\n seriesKeys: string[];\n yKey: string;\n}\n\nexport const processChartData = (\n data: TabularData,\n chart: ChartConfig,\n sortOrder: SortOrder = \"none\",\n limit = 20,\n): ChartDataPoint[] => {\n const result = processChartDataMultiSeries(data, chart, sortOrder, limit);\n return result.data;\n};\n\nexport const processChartDataMultiSeries = (\n data: TabularData,\n chart: ChartConfig,\n sortOrder: SortOrder = \"none\",\n limit = 20,\n): ProcessedChartResult => {\n let result: ChartDataPoint[] = [];\n\n // Find actual columns (case-insensitive match)\n const xColDef = data.columns.find(\n (c) => c.name.toLowerCase() === chart.xAxis.toLowerCase(),\n );\n const yColDef = data.columns.find(\n (c) => c.name.toLowerCase() === chart.yAxis.toLowerCase(),\n );\n const groupColDef = chart.groupBy\n ? data.columns.find(\n (c) => c.name.toLowerCase() === chart.groupBy!.toLowerCase(),\n )\n : undefined;\n\n if (!xColDef) return { data: [], seriesKeys: [], yKey: chart.yAxis };\n\n const xCol = xColDef.name;\n const xIdx = xColDef.index;\n\n // For count aggregation, we don't need a valid Y column - we just count occurrences\n const isCountMode = chart.aggregation === \"count\";\n const yCol = yColDef?.name ?? \"count\";\n const yIdx = yColDef?.index ?? -1;\n\n // GroupBy mode: create multi-series data (not supported for pie/scatter)\n const supportsGroupBy =\n chart.type !== \"pie\" && chart.type !== \"scatter\";\n if (\n supportsGroupBy &&\n groupColDef &&\n chart.aggregation &&\n chart.aggregation !== \"none\"\n ) {\n const groupIdx = groupColDef.index;\n const allGroups = new Set<string>();\n\n // Nested grouping: xVal -> groupVal -> stats\n const grouped = new Map<\n string,\n Map<string, { sum: number; count: number; min: number; max: number }>\n >();\n\n data.rows.forEach((row) => {\n const xVal = String(row[xIdx] ?? \"\").trim();\n const groupVal = String(row[groupIdx] ?? \"\").trim();\n if (!xVal || !groupVal) return;\n\n allGroups.add(groupVal);\n\n if (!grouped.has(xVal)) grouped.set(xVal, new Map());\n const xGroup = grouped.get(xVal)!;\n\n if (isCountMode) {\n const current = xGroup.get(groupVal) ?? {\n sum: 0,\n count: 0,\n min: 0,\n max: 0,\n };\n xGroup.set(groupVal, { ...current, count: current.count + 1 });\n } else if (yIdx >= 0) {\n const yVal = parseFloat(String(row[yIdx] ?? \"0\"));\n if (!isNaN(yVal)) {\n const current = xGroup.get(groupVal) ?? {\n sum: 0,\n count: 0,\n min: Infinity,\n max: -Infinity,\n };\n xGroup.set(groupVal, {\n sum: current.sum + yVal,\n count: current.count + 1,\n min: Math.min(current.min, yVal),\n max: Math.max(current.max, yVal),\n });\n }\n }\n });\n\n const seriesKeys = Array.from(allGroups).slice(0, 8); // max 8 series\n\n grouped.forEach((groupMap, xKey) => {\n const point: ChartDataPoint = { [xCol]: xKey };\n seriesKeys.forEach((groupKey) => {\n const stats = groupMap.get(groupKey);\n if (stats) {\n let value: number;\n switch (chart.aggregation) {\n case \"sum\":\n value = stats.sum;\n break;\n case \"avg\":\n value = stats.count > 0 ? stats.sum / stats.count : 0;\n break;\n case \"count\":\n value = stats.count;\n break;\n case \"min\":\n value = stats.min === Infinity ? 0 : stats.min;\n break;\n case \"max\":\n value = stats.max === -Infinity ? 0 : stats.max;\n break;\n default:\n value = stats.sum;\n }\n point[groupKey] = Math.round(value * 100) / 100;\n } else {\n point[groupKey] = 0;\n }\n });\n result.push(point);\n });\n\n // Sort by first series value or alphabetically\n if (sortOrder !== \"none\" && seriesKeys[0]) {\n const firstKey = seriesKeys[0];\n result.sort((a, b) => {\n const aVal = (a[firstKey] as number) ?? 0;\n const bVal = (b[firstKey] as number) ?? 0;\n return sortOrder === \"desc\" ? bVal - aVal : aVal - bVal;\n });\n }\n\n return {\n data: result.slice(0, limit),\n seriesKeys,\n yKey: yCol,\n };\n }\n\n // Standard single-series mode (existing logic)\n if (chart.aggregation && chart.aggregation !== \"none\") {\n const groups = new Map<\n string,\n { sum: number; count: number; min: number; max: number }\n >();\n\n data.rows.forEach((row) => {\n const xVal = String(row[xIdx] ?? \"\").trim();\n if (!xVal) return;\n\n if (isCountMode) {\n const current = groups.get(xVal) ?? {\n sum: 0,\n count: 0,\n min: 0,\n max: 0,\n };\n groups.set(xVal, {\n ...current,\n count: current.count + 1,\n });\n } else if (yIdx >= 0) {\n const yVal = parseFloat(String(row[yIdx] ?? \"0\"));\n if (!isNaN(yVal)) {\n const current = groups.get(xVal) ?? {\n sum: 0,\n count: 0,\n min: Infinity,\n max: -Infinity,\n };\n groups.set(xVal, {\n sum: current.sum + yVal,\n count: current.count + 1,\n min: Math.min(current.min, yVal),\n max: Math.max(current.max, yVal),\n });\n }\n }\n });\n\n groups.forEach((stats, key) => {\n let value: number;\n switch (chart.aggregation) {\n case \"sum\":\n value = stats.sum;\n break;\n case \"avg\":\n value = stats.count > 0 ? stats.sum / stats.count : 0;\n break;\n case \"count\":\n value = stats.count;\n break;\n case \"min\":\n value = stats.min === Infinity ? 0 : stats.min;\n break;\n case \"max\":\n value = stats.max === -Infinity ? 0 : stats.max;\n break;\n default:\n value = stats.sum;\n }\n result.push({ [xCol]: key, [yCol]: Math.round(value * 100) / 100 });\n });\n } else if (yIdx >= 0) {\n result = data.rows\n .slice(0, Math.min(limit * 2, data.rows.length))\n .map((row) => ({\n [xCol]: row[xIdx] ?? \"\",\n [yCol]: parseFloat(String(row[yIdx] ?? \"0\")),\n }))\n .filter((item) => !isNaN(item[yCol] as number));\n }\n\n // Apply sorting\n if (sortOrder !== \"none\") {\n result.sort((a, b) => {\n const aVal = a[yCol] as number;\n const bVal = b[yCol] as number;\n return sortOrder === \"desc\" ? bVal - aVal : aVal - bVal;\n });\n }\n\n return {\n data: result.slice(0, limit),\n seriesKeys: [],\n yKey: yCol,\n };\n};\n","export const COLORS = [\n \"#8b5cf6\", // Violet 500\n \"#06b6d4\", // Cyan 500\n \"#f43f5e\", // Rose 500\n \"#eab308\", // Yellow 500\n \"#10b981\", // Emerald 500\n \"#3b82f6\", // Blue 500\n \"#d946ef\", // Fuchsia 500\n \"#f97316\", // Orange 500\n];\n","export type ChartType = \"bar\" | \"line\" | \"pie\" | \"scatter\" | \"area\";\nexport type AggregationType =\n | \"sum\"\n | \"avg\"\n | \"count\"\n | \"min\"\n | \"max\"\n | \"none\";\n\nexport interface TabularData {\n headers: string[];\n rows: string[][];\n columns: {\n name: string;\n type: \"string\" | \"number\" | \"date\" | \"boolean\";\n index: number;\n }[];\n rowCount: number;\n}\n\nexport interface ChartConfig {\n id: string;\n type: ChartType;\n title: string;\n description: string;\n xAxis: string;\n yAxis: string;\n groupBy?: string;\n aggregation: AggregationType;\n dataConfig?: {\n xColumn: string;\n yColumn: string;\n groupColumn?: string;\n };\n}\n\nexport type SortOrder = \"none\" | \"asc\" | \"desc\";\nexport type ChartDataPoint = Record<string, string | number>;\n\n// Theme types\nexport interface ChartTheme {\n colors: string[];\n background: string;\n cardBackground: string;\n border: string;\n text: string;\n textMuted: string;\n textDimmed: string;\n gridStroke: string;\n tooltipBackground: string;\n tooltipBorder: string;\n accentPrimary: string;\n accentSecondary: string;\n accentSuccess: string;\n accentDanger: string;\n}\n\nexport const defaultDarkTheme: ChartTheme = {\n colors: [\n \"#8b5cf6\",\n \"#06b6d4\",\n \"#f43f5e\",\n \"#eab308\",\n \"#10b981\",\n \"#3b82f6\",\n \"#d946ef\",\n \"#f97316\",\n ],\n background: \"rgba(15, 23, 42, 0.5)\",\n cardBackground: \"rgba(255, 255, 255, 0.05)\",\n border: \"rgba(255, 255, 255, 0.1)\",\n text: \"#ffffff\",\n textMuted: \"#9ca3af\",\n textDimmed: \"#6b7280\",\n gridStroke: \"#374151\",\n tooltipBackground: \"#1f2937\",\n tooltipBorder: \"1px solid #374151\",\n accentPrimary: \"#8b5cf6\",\n accentSecondary: \"#06b6d4\",\n accentSuccess: \"#10b981\",\n accentDanger: \"#ef4444\",\n};\n\nexport const defaultLightTheme: ChartTheme = {\n colors: [\n \"#7c3aed\",\n \"#0891b2\",\n \"#e11d48\",\n \"#ca8a04\",\n \"#059669\",\n \"#2563eb\",\n \"#c026d3\",\n \"#ea580c\",\n ],\n background: \"#ffffff\",\n cardBackground: \"#f8fafc\",\n border: \"#e2e8f0\",\n text: \"#0f172a\",\n textMuted: \"#64748b\",\n textDimmed: \"#94a3b8\",\n gridStroke: \"#e2e8f0\",\n tooltipBackground: \"#ffffff\",\n tooltipBorder: \"1px solid #e2e8f0\",\n accentPrimary: \"#7c3aed\",\n accentSecondary: \"#0891b2\",\n accentSuccess: \"#059669\",\n accentDanger: \"#dc2626\",\n};\n","import { generateObject, type LanguageModel } from \"ai\";\nimport { z } from \"zod\";\nimport type { ChartConfig, TabularData } from \"./types\";\nimport { requireProvider } from \"./providers\";\n\n// ============ Input Validation Schemas ============\n\n/** Zod schema for simple API config (OpenAI-compatible endpoints) */\nexport const AIConfigSchema = z.object({\n /** API key for authentication */\n apiKey: z.string(),\n /** Model identifier (e.g. \"gpt-4o\", \"llama3\", \"mistral-large\") */\n model: z.string(),\n /** Custom base URL for non-OpenAI providers (Ollama, vLLM, Mistral, etc.) */\n baseURL: z.string().optional(),\n /** Provider name — must match a registered provider. Defaults to \"openai\". */\n provider: z.string().optional().default(\"openai\"),\n});\n\nexport type AIConfig = z.infer<typeof AIConfigSchema>;\n\n/** Zod schema for TabularData validation */\nexport const TabularDataSchema = z.object({\n headers: z.array(z.string()).min(1, \"Data must have at least one column\"),\n rows: z.array(z.array(z.string())),\n columns: z.array(\n z.object({\n name: z.string(),\n type: z.enum([\"string\", \"number\", \"date\", \"boolean\"]),\n index: z.number(),\n }),\n ),\n rowCount: z.number(),\n});\n\n/**\n * Extended config for multi-provider apps.\n * Supports provider selection via npm package name (e.g. \"@ai-sdk/anthropic\").\n */\nexport interface AppModelConfig {\n apiKey: string;\n model?: string;\n /** Provider npm package name (e.g. \"@ai-sdk/anthropic\", \"@ai-sdk/google\") */\n providerNpm?: string;\n /** Provider base API URL (for OpenAI-compatible endpoints) */\n providerApi?: string;\n /** Custom endpoint URL (takes priority over providerNpm) */\n customEndpoint?: string;\n /** Custom model name (takes priority over model) */\n customModel?: string;\n /** Custom headers to pass to the provider (e.g. Anthropic browser access header) */\n headers?: Record<string, string>;\n}\n\n/** Model input: either a simple config object, an app config, or a pre-built LanguageModel */\nexport type ModelInput = AIConfig | AppModelConfig | LanguageModel;\n\n// ============ Chart Output Schemas ============\n\nconst ChartSuggestionSchema = z.object({\n type: z.enum([\"bar\", \"line\", \"pie\", \"scatter\", \"area\"]),\n title: z.string(),\n description: z\n .string()\n .optional()\n .default(\"\")\n .describe(\"Short description of what the chart shows\"),\n xColumn: z\n .string()\n .describe(\"The EXACT column name to use for X axis (categories/labels)\"),\n yColumn: z\n .string()\n .describe(\"The EXACT column name to use for Y axis (values)\"),\n groupColumn: z\n .string()\n .optional()\n .describe(\"Optional column to group/segment the data\"),\n aggregation: z\n .enum([\"sum\", \"avg\", \"count\", \"min\", \"max\", \"none\"])\n .optional()\n .default(\"none\")\n .describe(\"How to aggregate Y values when there are duplicates in X\"),\n reasoning: z\n .string()\n .optional()\n .default(\"\")\n .describe(\"Brief explanation of why this chart is useful for this data\"),\n});\n\nconst ChartSuggestionsResponseSchema = z.object({\n charts: z.array(ChartSuggestionSchema),\n});\n\nconst SingleChartResponseSchema = z.object({\n chart: ChartSuggestionSchema,\n});\n\n// ============ Error Handling ============\n\n/**\n * Extracts a user-friendly error message from AI provider errors.\n * Exported so consumers can use it in their own error handling.\n */\nexport function getAIErrorMessage(error: unknown): string {\n // Handle Zod validation errors\n if (\n error instanceof Error &&\n error.name === \"ZodError\" &&\n \"issues\" in error\n ) {\n const issues = (error as { issues: Array<{ message: string }> }).issues;\n return `Invalid data: ${issues.map((i) => i.message).join(\", \")}`;\n }\n\n if (error instanceof Error) {\n const message = error.message.toLowerCase();\n\n if (message.includes(\"rate limit\") || message.includes(\"429\")) {\n return \"Rate limit exceeded. Please wait a moment and try again.\";\n }\n if (\n message.includes(\"unauthorized\") ||\n message.includes(\"401\") ||\n message.includes(\"invalid api key\") ||\n message.includes(\"invalid_api_key\")\n ) {\n return \"Invalid API key. Please check your API key configuration.\";\n }\n if (\n message.includes(\"quota\") ||\n message.includes(\"insufficient_quota\") ||\n message.includes(\"billing\")\n ) {\n return \"API quota exceeded or billing issue. Please check your account status.\";\n }\n if (\n message.includes(\"network\") ||\n message.includes(\"timeout\") ||\n message.includes(\"econnrefused\") ||\n message.includes(\"fetch failed\")\n ) {\n return \"Network error. Please check your internet connection and try again.\";\n }\n if (\n message.includes(\"model\") &&\n (message.includes(\"not found\") || message.includes(\"does not exist\"))\n ) {\n return \"Model not available. Please select a different model.\";\n }\n\n return error.message;\n }\n\n return \"An unexpected error occurred. Please try again.\";\n}\n\n// ============ Data Summary Generation ============\n\n/**\n * Generate a text summary of tabular data for AI consumption.\n * If the consumer doesn't provide a `dataSummary`, this is used automatically.\n */\nexport function summarizeTabularData(data: TabularData): string {\n const lines: string[] = [];\n lines.push(`Dataset: ${data.rowCount} rows, ${data.headers.length} columns`);\n lines.push(`Columns: ${data.headers.join(\", \")}`);\n lines.push(\"\");\n\n for (const col of data.columns) {\n const idx = col.index;\n const values = data.rows.map((r) => r[idx] ?? \"\").filter((v) => v !== \"\");\n\n if (col.type === \"number\") {\n const nums = values.map(Number).filter((n) => !isNaN(n));\n if (nums.length > 0) {\n const min = nums.reduce((a, b) => (b < a ? b : a), nums[0]!);\n const max = nums.reduce((a, b) => (b > a ? b : a), nums[0]!);\n const avg = nums.reduce((a, b) => a + b, 0) / nums.length;\n lines.push(\n `- ${col.name} (${col.type}): min=${min}, max=${max}, avg=${avg.toFixed(2)}, ${nums.length} values`,\n );\n } else {\n lines.push(`- ${col.name} (${col.type}): no valid numeric values`);\n }\n } else {\n const distinct = new Set(values).size;\n const sample = values.slice(0, 5).join(\", \");\n lines.push(\n `- ${col.name} (${col.type}): ${distinct} distinct values, sample: [${sample}]`,\n );\n }\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Generate a detailed human-readable summary of tabular data,\n * including column statistics and sample rows.\n *\n * @example\n * ```ts\n * const summary = generateDataSummary(data);\n * // \"Dataset with 150 rows and 4 columns.\\n\\nColumns:\\n- name (text): 120 unique values...\"\n * ```\n */\nexport function generateDataSummary(data: TabularData): string {\n const summary: string[] = [];\n\n summary.push(\n `Dataset with ${data.rowCount} rows and ${data.columns.length} columns.`,\n );\n summary.push(\"\\nColumns:\");\n\n data.columns.forEach((col) => {\n const values = data.rows.map((row) => row[col.index] ?? \"\");\n const nonEmpty = values.filter((v) => v.trim() !== \"\");\n\n if (col.type === \"number\") {\n const numbers = nonEmpty\n .map((v) => parseFloat(v.replace(/[\\s,]/g, \"\").replace(\",\", \".\")))\n .filter((n) => !isNaN(n));\n\n if (numbers.length > 0) {\n const min = Math.min(...numbers);\n const max = Math.max(...numbers);\n const avg = numbers.reduce((a, b) => a + b, 0) / numbers.length;\n summary.push(\n `- ${col.name} (number): min=${min.toFixed(2)}, max=${max.toFixed(2)}, avg=${avg.toFixed(2)}, ${numbers.length} values`,\n );\n } else {\n summary.push(`- ${col.name} (number): no valid values`);\n }\n } else if (col.type === \"string\") {\n const uniqueValues = new Set(nonEmpty);\n const uniqueCount = uniqueValues.size;\n const sampleValues = Array.from(uniqueValues).slice(0, 5).join(\", \");\n summary.push(\n `- ${col.name} (text): ${uniqueCount} unique values, examples: ${sampleValues}`,\n );\n } else if (col.type === \"date\") {\n summary.push(`- ${col.name} (date): ${nonEmpty.length} values`);\n } else if (col.type === \"boolean\") {\n summary.push(`- ${col.name} (boolean): ${nonEmpty.length} values`);\n }\n });\n\n // Add sample rows\n summary.push(\"\\nFirst 5 rows sample:\");\n const sampleRows = data.rows.slice(0, 5);\n sampleRows.forEach((row, i) => {\n const rowData = data.columns\n .map((col) => `${col.name}: ${row[col.index] ?? \"N/A\"}`)\n .join(\", \");\n summary.push(`Row ${i + 1}: ${rowData}`);\n });\n\n return summary.join(\"\\n\");\n}\n\n// ============ Model Resolution ============\n\nfunction isLanguageModel(input: unknown): input is LanguageModel {\n return (\n typeof input === \"object\" &&\n input !== null &&\n \"doGenerate\" in input &&\n typeof (input as Record<string, unknown>).doGenerate === \"function\"\n );\n}\n\n/**\n * Create a LanguageModel from an AIConfig.\n * The provider must be registered beforehand via {@link registerProvider}.\n *\n * @example\n * ```ts\n * import { registerProvider, fromSDK, createModel } from \"csv-charts-ai\";\n * import { createOpenAI } from \"@ai-sdk/openai\";\n *\n * registerProvider(\"openai\", fromSDK(createOpenAI));\n *\n * const model = createModel({ apiKey: \"sk-...\", model: \"gpt-4o\" });\n * ```\n */\nexport function createModel(config: AIConfig): LanguageModel {\n const parsed = AIConfigSchema.parse(config);\n const factory = requireProvider(parsed.provider);\n return factory({\n apiKey: parsed.apiKey,\n model: parsed.model,\n ...(parsed.baseURL && { baseURL: parsed.baseURL }),\n });\n}\n\n/**\n * Create a LanguageModel from an AppModelConfig.\n * Handles multi-provider apps with providerNpm-based routing and\n * custom endpoints.\n *\n * The provider identified by `providerNpm` (or `\"openai\"` by default)\n * must be registered beforehand via {@link registerProvider}.\n *\n * @example\n * ```ts\n * const model = createAppModel({\n * apiKey: \"sk-...\",\n * model: \"claude-haiku-4-5\",\n * providerNpm: \"@ai-sdk/anthropic\",\n * });\n * ```\n */\nexport function createAppModel(config: AppModelConfig): LanguageModel {\n const modelName = config.customModel ?? config.model ?? \"\";\n\n if (config.customEndpoint) {\n const factory = requireProvider(\"openai\");\n return factory({\n apiKey: config.apiKey || \"\",\n model: config.customModel ?? modelName,\n baseURL: config.customEndpoint,\n ...(config.headers && { headers: config.headers }),\n });\n }\n\n const providerName = config.providerNpm ?? \"openai\";\n const factory = requireProvider(providerName);\n return factory({\n apiKey: config.apiKey,\n model: modelName,\n ...(config.providerApi && { baseURL: config.providerApi }),\n ...(config.headers && { headers: config.headers }),\n });\n}\n\nfunction isAppModelConfig(input: unknown): input is AppModelConfig {\n if (typeof input !== \"object\" || input === null) return false;\n if (\"doGenerate\" in input) return false; // LanguageModel\n // AppModelConfig is identified by its unique fields (providerNpm, providerApi, customEndpoint, customModel)\n // This avoids misrouting AIConfig objects (which have provider/baseURL) through createAppModel\n return (\n \"providerNpm\" in input ||\n \"providerApi\" in input ||\n \"customEndpoint\" in input ||\n \"customModel\" in input\n );\n}\n\nexport function resolveModel(input: ModelInput): LanguageModel {\n if (isLanguageModel(input)) return input;\n if (isAppModelConfig(input)) return createAppModel(input);\n return createModel(input as AIConfig);\n}\n\n// ============ Prompts ============\n\nconst getChartSystemPrompt = (\n columns: string[],\n language?: string,\n) => `You are a data visualization expert.${language ? ` Respond in ${language}.` : \"\"}\n\nYou will analyze CSV data and suggest the best charts to visualize it.\n\nAVAILABLE COLUMNS (use these EXACT names):\n${columns.map((c) => `- \"${c}\"`).join(\"\\n\")}\n\nCRITICAL RULES:\n1. xColumn and yColumn MUST be exact column names from the list above\n2. For numeric analysis, yColumn should be a numeric column\n3. For categorical comparisons, xColumn should be a categorical column\n4. Only suggest charts that make sense for the data types\n5. Use aggregation when there are multiple rows per category:\n - \"sum\" for totals (sales, revenue)\n - \"avg\" for averages (ratings, scores)\n - \"count\" for frequencies\n - \"none\" for unique values or time series\n6. Suggest 2-4 charts maximum, focusing on the most insightful ones\n\nCHART TYPE GUIDELINES:\n- bar: Compare categories (xColumn=category, yColumn=numeric)\n- line: Show trends over time (xColumn=date/time, yColumn=numeric)\n- pie: Show proportions (xColumn=category, yColumn=numeric with sum/count)\n- scatter: Show correlations (xColumn=numeric, yColumn=numeric, aggregation=none)\n- area: Show cumulative trends (xColumn=date/time, yColumn=numeric)`;\n\nconst getCustomChartPrompt = (\n columns: string[],\n language?: string,\n) => `You are a data visualization expert.${language ? ` Respond in ${language}.` : \"\"}\n\nCreate a chart configuration based on the user's request.\n\nAVAILABLE COLUMNS (use these EXACT names):\n${columns.map((c) => `- \"${c}\"`).join(\"\\n\")}\n\nIMPORTANT: Column names MUST exactly match the list above.`;\n\n// ============ Helpers ============\n\nfunction mapChartResult(\n raw: z.infer<typeof ChartSuggestionSchema>,\n id: string,\n): ChartConfig {\n return {\n id,\n type: raw.type,\n title: raw.title,\n description: raw.description,\n xAxis: raw.xColumn,\n yAxis: raw.yColumn,\n groupBy: raw.groupColumn,\n aggregation: raw.aggregation,\n dataConfig: {\n xColumn: raw.xColumn,\n yColumn: raw.yColumn,\n groupColumn: raw.groupColumn,\n },\n };\n}\n\n// ============ Options ============\n\nexport interface SuggestChartsOptions {\n /** The AI model — either a simple config or a LanguageModel instance */\n model: ModelInput;\n /** The tabular data to analyze */\n data: TabularData;\n /** A text summary of the data. If omitted, auto-generated from `data`. */\n dataSummary?: string;\n /** Language for AI responses (e.g. \"English\", \"French\") */\n language?: string;\n /** Temperature for AI generation (default: 0.5) */\n temperature?: number;\n /** AbortSignal to cancel the request */\n signal?: AbortSignal;\n}\n\nexport interface SuggestCustomChartOptions {\n /** The AI model — either a simple config or a LanguageModel instance */\n model: ModelInput;\n /** The tabular data */\n data: TabularData;\n /** A text summary of the data. If omitted, auto-generated from `data`. */\n dataSummary?: string;\n /** The user's chart request (e.g. \"show sales by month\") */\n prompt: string;\n /** Language for AI responses */\n language?: string;\n /** Temperature (default: 0.5) */\n temperature?: number;\n /** AbortSignal to cancel the request */\n signal?: AbortSignal;\n}\n\nexport interface RepairChartOptions {\n /** The AI model — either a simple config or a LanguageModel instance */\n model: ModelInput;\n /** The chart configuration that failed */\n failedChart: ChartConfig;\n /** Available column names */\n columns: string[];\n /** Description of why the chart failed */\n errorContext: string;\n /** Language for AI responses */\n language?: string;\n /** Temperature (default: 0.3) */\n temperature?: number;\n /** AbortSignal to cancel the request */\n signal?: AbortSignal;\n}\n\n// ============ Public API ============\n\n/**\n * Generate chart suggestions from tabular data using AI.\n *\n * @example\n * ```ts\n * import { suggestCharts } from \"csv-charts-ai\";\n *\n * // Minimal — auto-generates dataSummary from the data\n * const charts = await suggestCharts({\n * model: { apiKey: \"sk-...\", model: \"gpt-4o\" },\n * data: myData,\n * });\n *\n * // Custom endpoint — Ollama\n * const charts = await suggestCharts({\n * model: { apiKey: \"\", model: \"llama3\", baseURL: \"http://localhost:11434/v1\" },\n * data: myData,\n * });\n *\n * // Advanced — any LanguageModel from the ai SDK\n * import { anthropic } from \"@ai-sdk/anthropic\";\n * const charts = await suggestCharts({\n * model: anthropic(\"claude-sonnet-4-20250514\"),\n * data: myData,\n * language: \"French\",\n * });\n * ```\n */\nexport async function suggestCharts(\n options: SuggestChartsOptions,\n): Promise<ChartConfig[]> {\n const { data, language, temperature = 0.5, signal } = options;\n const dataSummary = options.dataSummary ?? summarizeTabularData(data);\n\n try {\n TabularDataSchema.parse(data);\n const model = resolveModel(options.model);\n\n const { object } = await generateObject({\n model,\n schema: ChartSuggestionsResponseSchema,\n system: getChartSystemPrompt(data.headers, language),\n prompt: `Analyze this CSV data and suggest the best charts:\\n\\n${dataSummary}`,\n temperature,\n ...(signal && { abortSignal: signal }),\n });\n\n return object.charts.map((s, i) =>\n mapChartResult(s, `chart-${i}-${Date.now()}`),\n );\n } catch (error) {\n throw new Error(getAIErrorMessage(error));\n }\n}\n\n/**\n * Generate a single chart from a user's text prompt.\n *\n * @example\n * ```ts\n * const chart = await suggestCustomChart({\n * model: { apiKey: \"sk-...\", model: \"gpt-4o\" },\n * data: myData,\n * prompt: \"Show me a bar chart of sales by category\",\n * });\n * ```\n */\nexport async function suggestCustomChart(\n options: SuggestCustomChartOptions,\n): Promise<ChartConfig | null> {\n const { data, prompt, language, temperature = 0.5, signal } = options;\n const dataSummary = options.dataSummary ?? summarizeTabularData(data);\n\n try {\n TabularDataSchema.parse(data);\n const model = resolveModel(options.model);\n\n const { object } = await generateObject({\n model,\n schema: SingleChartResponseSchema,\n system: getCustomChartPrompt(data.headers, language),\n prompt: `Data summary:\\n${dataSummary}\\n\\nUser request: ${prompt}`,\n temperature,\n ...(signal && { abortSignal: signal }),\n });\n\n return mapChartResult(object.chart, `chart-custom-${Date.now()}`);\n } catch (error) {\n throw new Error(getAIErrorMessage(error));\n }\n}\n\n/**\n * Repair a chart configuration that failed to render.\n *\n * @example\n * ```ts\n * const fixed = await repairChart({\n * model: { apiKey: \"sk-...\", model: \"gpt-4o\" },\n * failedChart: brokenChart,\n * columns: [\"name\", \"sales\", \"date\"],\n * errorContext: \"Column 'revenue' does not exist\",\n * });\n * ```\n */\nexport async function repairChart(\n options: RepairChartOptions,\n): Promise<ChartConfig | null> {\n const {\n failedChart,\n columns,\n errorContext,\n language,\n temperature = 0.3,\n signal,\n } = options;\n\n try {\n const model = resolveModel(options.model);\n\n const { object } = await generateObject({\n model,\n schema: SingleChartResponseSchema,\n system: getCustomChartPrompt(columns, language),\n prompt: `The following chart configuration failed to render:\\n${JSON.stringify(failedChart, null, 2)}\\n\\nError context: ${errorContext}\\n\\nPlease fix the configuration to use valid columns and aggregation. Available columns: ${columns.join(\", \")}`,\n temperature,\n ...(signal && { abortSignal: signal }),\n });\n\n return mapChartResult(object.chart, failedChart.id);\n } catch (error) {\n throw new Error(getAIErrorMessage(error));\n }\n}\n","import type { TabularData } from \"./types\";\n\n/* ── Types ── */\n\nexport type MatchMode = \"index\" | \"key\" | \"content\";\nexport type DiffStatus = \"same\" | \"changed\" | \"added\" | \"removed\";\n\nexport interface DiffRow {\n indexA: number | null;\n indexB: number | null;\n status: DiffStatus;\n rowA: (string | number)[] | null;\n rowB: (string | number)[] | null;\n changedCols: Set<string>;\n}\n\nexport interface DiffCounts {\n same: number;\n changed: number;\n added: number;\n removed: number;\n}\n\nexport interface DiffResult {\n commonHeaders: string[];\n onlyInA: string[];\n onlyInB: string[];\n rows: DiffRow[];\n counts: DiffCounts;\n}\n\nexport interface DiffOptions {\n matchMode: MatchMode;\n keyColumn?: string;\n}\n\n/* ── Diff computation ── */\n\nexport function computeDiff(\n primaryData: TabularData,\n compareData: TabularData,\n options: DiffOptions,\n): DiffResult {\n const { matchMode, keyColumn = \"\" } = options;\n\n const commonHeaders = primaryData.headers.filter((h) =>\n compareData.headers.includes(h),\n );\n const onlyInA = primaryData.headers.filter(\n (h) => !compareData.headers.includes(h),\n );\n const onlyInB = compareData.headers.filter(\n (h) => !primaryData.headers.includes(h),\n );\n\n const rows: DiffRow[] = [];\n\n const getChangedCols = (\n a: (string | number)[],\n b: (string | number)[],\n ): Set<string> => {\n const changed = new Set<string>();\n for (const h of commonHeaders) {\n const aIdx = primaryData.headers.indexOf(h);\n const bIdx = compareData.headers.indexOf(h);\n if (String(a[aIdx] ?? \"\") !== String(b[bIdx] ?? \"\")) {\n changed.add(h);\n }\n }\n return changed;\n };\n\n // Determine effective match mode\n const effectiveMode =\n matchMode === \"content\"\n ? \"content\"\n : matchMode === \"key\" && keyColumn && commonHeaders.includes(keyColumn)\n ? \"key\"\n : \"index\";\n\n if (effectiveMode === \"content\") {\n const makeKey = (row: (string | number)[], headers: string[]) =>\n commonHeaders\n .map((h) => String(row[headers.indexOf(h)] ?? \"\"))\n .join(\"\\0\");\n\n const aMap = new Map<string, { row: (string | number)[]; idx: number }[]>();\n for (let i = 0; i < primaryData.rows.length; i++) {\n const key = makeKey(primaryData.rows[i]!, primaryData.headers);\n const list = aMap.get(key) ?? [];\n list.push({ row: primaryData.rows[i]!, idx: i });\n aMap.set(key, list);\n }\n\n const matchedAIndices = new Set<number>();\n\n for (let i = 0; i < compareData.rows.length; i++) {\n const key = makeKey(compareData.rows[i]!, compareData.headers);\n const candidates = aMap.get(key);\n\n if (candidates) {\n const match = candidates.find((c) => !matchedAIndices.has(c.idx));\n if (match) {\n matchedAIndices.add(match.idx);\n rows.push({\n indexA: match.idx,\n indexB: i,\n status: \"same\",\n rowA: match.row,\n rowB: compareData.rows[i]!,\n changedCols: new Set(),\n });\n } else {\n rows.push({\n indexA: null,\n indexB: i,\n status: \"added\",\n rowA: null,\n rowB: compareData.rows[i]!,\n changedCols: new Set(),\n });\n }\n } else {\n rows.push({\n indexA: null,\n indexB: i,\n status: \"added\",\n rowA: null,\n rowB: compareData.rows[i]!,\n changedCols: new Set(),\n });\n }\n }\n\n for (let i = 0; i < primaryData.rows.length; i++) {\n if (!matchedAIndices.has(i)) {\n rows.push({\n indexA: i,\n indexB: null,\n status: \"removed\",\n rowA: primaryData.rows[i]!,\n rowB: null,\n changedCols: new Set(),\n });\n }\n }\n } else if (effectiveMode === \"index\") {\n const maxLen = Math.max(primaryData.rows.length, compareData.rows.length);\n for (let i = 0; i < maxLen; i++) {\n const a = i < primaryData.rows.length ? primaryData.rows[i]! : null;\n const b = i < compareData.rows.length ? compareData.rows[i]! : null;\n\n if (!a) {\n rows.push({\n indexA: null,\n indexB: i,\n status: \"added\",\n rowA: null,\n rowB: b,\n changedCols: new Set(),\n });\n } else if (!b) {\n rows.push({\n indexA: i,\n indexB: null,\n status: \"removed\",\n rowA: a,\n rowB: null,\n changedCols: new Set(),\n });\n } else {\n const changedCols = getChangedCols(a, b);\n rows.push({\n indexA: i,\n indexB: i,\n status: changedCols.size > 0 ? \"changed\" : \"same\",\n rowA: a,\n rowB: b,\n changedCols,\n });\n }\n }\n } else {\n // Key-based matching\n const keyIdxA = primaryData.headers.indexOf(keyColumn);\n const keyIdxB = compareData.headers.indexOf(keyColumn);\n\n const aMap = new Map<string, { row: (string | number)[]; idx: number }>();\n const bMap = new Map<string, { row: (string | number)[]; idx: number }>();\n\n for (let i = 0; i < primaryData.rows.length; i++) {\n const key = String(primaryData.rows[i]![keyIdxA] ?? \"\");\n if (!aMap.has(key)) aMap.set(key, { row: primaryData.rows[i]!, idx: i });\n }\n for (let i = 0; i < compareData.rows.length; i++) {\n const key = String(compareData.rows[i]![keyIdxB] ?? \"\");\n if (!bMap.has(key)) bMap.set(key, { row: compareData.rows[i]!, idx: i });\n }\n\n const processedBKeys = new Set<string>();\n\n for (const [key, aEntry] of aMap) {\n const bEntry = bMap.get(key);\n if (bEntry) {\n processedBKeys.add(key);\n const changedCols = getChangedCols(aEntry.row, bEntry.row);\n rows.push({\n indexA: aEntry.idx,\n indexB: bEntry.idx,\n status: changedCols.size > 0 ? \"changed\" : \"same\",\n rowA: aEntry.row,\n rowB: bEntry.row,\n changedCols,\n });\n } else {\n rows.push({\n indexA: aEntry.idx,\n indexB: null,\n status: \"removed\",\n rowA: aEntry.row,\n rowB: null,\n changedCols: new Set(),\n });\n }\n }\n\n for (const [key, bEntry] of bMap) {\n if (!processedBKeys.has(key)) {\n rows.push({\n indexA: null,\n indexB: bEntry.idx,\n status: \"added\",\n rowA: null,\n rowB: bEntry.row,\n changedCols: new Set(),\n });\n }\n }\n }\n\n const counts: DiffCounts = {\n same: rows.filter((r) => r.status === \"same\").length,\n changed: rows.filter((r) => r.status === \"changed\").length,\n added: rows.filter((r) => r.status === \"added\").length,\n removed: rows.filter((r) => r.status === \"removed\").length,\n };\n\n return { commonHeaders, onlyInA, onlyInB, rows, counts };\n}\n","import { generateObject, generateText, streamText } from \"ai\";\nimport { z } from \"zod\";\nimport type { TabularData, ChartConfig } from \"./types\";\nimport type { ModelInput } from \"./ai\";\nimport { summarizeTabularData, getAIErrorMessage, resolveModel } from \"./ai\";\nimport { suggestCharts } from \"./ai\";\n\n// ============ Schemas ============\n\nconst DataSummarySchema = z.object({\n summary: z.string(),\n keyInsights: z.array(z.string()),\n dataQuality: z.string(),\n});\n\nconst AnomalySchema = z.object({\n row: z.number(),\n column: z.string(),\n value: z.string(),\n issue: z.string(),\n severity: z.enum([\"low\", \"medium\", \"high\"]),\n});\n\nconst AnomaliesResponseSchema = z.object({\n anomalies: z.array(AnomalySchema),\n});\n\n// ============ Result Types ============\n\nexport interface DataSummaryResult {\n summary: string;\n keyInsights: string[];\n dataQuality: string;\n}\n\nexport interface AnomalyResult {\n row: number;\n column: string;\n value: string;\n issue: string;\n severity: \"low\" | \"medium\" | \"high\";\n}\n\nexport interface AnalysisResult {\n summary: DataSummaryResult;\n anomalies: AnomalyResult[];\n charts: ChartConfig[];\n}\n\n// ============ Prompts ============\n\nconst summarySystemPrompt = (\n language?: string,\n) => `You are a data analyst.${language ? ` Respond in ${language}.` : \"\"}\n\nAnalyze the provided CSV data summary and provide:\n1. A comprehensive summary of what this dataset represents (2-3 sentences)\n2. 3-5 key insights or patterns you notice\n3. An assessment of data quality (completeness, consistency)`;\n\nconst anomalySystemPrompt = (\n language?: string,\n) => `You are a data quality expert.${language ? ` Respond in ${language}.` : \"\"}\n\nAnalyze the provided CSV data and identify anomalies, outliers, or suspicious data points.\n\nFor each anomaly found, provide:\n1. Row number (1-indexed, excluding header)\n2. Column name\n3. The problematic value\n4. Description of the issue\n5. Severity (low, medium, high)\n\nLook for:\n- Missing or empty values where data is expected\n- Values that don't match the expected type\n- Outliers (extremely high or low values)\n- Inconsistent formatting\n- Invalid dates or formats\n\nAnalyze ALL rows provided. Return empty array if no anomalies found.`;\n\nconst questionSystemPrompt = (\n language?: string,\n) =>\n `You are a data analysis expert.${language ? ` Respond in ${language}.` : \"\"}\\n\\nThe user will ask questions about a CSV dataset. Respond clearly and precisely.`;\n\n// ============ Helper ============\n\nfunction escapeCSVField(value: string): string {\n if (\n value.includes(\",\") ||\n value.includes('\"') ||\n value.includes(\"\\n\") ||\n value.includes(\"\\r\")\n ) {\n return `\"${value.replace(/\"/g, '\"\"')}\"`;\n }\n return value;\n}\n\nfunction buildSampleCSV(data: TabularData, maxRows = 50): string {\n const header = data.headers.map(escapeCSVField).join(\",\");\n const rows = data.rows\n .slice(0, maxRows)\n .map((row) => row.map(escapeCSVField).join(\",\"))\n .join(\"\\n\");\n return `${header}\\n${rows}`;\n}\n\n// ============ Individual Functions ============\n\nexport interface SummarizeDataOptions {\n model: ModelInput;\n data: TabularData;\n dataSummary?: string;\n language?: string;\n temperature?: number;\n /** AbortSignal to cancel the request */\n signal?: AbortSignal;\n}\n\n/**\n * Generate an AI summary of tabular data.\n *\n * @example\n * ```ts\n * const result = await summarizeData({\n * model: { apiKey: \"sk-...\", model: \"gpt-4o\" },\n * data: myData,\n * });\n * console.log(result.summary);\n * console.log(result.keyInsights);\n * console.log(result.dataQuality);\n * ```\n */\nexport async function summarizeData(\n options: SummarizeDataOptions,\n): Promise<DataSummaryResult> {\n const { data, language, temperature = 0.5, signal } = options;\n const dataSummary = options.dataSummary ?? summarizeTabularData(data);\n\n try {\n const model = resolveModel(options.model);\n\n const { object } = await generateObject({\n model,\n schema: DataSummarySchema,\n system: summarySystemPrompt(language),\n prompt: `Here is the data to analyze:\\n\\n${dataSummary}`,\n temperature,\n ...(signal && { abortSignal: signal }),\n });\n\n return {\n summary: object.summary,\n keyInsights: object.keyInsights,\n dataQuality: object.dataQuality,\n };\n } catch (error) {\n throw new Error(getAIErrorMessage(error));\n }\n}\n\nexport interface DetectAnomaliesOptions {\n model: ModelInput;\n data: TabularData;\n dataSummary?: string;\n /** Max rows to send for analysis (default: 50) */\n maxRows?: number;\n language?: string;\n temperature?: number;\n /** AbortSignal to cancel the request */\n signal?: AbortSignal;\n}\n\n/**\n * Detect anomalies in tabular data using AI.\n *\n * @example\n * ```ts\n * const anomalies = await detectAnomalies({\n * model: { apiKey: \"sk-...\", model: \"gpt-4o\" },\n * data: myData,\n * });\n * anomalies.forEach(a => console.log(`Row ${a.row}: ${a.issue}`));\n * ```\n */\nexport async function detectAnomalies(\n options: DetectAnomaliesOptions,\n): Promise<AnomalyResult[]> {\n const { data, maxRows = 50, language, temperature = 0.3, signal } = options;\n const dataSummary = options.dataSummary ?? summarizeTabularData(data);\n const sampleCSV = buildSampleCSV(data, maxRows);\n\n try {\n const model = resolveModel(options.model);\n\n const { object } = await generateObject({\n model,\n schema: AnomaliesResponseSchema,\n system: anomalySystemPrompt(language),\n prompt: `Data summary:\\n${dataSummary}\\n\\nData to analyze (CSV format):\\n${sampleCSV}`,\n temperature,\n ...(signal && { abortSignal: signal }),\n });\n\n return object.anomalies;\n } catch (error) {\n throw new Error(getAIErrorMessage(error));\n }\n}\n\nexport interface AskAboutDataOptions {\n model: ModelInput;\n data: TabularData;\n question: string;\n dataSummary?: string;\n /** Previous conversation messages for context */\n history?: Array<{ prompt: string; response: string }>;\n language?: string;\n temperature?: number;\n /** AbortSignal to cancel the request */\n signal?: AbortSignal;\n}\n\n/**\n * Ask a question about the data and get a text response.\n *\n * @example\n * ```ts\n * const answer = await askAboutData({\n * model: { apiKey: \"sk-...\", model: \"gpt-4o\" },\n * data: myData,\n * question: \"What is the average revenue by category?\",\n * });\n * console.log(answer);\n * ```\n */\nexport async function askAboutData(\n options: AskAboutDataOptions,\n): Promise<string> {\n const { data, question, history = [], language, temperature = 0.5, signal } = options;\n const dataSummary = options.dataSummary ?? summarizeTabularData(data);\n\n try {\n const model = resolveModel(options.model);\n\n const historyText = history\n .map((item) => `User: ${item.prompt}\\nAI: ${item.response}`)\n .join(\"\\n\\n\");\n const contextPrompt = historyText\n ? `Previous conversation history:\\n${historyText}\\n\\n`\n : \"\";\n\n const { text } = await generateText({\n model,\n system: questionSystemPrompt(language),\n prompt: `Here is the data:\\n\\n${dataSummary}\\n\\n${contextPrompt}User question: ${question}`,\n temperature,\n ...(signal && { abortSignal: signal }),\n });\n\n return text;\n } catch (error) {\n throw new Error(getAIErrorMessage(error));\n }\n}\n\nexport interface StreamAskAboutDataOptions extends Omit<AskAboutDataOptions, \"signal\"> {\n onChunk: (chunk: string) => void;\n onComplete: (fullText: string) => void;\n /** AbortSignal to cancel the stream */\n signal?: AbortSignal;\n}\n\n/**\n * Ask a question with streaming response.\n *\n * @example\n * ```ts\n * await streamAskAboutData({\n * model: { apiKey: \"sk-...\", model: \"gpt-4o\" },\n * data: myData,\n * question: \"What trends do you see?\",\n * onChunk: (chunk) => process.stdout.write(chunk),\n * onComplete: (full) => console.log(\"\\nDone:\", full.length, \"chars\"),\n * });\n * ```\n */\nexport async function streamAskAboutData(\n options: StreamAskAboutDataOptions,\n): Promise<void> {\n const {\n data,\n question,\n history = [],\n language,\n temperature = 0.5,\n signal,\n onChunk,\n onComplete,\n } = options;\n const dataSummary = options.dataSummary ?? summarizeTabularData(data);\n\n try {\n const model = resolveModel(options.model);\n\n const historyText = history\n .map((item) => `User: ${item.prompt}\\nAI: ${item.response}`)\n .join(\"\\n\\n\");\n const contextPrompt = historyText\n ? `Previous conversation history:\\n${historyText}\\n\\n`\n : \"\";\n\n let streamError: Error | null = null;\n\n const result = streamText({\n model,\n system: questionSystemPrompt(language),\n prompt: `Here is the data:\\n\\n${dataSummary}\\n\\n${contextPrompt}User question: ${question}`,\n temperature,\n ...(signal && { abortSignal: signal }),\n onError: ({ error }) => {\n streamError =\n error instanceof Error ? error : new Error(String(error));\n },\n });\n\n let fullText = \"\";\n\n for await (const textPart of result.textStream) {\n fullText += textPart;\n onChunk(textPart);\n }\n\n if (streamError) throw streamError;\n\n const finishReason = await result.finishReason;\n if (finishReason === \"error\") {\n throw new Error(\"The AI model encountered an error while generating the response.\");\n }\n\n onComplete(fullText);\n } catch (error) {\n throw new Error(getAIErrorMessage(error));\n }\n}\n\n// ============ Full Pipeline ============\n\nexport interface AnalyzeOptions {\n model: ModelInput;\n data: TabularData;\n dataSummary?: string;\n language?: string;\n /** Set to false to skip anomaly detection (default: true) */\n detectAnomalies?: boolean;\n /** Set to false to skip chart suggestions (default: true) */\n suggestCharts?: boolean;\n /** AbortSignal to cancel all parallel requests */\n signal?: AbortSignal;\n}\n\n/**\n * Run a complete AI analysis on tabular data in one call.\n * Returns summary, anomalies, and chart suggestions.\n *\n * @example\n * ```ts\n * import { analyzeData, ChartDisplay } from \"csv-charts-ai\";\n *\n * const result = await analyzeData({\n * model: { apiKey: \"sk-...\", model: \"gpt-4o\" },\n * data: myCSVData,\n * });\n *\n * console.log(result.summary.keyInsights);\n * console.log(`Found ${result.anomalies.length} anomalies`);\n *\n * // Render charts\n * <ChartDisplay data={myCSVData} charts={result.charts} />\n * ```\n */\nexport async function analyzeData(\n options: AnalyzeOptions,\n): Promise<AnalysisResult> {\n const {\n data,\n language,\n signal,\n detectAnomalies: runAnomalies = true,\n suggestCharts: runCharts = true,\n } = options;\n const dataSummary = options.dataSummary ?? summarizeTabularData(data);\n\n // Run all in parallel\n const [summary, anomalies, charts] = await Promise.all([\n summarizeData({ model: options.model, data, dataSummary, language, signal }),\n runAnomalies\n ? detectAnomalies({ model: options.model, data, dataSummary, language, signal })\n : Promise.resolve([]),\n runCharts\n ? suggestCharts({ model: options.model, data, dataSummary, language, signal })\n : Promise.resolve([]),\n ]);\n\n return { summary, anomalies, charts };\n}\n\n// ============ Question Suggestions ============\n\nconst questionsSystemPrompt = (\n language?: string,\n) => `You are a data analysis expert.${language ? ` Respond in ${language}.` : \"\"}\n\nGiven a dataset summary, suggest insightful questions that a user could ask to better understand their data. Focus on:\n- Trends and patterns\n- Comparisons and rankings\n- Correlations between columns\n- Outliers and anomalies\n- Actionable business insights\n\nEach question should be specific to the data columns available.`;\n\nconst QuestionsResponseSchema = z.object({\n questions: z\n .array(\n z.object({\n question: z.string().describe(\"The question to ask about the data\"),\n category: z\n .enum([\"trend\", \"comparison\", \"correlation\", \"anomaly\", \"insight\"])\n .describe(\"Category of the question\"),\n }),\n )\n .describe(\"5-8 suggested questions\"),\n});\n\nexport interface SuggestQuestionsOptions {\n model: ModelInput;\n data: TabularData;\n dataSummary?: string;\n language?: string;\n /** Number of questions to suggest (default: 6) */\n count?: number;\n temperature?: number;\n /** AbortSignal to cancel the request */\n signal?: AbortSignal;\n}\n\nexport interface SuggestedQuestion {\n question: string;\n category: \"trend\" | \"comparison\" | \"correlation\" | \"anomaly\" | \"insight\";\n}\n\n/**\n * Suggest interesting questions a user could ask about their data.\n * Great for onboarding users who don't know where to start with their dataset.\n *\n * @example\n * ```ts\n * const questions = await suggestQuestions({\n * model: { apiKey: \"sk-...\", model: \"gpt-4o\" },\n * data: myData,\n * });\n *\n * questions.forEach(q => console.log(`[${q.category}] ${q.question}`));\n * // [trend] How has revenue changed over the last 6 months?\n * // [comparison] Which product category generates the most revenue?\n * // [correlation] Is there a relationship between price and quantity sold?\n * ```\n */\nexport async function suggestQuestions(\n options: SuggestQuestionsOptions,\n): Promise<SuggestedQuestion[]> {\n const { data, language, count = 6, temperature = 0.7, signal } = options;\n const dataSummary = options.dataSummary ?? summarizeTabularData(data);\n\n try {\n const model = resolveModel(options.model);\n\n const { object } = await generateObject({\n model,\n schema: QuestionsResponseSchema,\n system: questionsSystemPrompt(language),\n prompt: `Here is the dataset to analyze:\\n\\n${dataSummary}\\n\\nSuggest ${count} insightful questions about this data.`,\n temperature,\n ...(signal && { abortSignal: signal }),\n });\n\n return object.questions.slice(0, count);\n } catch (error) {\n throw new Error(getAIErrorMessage(error));\n }\n}\n"],"mappings":"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","names":["BOOLEAN_VALUES","DATE_PATTERNS","inferColumnType","factory","generateObject","z","z","generateObject"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "csv-charts-ai",
3
- "version": "1.9.0",
3
+ "version": "1.10.0",
4
4
  "description": "AI-powered CSV analysis, chart generation, and interactive visualization. Parse CSV, detect anomalies, suggest charts, and ask questions about your data using any LLM provider.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -53,7 +53,11 @@
53
53
  "peerDependencies": {
54
54
  "react": "^18.0.0 || ^19.0.0",
55
55
  "recharts": "^3.0.0",
56
- "lucide-react": ">=0.400.0"
56
+ "lucide-react": ">=0.400.0",
57
+ "@ai-sdk/openai": "^3.0.0",
58
+ "@ai-sdk/anthropic": "^3.0.0",
59
+ "@ai-sdk/google": "^3.0.0",
60
+ "@ai-sdk/mistral": "^3.0.0"
57
61
  },
58
62
  "peerDependenciesMeta": {
59
63
  "react": {
@@ -64,15 +68,23 @@
64
68
  },
65
69
  "lucide-react": {
66
70
  "optional": true
71
+ },
72
+ "@ai-sdk/openai": {
73
+ "optional": true
74
+ },
75
+ "@ai-sdk/anthropic": {
76
+ "optional": true
77
+ },
78
+ "@ai-sdk/google": {
79
+ "optional": true
80
+ },
81
+ "@ai-sdk/mistral": {
82
+ "optional": true
67
83
  }
68
84
  },
69
85
  "dependencies": {
70
86
  "ai": "^6.0.134",
71
87
  "zod": "^4.1.13",
72
- "@ai-sdk/openai": "^3.0.47",
73
- "@ai-sdk/anthropic": "^3.0.63",
74
- "@ai-sdk/google": "^3.0.52",
75
- "@ai-sdk/mistral": "^3.0.27",
76
88
  "read-excel-file": "^7.0.2"
77
89
  },
78
90
  "devDependencies": {