pychartai 0.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. pychartai/__init__.py +504 -0
  2. pychartai/cli.py +91 -0
  3. pychartai-0.5.0.dist-info/METADATA +240 -0
  4. pychartai-0.5.0.dist-info/RECORD +49 -0
  5. pychartai-0.5.0.dist-info/WHEEL +5 -0
  6. pychartai-0.5.0.dist-info/entry_points.txt +4 -0
  7. pychartai-0.5.0.dist-info/licenses/LICENSE +21 -0
  8. pychartai-0.5.0.dist-info/top_level.txt +3 -0
  9. pychartai_core/__init__.py +148 -0
  10. pychartai_core/agent.py +1248 -0
  11. pychartai_core/api.py +189 -0
  12. pychartai_core/cache.py +119 -0
  13. pychartai_core/cloud_connectors.py +364 -0
  14. pychartai_core/code_sanitizer.py +144 -0
  15. pychartai_core/config.py +115 -0
  16. pychartai_core/connections.py +253 -0
  17. pychartai_core/dashboard_report.py +266 -0
  18. pychartai_core/data_manager.py +116 -0
  19. pychartai_core/db_connectors.py +302 -0
  20. pychartai_core/error_hints.py +79 -0
  21. pychartai_core/intent_classifier.py +203 -0
  22. pychartai_core/io.py +86 -0
  23. pychartai_core/logging.py +103 -0
  24. pychartai_core/memory.py +134 -0
  25. pychartai_core/model_config.py +404 -0
  26. pychartai_core/model_manager.py +209 -0
  27. pychartai_core/pipeline.py +334 -0
  28. pychartai_core/profiler.py +171 -0
  29. pychartai_core/providers.py +402 -0
  30. pychartai_core/redactor.py +172 -0
  31. pychartai_core/reporter.py +466 -0
  32. pychartai_core/sandbox.py +865 -0
  33. pychartai_core/schema.py +100 -0
  34. pychartai_core/skills.py +179 -0
  35. pychartai_core/smart_df.py +635 -0
  36. pychartai_core/streaming.py +56 -0
  37. pychartai_core/themes.py +170 -0
  38. pychartai_core/visualization.py +391 -0
  39. pychartai_core/visualization_backends/__init__.py +29 -0
  40. pychartai_core/visualization_backends/base.py +85 -0
  41. pychartai_core/visualization_backends/catalog.py +172 -0
  42. pychartai_core/visualization_backends/matplotlib_backend.py +700 -0
  43. pychartai_core/visualization_backends/plotly_backend.py +439 -0
  44. pychartai_core/visualization_backends/seaborn_backend.py +839 -0
  45. pychartai_core/visualization_backends/utils.py +95 -0
  46. pychartai_mcp/__init__.py +1 -0
  47. pychartai_mcp/agent_server.py +78 -0
  48. pychartai_mcp/server.py +97 -0
  49. pychartai_mcp/tools.py +251 -0
pychartai/__init__.py ADDED
@@ -0,0 +1,504 @@
1
+ """
2
+ pychartai — AI-powered data analysis and chart generation.
3
+
4
+ Single public API. Everything a user needs is available directly under
5
+ ``import pychartai as pai``. The ``pychartai_core`` sub-package is an
6
+ implementation detail and should not be imported directly.
7
+
8
+ Quick start::
9
+
10
+ import pychartai as pai
11
+
12
+ llm = pai.OllamaLLM(model='llama3.2')
13
+ pai.config.set({'llm': llm})
14
+
15
+ df = pai.read_csv('data/sales.csv')
16
+ print(df.chat('What is the average revenue by region?'))
17
+ df.chat('Plot a bar chart of revenue by region', chart_library='plotly')
18
+
19
+ # Data profiling — no LLM needed
20
+ report = df.profile()
21
+ print(report.summary)
22
+
23
+ # Conversation memory
24
+ df.enable_memory()
25
+ df.chat('Total sales by region')
26
+ df.chat('Now show that as a percentage')
27
+ """
28
+
29
+ from __future__ import annotations
30
+
31
+ import sys
32
+ from typing import Any, Optional
33
+ import pandas as pd
34
+
35
+ # ---------------------------------------------------------------------------
36
+ # Core imports from implementation package
37
+ # ---------------------------------------------------------------------------
38
+
39
+ from pychartai_core import config as global_config
40
+ from pychartai_core.providers import (
41
+ PyChartLLM,
42
+ OllamaLLM,
43
+ GitHubLLM,
44
+ OpenAILLM,
45
+ GeminiLLM,
46
+ AnthropicLLM,
47
+ QwenLLM,
48
+ DeepSeekLLM,
49
+ GenericLLM,
50
+ )
51
+ from pychartai_core.smart_df import SmartDataFrame
52
+ from pychartai_core.agent import PyChartAgent, TransformationLog, QueryIntent
53
+ from pychartai_core.sandbox import RestrictedSandbox, DockerSandbox
54
+ from pychartai_core.streaming import StreamEvent
55
+ from pychartai_core.reporter import InsightReporter
56
+ from pychartai_core.skills import Skill, skill
57
+ from pychartai_core.schema import Schema, Column
58
+ from pychartai_core.cache import ResponseCache
59
+ from pychartai_core.memory import ConversationMemory, Turn
60
+ from pychartai_core.profiler import DataProfiler, ProfileReport
61
+ from pychartai_core.themes import ChartTheme, resolve_theme, BUILTIN_THEMES
62
+ from pychartai_core.error_hints import get_hint, format_error_with_hint
63
+ from pychartai_core.model_config import init, load_model_config, get_model, list_models
64
+ from pychartai_core.redactor import DataRedactor
65
+ from pychartai_core.logging import (
66
+ get_logger, configure_logger, set_log_level,
67
+ )
68
+ from pychartai_core.pipeline import (
69
+ Pipeline, PipelineStep, PipelineContext,
70
+ ValidateInput, InjectSchema, InjectSkills,
71
+ CacheLookup, CallAnalyzer, CallOwnAgent, CacheStore,
72
+ default_pipeline,
73
+ )
74
+ from pychartai_core.connections import (
75
+ BaseConnection, CSVConnection, ExcelConnection,
76
+ JSONConnection, ParquetConnection, SQLConnection,
77
+ connect,
78
+ )
79
+ from pychartai_core.db_connectors import (
80
+ PostgreSQLConnection,
81
+ MySQLConnection,
82
+ SnowflakeConnection,
83
+ BigQueryConnection,
84
+ RedshiftConnection,
85
+ )
86
+ from pychartai_core.cloud_connectors import (
87
+ S3Connection,
88
+ GCSConnection,
89
+ AzureBlobConnection,
90
+ GoogleSheetsConnection,
91
+ )
92
+ from pychartai_core.visualization import (
93
+ get_chart_helper_names,
94
+ list_backends,
95
+ area_chart,
96
+ bar_chart,
97
+ box_chart,
98
+ bubble_chart,
99
+ count_chart,
100
+ ecdf_chart,
101
+ funnel_chart,
102
+ heatmap,
103
+ histogram,
104
+ kde_chart,
105
+ line_chart,
106
+ pairplot_chart,
107
+ pie_chart,
108
+ regression_chart,
109
+ scatter_chart,
110
+ stacked_bar_chart,
111
+ step_chart,
112
+ strip_chart,
113
+ swarm_chart,
114
+ violin_chart,
115
+ )
116
+
117
+
118
+
119
+ __version__ = '0.5.0'
120
+
121
+ # Expose global config singleton under the expected name
122
+ config = global_config
123
+
124
+
125
+ # ---------------------------------------------------------------------------
126
+ # Convenience helpers
127
+ # ---------------------------------------------------------------------------
128
+
129
+ def available_backends() -> tuple[str, ...]:
130
+ """Return the names of all supported chart backends."""
131
+ return tuple(list_backends())
132
+
133
+
134
+ def available_charts(chart_library: Optional[str] = None) -> tuple[str, ...]:
135
+ """Return all supported chart helper names, optionally filtered by backend."""
136
+ return get_chart_helper_names(chart_library)
137
+
138
+
139
+ # ---------------------------------------------------------------------------
140
+ # SmartDataFrame alias — canonical class is SmartDataFrame (capital F).
141
+ # SmartDataframe (lower-case f) is kept as a backward-compatible alias.
142
+ # ---------------------------------------------------------------------------
143
+
144
+ # SmartDataFrame is already imported above; re-export the alias
145
+ SmartDataframe = SmartDataFrame # backward-compat alias
146
+
147
+
148
+ # ---------------------------------------------------------------------------
149
+ # I/O helpers — return SmartDataFrame directly
150
+ # ---------------------------------------------------------------------------
151
+
152
+ def DataFrame(
153
+ data: Any = None,
154
+ *,
155
+ config: Optional[dict[str, Any]] = None,
156
+ chart_library: Optional[str] = None,
157
+ **kwargs: Any,
158
+ ) -> SmartDataFrame:
159
+ """Create a :class:`SmartDataFrame` from any pandas-compatible input.
160
+
161
+ Args:
162
+ data: Data passed through to :class:`pandas.DataFrame`.
163
+ config: Optional dict of pychartai config overrides to apply.
164
+ chart_library: Default chart backend for this instance.
165
+ **kwargs: Forwarded to :class:`pandas.DataFrame`.
166
+ """
167
+ if isinstance(data, pd.DataFrame):
168
+ raw = data
169
+ elif isinstance(data, SmartDataFrame):
170
+ raw = data._df
171
+ else:
172
+ raw = pd.DataFrame(data, **kwargs)
173
+ sdf = SmartDataFrame(raw)
174
+ if chart_library:
175
+ global_config.set({'chart_backend': chart_library})
176
+ if config:
177
+ normalized = dict(config)
178
+ if 'chart_library' in normalized and 'chart_backend' not in normalized:
179
+ normalized['chart_backend'] = normalized.pop('chart_library')
180
+ global_config.set(normalized)
181
+ return sdf
182
+
183
+
184
+ def read_csv(
185
+ filepath_or_buffer: Any,
186
+ *,
187
+ config: Optional[dict[str, Any]] = None,
188
+ chart_library: Optional[str] = None,
189
+ **kwargs: Any,
190
+ ) -> SmartDataFrame:
191
+ """Read a CSV file and return a :class:`SmartDataFrame`."""
192
+ return DataFrame(pd.read_csv(filepath_or_buffer, **kwargs),
193
+ config=config, chart_library=chart_library)
194
+
195
+
196
+ def read_excel(
197
+ filepath_or_buffer: Any,
198
+ *,
199
+ config: Optional[dict[str, Any]] = None,
200
+ chart_library: Optional[str] = None,
201
+ **kwargs: Any,
202
+ ) -> SmartDataFrame:
203
+ """Read an Excel file and return a :class:`SmartDataFrame`."""
204
+ return DataFrame(pd.read_excel(filepath_or_buffer, **kwargs),
205
+ config=config, chart_library=chart_library)
206
+
207
+
208
+ def read_json(
209
+ filepath_or_buffer: Any,
210
+ *,
211
+ config: Optional[dict[str, Any]] = None,
212
+ chart_library: Optional[str] = None,
213
+ **kwargs: Any,
214
+ ) -> SmartDataFrame:
215
+ """Read a JSON file and return a :class:`SmartDataFrame`."""
216
+ return DataFrame(pd.read_json(filepath_or_buffer, **kwargs),
217
+ config=config, chart_library=chart_library)
218
+
219
+
220
+ def read_parquet(
221
+ filepath_or_buffer: Any,
222
+ *,
223
+ config: Optional[dict[str, Any]] = None,
224
+ chart_library: Optional[str] = None,
225
+ **kwargs: Any,
226
+ ) -> SmartDataFrame:
227
+ """Read a Parquet file and return a :class:`SmartDataFrame`."""
228
+ return DataFrame(pd.read_parquet(filepath_or_buffer, **kwargs),
229
+ config=config, chart_library=chart_library)
230
+
231
+
232
+ # ---------------------------------------------------------------------------
233
+ # Module-level chat() — multi-DataFrame queries
234
+ # ---------------------------------------------------------------------------
235
+
236
+ def _normalize_df(value: Any) -> pd.DataFrame:
237
+ """Coerce a SmartDataFrame or plain DataFrame to pd.DataFrame."""
238
+ if isinstance(value, SmartDataFrame):
239
+ return object.__getattribute__(value, '_df')
240
+ if isinstance(value, pd.DataFrame):
241
+ return value
242
+ raise TypeError(
243
+ f'pychartai.chat() expects pandas DataFrame or SmartDataFrame, got {type(value).__name__}'
244
+ )
245
+
246
+
247
+
248
+ def chat(
249
+ query: str,
250
+ *dataframes: Any,
251
+ sandbox: Optional[Any] = None,
252
+ chart_library: Optional[str] = None,
253
+ plot_type: Optional[str] = None,
254
+ chart_options: Optional[dict[str, Any]] = None,
255
+ model: Optional[Any] = None,
256
+ **chart_kwargs: Any,
257
+ ) -> str:
258
+ """Run a natural-language query over one or more DataFrames.
259
+
260
+ Call ``.chat()`` directly on a :class:`SmartDataFrame` (recommended)::
261
+
262
+ df = pai.read_csv('data.csv')
263
+ df.chat('Who earns the most?')
264
+
265
+ Args:
266
+ query: Natural-language question.
267
+ *dataframes: One or more :class:`pandas.DataFrame` or
268
+ :class:`SmartDataFrame` objects.
269
+ sandbox: Optional :class:`RestrictedSandbox` or
270
+ :class:`DockerSandbox`.
271
+ chart_library: Override the visualization backend
272
+ ('seaborn', 'matplotlib', 'plotly').
273
+ plot_type: Chart type hint (e.g. 'bar', 'line').
274
+ chart_options: Extra chart keyword options.
275
+ model: Optional model override. Can be a preset name,
276
+ ``"provider/model"`` string, or a ``PyChartLLM`` instance.
277
+ Falls back to global config if omitted.
278
+ **chart_kwargs: Additional chart parameters.
279
+
280
+ Returns:
281
+ Analysis result as a string, or a chart file path.
282
+
283
+ Raises:
284
+ ValueError: If no DataFrames are passed.
285
+ RuntimeError: If no LLM is configured.
286
+
287
+ """
288
+ if not dataframes:
289
+ raise ValueError('pychartai.chat() requires at least one DataFrame.')
290
+
291
+ # Resolve model: explicit > global config
292
+ llm = None
293
+ if model is not None:
294
+ if isinstance(model, (OllamaLLM, GitHubLLM, OpenAILLM, GeminiLLM,
295
+ AnthropicLLM, QwenLLM, DeepSeekLLM, GenericLLM)):
296
+ llm = model
297
+ elif isinstance(model, str):
298
+ from pychartai_core.model_config import _MODEL_REGISTRY, get_model, _build_from_provider
299
+ if model in _MODEL_REGISTRY:
300
+ llm = get_model(model)
301
+ elif '/' in model:
302
+ prov, mname = model.split('/', 1)
303
+ llm = _build_from_provider(prov, mname)
304
+ else:
305
+ raise KeyError(
306
+ f"Unknown model {model!r}. Use a preset name from models.yml, "
307
+ "'provider/model' format, or a PyChartLLM instance."
308
+ )
309
+ else:
310
+ raise TypeError(f"model must be str or PyChartLLM, got {type(model).__name__}")
311
+ else:
312
+ llm = config.get('llm')
313
+
314
+ if llm is None:
315
+ raise RuntimeError(
316
+ 'No LLM configured. '
317
+ "Use pai.init() at startup, e.g.: pai.init(model='deepseek-v4-flash')"
318
+ )
319
+
320
+ backend = chart_library or config.get('chart_backend', 'seaborn')
321
+ output_dir = config.get('charts_output_dir', 'exports/charts')
322
+ directive = SmartDataFrame._build_chart_directive(plot_type, chart_options, chart_kwargs)
323
+ effective_query = query + directive
324
+ frames = [_normalize_df(item) for item in dataframes]
325
+
326
+ if sandbox is not None:
327
+ from pychartai_core.agent import PyChartAgent
328
+ agent = PyChartAgent(llm=llm, chart_backend=backend, charts_output_dir=output_dir)
329
+ if len(frames) == 1:
330
+ return agent.chat(effective_query, frames[0])
331
+ # Multi-DataFrame: merge and query
332
+ import pandas as _pd
333
+ merged = _pd.concat(frames, ignore_index=True)
334
+ return agent.chat(effective_query, merged)
335
+
336
+ # Default path: use PyChartAgent
337
+ from pychartai_core.agent import PyChartAgent
338
+ agent = PyChartAgent(llm=llm, chart_backend=backend, charts_output_dir=output_dir)
339
+ if len(frames) == 1:
340
+ return agent.chat(effective_query, frames[0])
341
+ import pandas as _pd
342
+ merged = _pd.concat(frames, ignore_index=True)
343
+ return agent.chat(effective_query, merged)
344
+
345
+
346
+ async def achat(
347
+ query: str,
348
+ *dataframes: Any,
349
+ sandbox: Optional[Any] = None,
350
+ chart_library: Optional[str] = None,
351
+ plot_type: Optional[str] = None,
352
+ chart_options: Optional[dict[str, Any]] = None,
353
+ **chart_kwargs: Any,
354
+ ) -> str:
355
+ """Async wrapper around :func:`chat`.
356
+
357
+ Runs the synchronous call in a thread-pool executor so it can be awaited
358
+ without blocking the event loop::
359
+
360
+ result = await pai.achat('Who earns the most?', df)
361
+ """
362
+ import asyncio
363
+ loop = asyncio.get_event_loop()
364
+ return await loop.run_in_executor(
365
+ None,
366
+ lambda: chat(
367
+ query,
368
+ *dataframes,
369
+ sandbox=sandbox,
370
+ chart_library=chart_library,
371
+ plot_type=plot_type,
372
+ chart_options=chart_options,
373
+ **chart_kwargs,
374
+ ),
375
+ )
376
+
377
+
378
+ # ---------------------------------------------------------------------------
379
+ # Public API surface
380
+ # ---------------------------------------------------------------------------
381
+
382
+ __all__ = [
383
+ '__version__',
384
+ # Config
385
+ 'config',
386
+ # LLM providers
387
+ 'PyChartLLM',
388
+ 'OllamaLLM',
389
+ 'GitHubLLM',
390
+ 'OpenAILLM',
391
+ 'GeminiLLM',
392
+ 'AnthropicLLM',
393
+ 'QwenLLM',
394
+ 'DeepSeekLLM',
395
+ 'GenericLLM',
396
+
397
+ # DataFrame
398
+ 'SmartDataFrame',
399
+ 'SmartDataframe', # backward-compat alias
400
+ 'DataFrame',
401
+ 'read_csv',
402
+ 'read_excel',
403
+ 'read_json',
404
+ 'read_parquet',
405
+ # Agents
406
+ 'PyChartAgent',
407
+ 'TransformationLog',
408
+ 'QueryIntent',
409
+ # Module-level chat
410
+ 'chat',
411
+ 'achat',
412
+ # Sandbox & streaming
413
+ 'RestrictedSandbox',
414
+ 'DockerSandbox',
415
+ 'StreamEvent',
416
+ # Memory
417
+ 'ConversationMemory',
418
+ 'Turn',
419
+ # Profiling
420
+ 'DataProfiler',
421
+ 'ProfileReport',
422
+ # Themes
423
+ 'ChartTheme',
424
+ 'resolve_theme',
425
+ 'BUILTIN_THEMES',
426
+ # Skills
427
+ 'Skill',
428
+ 'skill',
429
+ # Semantic layer
430
+ 'Schema',
431
+ 'Column',
432
+ # Cache
433
+ 'ResponseCache',
434
+ # PII redaction
435
+ 'DataRedactor',
436
+ # Error hints
437
+ 'get_hint',
438
+ 'format_error_with_hint',
439
+ # Logging
440
+ 'get_logger',
441
+ 'configure_logger',
442
+ 'set_log_level',
443
+
444
+ # Pipeline
445
+ 'Pipeline',
446
+ 'PipelineStep',
447
+ 'PipelineContext',
448
+ 'ValidateInput',
449
+ 'InjectSchema',
450
+ 'InjectSkills',
451
+ 'CacheLookup',
452
+ 'CallAnalyzer',
453
+ 'CallOwnAgent',
454
+ 'CacheStore',
455
+ 'default_pipeline',
456
+ # Connections
457
+ 'BaseConnection',
458
+ 'CSVConnection',
459
+ 'ExcelConnection',
460
+ 'JSONConnection',
461
+ 'ParquetConnection',
462
+ 'SQLConnection',
463
+ 'connect',
464
+ # Database connectors
465
+ 'PostgreSQLConnection',
466
+ 'MySQLConnection',
467
+ 'SnowflakeConnection',
468
+ 'BigQueryConnection',
469
+ 'RedshiftConnection',
470
+ # Cloud storage connectors
471
+ 'S3Connection',
472
+ 'GCSConnection',
473
+ 'AzureBlobConnection',
474
+ 'GoogleSheetsConnection',
475
+ # Chart helpers (all 20)
476
+ 'area_chart',
477
+ 'bar_chart',
478
+ 'box_chart',
479
+ 'bubble_chart',
480
+ 'count_chart',
481
+ 'ecdf_chart',
482
+ 'funnel_chart',
483
+ 'heatmap',
484
+ 'histogram',
485
+ 'kde_chart',
486
+ 'line_chart',
487
+ 'pairplot_chart',
488
+ 'pie_chart',
489
+ 'regression_chart',
490
+ 'scatter_chart',
491
+ 'stacked_bar_chart',
492
+ 'step_chart',
493
+ 'strip_chart',
494
+ 'swarm_chart',
495
+ 'violin_chart',
496
+ # Utilities
497
+ 'available_backends',
498
+ 'available_charts',
499
+ 'get_hint',
500
+ 'format_error_with_hint',
501
+ # Reporting
502
+ 'InsightReporter',
503
+
504
+ ]
pychartai/cli.py ADDED
@@ -0,0 +1,91 @@
1
+ """pychartai.cli — command-line entry point.
2
+
3
+ pychartai data.csv "What is the average revenue by region?"
4
+ pychartai data.csv --profile
5
+ pychartai data.csv --report report.html
6
+ pychartai data.csv "Plot revenue by region" --provider openai --model gpt-4o --backend plotly
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import argparse
12
+ import sys
13
+
14
+ import pychartai as pai
15
+
16
+ _READERS = {
17
+ 'csv': pai.read_csv,
18
+ 'xlsx': pai.read_excel,
19
+ 'xls': pai.read_excel,
20
+ 'json': pai.read_json,
21
+ 'parquet': pai.read_parquet,
22
+ }
23
+
24
+ _LLM_BUILDERS = {
25
+ 'ollama': pai.OllamaLLM,
26
+ 'openai': pai.OpenAILLM,
27
+ 'github': pai.GitHubLLM,
28
+ 'qwen': pai.QwenLLM,
29
+ 'gemini': pai.GeminiLLM,
30
+ 'anthropic': pai.AnthropicLLM,
31
+ 'deepseek': pai.DeepSeekLLM,
32
+ }
33
+
34
+
35
+ def _load(path: str):
36
+ ext = path.rsplit('.', 1)[-1].lower() if '.' in path else ''
37
+ if ext not in _READERS:
38
+ raise ValueError(f'Unsupported file extension {ext!r}. Supported: {sorted(_READERS)}')
39
+ return _READERS[ext](path)
40
+
41
+
42
+ def main(argv=None) -> int:
43
+ ap = argparse.ArgumentParser(prog='pychartai', description=__doc__,
44
+ formatter_class=argparse.RawDescriptionHelpFormatter)
45
+ ap.add_argument('file', help='CSV/Excel/JSON/Parquet file to load')
46
+ ap.add_argument('query', nargs='?', help='Natural-language question (omit with --profile/--report)')
47
+ ap.add_argument('--provider', default='ollama', choices=sorted(_LLM_BUILDERS))
48
+ ap.add_argument('--model', default='llama3.2', help='Model name (default: llama3.2)')
49
+ ap.add_argument('--backend', choices=['seaborn', 'matplotlib', 'plotly'], help='Chart backend override')
50
+ ap.add_argument('--profile', action='store_true', help='Print an auto-EDA profile (no LLM call)')
51
+ ap.add_argument('--report', metavar='PATH', help='Write a self-contained HTML insight report to PATH')
52
+ args = ap.parse_args(argv)
53
+
54
+ # Use per-provider default model when the generic default doesn't apply
55
+ _DEFAULT_MODELS = {
56
+ 'openai': 'gpt-4o',
57
+ 'github': 'gpt-4.1',
58
+ 'qwen': 'qwen-plus',
59
+ 'gemini': 'gemini-2.0-flash',
60
+ 'anthropic': 'claude-3-5-sonnet-20241022',
61
+ 'deepseek': 'deepseek-chat',
62
+ }
63
+ if args.model == 'llama3.2' and args.provider in _DEFAULT_MODELS:
64
+ args.model = _DEFAULT_MODELS[args.provider]
65
+
66
+ if not args.query and not args.profile and not args.report:
67
+ ap.error('provide a query, or pass --profile / --report')
68
+
69
+ try:
70
+ df = _load(args.file)
71
+ except (ValueError, OSError) as exc:
72
+ print(f'pychartai: error: {exc}', file=sys.stderr)
73
+ return 1
74
+
75
+ if args.profile:
76
+ print(df.profile().summary)
77
+ return 0
78
+
79
+ if args.report:
80
+ path = df.report(args.report)
81
+ print(f'Report written to {path}')
82
+ return 0
83
+
84
+ pai.config.set({'llm': _LLM_BUILDERS[args.provider](model=args.model)})
85
+ result = df.chat(args.query, chart_library=args.backend) if args.backend else df.chat(args.query)
86
+ print(result)
87
+ return 0
88
+
89
+
90
+ if __name__ == '__main__':
91
+ sys.exit(main())