crewlyze 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/.dockerignore +12 -0
  2. package/.gitattributes +2 -0
  3. package/CHANGELOG.md +86 -0
  4. package/Dockerfile +21 -0
  5. package/LICENSE +21 -0
  6. package/README.md +139 -0
  7. package/USAGE.md +106 -0
  8. package/agents/__init__.py +0 -0
  9. package/agents/cleaner.py +38 -0
  10. package/agents/insights.py +44 -0
  11. package/agents/relation.py +36 -0
  12. package/agents/visualizer.py +41 -0
  13. package/assets/badge_crewai.svg +4 -0
  14. package/assets/badge_matplotlib.svg +4 -0
  15. package/assets/badge_ollama.svg +4 -0
  16. package/assets/badge_pandas.svg +4 -0
  17. package/assets/badge_seaborn.svg +4 -0
  18. package/assets/branding_image.png +0 -0
  19. package/assets/complete_workflow.svg +216 -0
  20. package/assets/favicon.png +0 -0
  21. package/assets/logo.png +0 -0
  22. package/assets/stars.svg +12 -0
  23. package/bin/crewlyze.js +79 -0
  24. package/config/README.md +129 -0
  25. package/config/__init__.py +1 -0
  26. package/config/context.py +16 -0
  27. package/config/llm_config.py +300 -0
  28. package/config/metrics_tracker.py +70 -0
  29. package/crew.py +870 -0
  30. package/crewlyze-3.1.0.tgz +0 -0
  31. package/fix_syntax.py +54 -0
  32. package/main.py +1279 -0
  33. package/package.json +22 -0
  34. package/pyproject.toml +32 -0
  35. package/requirements.txt +33 -0
  36. package/tools/__init__.py +0 -0
  37. package/tools/dataset_tools.py +803 -0
  38. package/ui/__init__.py +3 -0
  39. package/ui/copilot.py +200 -0
  40. package/ui/export.py +800 -0
  41. package/update_appjs.py +54 -0
  42. package/update_llm.py +21 -0
  43. package/update_main.py +20 -0
  44. package/web/app.js +3142 -0
  45. package/web/index.html +1105 -0
  46. package/web/style.css +2561 -0
  47. package/workflows/__init__.py +0 -0
  48. package/workflows/pipeline.py +254 -0
File without changes
@@ -0,0 +1,254 @@
1
+ # Crewlyze
2
+ # Copyright (c) 2025 Sowmiyan S
3
+ # Licensed under the MIT License
4
+
5
+ """
6
+ Pipeline factory.
7
+
8
+ Performance improvements in this version:
9
+ - make_pipeline() accepts a pre-computed `profile` string and embeds it
10
+ directly into each task description. This eliminates the 6-8 LLM tool-call
11
+ round-trips agents would otherwise spend reading the dataset before acting.
12
+ - visualize_task no longer uses context=[...] — the caller (run_crew) injects
13
+ relation + insight outputs into the task description after parallel execution.
14
+ - Adaptive cooldown: sleeps only when a rate-limit error is detected; otherwise
15
+ uses a configurable minimum delay (default 5s, 0 for self-hosted providers).
16
+
17
+ Quality improvements:
18
+ - Insight task mandates an ex-McKinsey/BCG format: Observation ➔ Implication ➔ Strategy.
19
+ - Visualizer task mandates corporate styling guidelines (Grid, Hex Palette, Tight Layout, DPI).
20
+ """
21
+
22
+ import os
23
+ import time
24
+ from pathlib import Path
25
+ from typing import Optional
26
+
27
+ from crewai import Task
28
+
29
+ from agents.cleaner import make_cleaner_agent
30
+ from agents.relation import make_relation_agent
31
+ from agents.insights import make_insights_agent
32
+ from agents.visualizer import make_visualizer_agent
33
+
34
+
35
+ # ---------------------------------------------------------------------------
36
+ # Adaptive cooldown callback
37
+ # ---------------------------------------------------------------------------
38
+
39
+ _RATE_LIMIT_SIGNALS = ("rate limit", "429", "too many requests", "quota")
40
+
41
+ def make_cooldown_callback(min_sleep: int = 5):
42
+ """
43
+ Return a task callback that sleeps adaptively based on API feedback.
44
+
45
+ - If the task output contains rate-limit signals → exponential back-off
46
+ starting at max(min_sleep, 10) seconds.
47
+ - Otherwise → sleep min_sleep seconds (0 = no wait, ideal for Ollama).
48
+
49
+ Args:
50
+ min_sleep: Base sleep in seconds between tasks (from API_COOLDOWN env var).
51
+ """
52
+ state = {"failures": 0}
53
+
54
+ def _callback(task_output) -> None:
55
+ output_str = str(task_output).lower() if task_output else ""
56
+ hit_rate_limit = any(sig in output_str for sig in _RATE_LIMIT_SIGNALS)
57
+
58
+ if hit_rate_limit:
59
+ state["failures"] += 1
60
+ delay = min(max(min_sleep, 10) * (2 ** (state["failures"] - 1)), 120)
61
+ print(f"\nRate-limit detected. Back-off sleep: {delay}s ...")
62
+ time.sleep(delay)
63
+ elif min_sleep > 0:
64
+ state["failures"] = max(0, state["failures"] - 1) # cool down error count
65
+ print(f"\nTask complete. Cooldown: {min_sleep}s ...")
66
+ time.sleep(min_sleep)
67
+ else:
68
+ print("\nTask complete. No cooldown (min_sleep=0).")
69
+
70
+ return _callback
71
+
72
+
73
+ # ---------------------------------------------------------------------------
74
+ # Pipeline factory
75
+ # ---------------------------------------------------------------------------
76
+
77
+ def make_pipeline(
78
+ session_id: str,
79
+ profile: str = "",
80
+ selected_tasks: Optional[list[str]] = None,
81
+ deep_analysis: bool = False,
82
+ project_goal: str = "",
83
+ report_title: str = "",
84
+ existing_relations: str = "",
85
+ coercion_summary: str = "",
86
+ ) -> tuple[list, list]:
87
+ """
88
+ Build and return (agents, tasks) for a single analysis run.
89
+
90
+ Every call creates fresh agent instances (picks up the latest LLM config)
91
+ and embeds the session-specific CSV and output paths + dataset profile
92
+ into each task description.
93
+ """
94
+ user_home = Path.home() / ".crewlyze"
95
+ sessions_dir = Path(os.getenv("CREWLYZE_DATA_DIR", str(user_home / "data"))) / "sessions"
96
+ outputs_dir_base = Path(os.getenv("CREWLYZE_OUTPUTS_DIR", str(user_home / "outputs")))
97
+
98
+ csv_path = str((sessions_dir / session_id / "cleaned.csv").resolve())
99
+ output_dir = str((outputs_dir_base / session_id).resolve())
100
+
101
+ from config.context import current_cooldown
102
+ ctx_cooldown = current_cooldown.get()
103
+ cooldown = int(ctx_cooldown) if ctx_cooldown is not None else int(os.getenv("API_COOLDOWN", "5"))
104
+ cb = make_cooldown_callback(min_sleep=cooldown)
105
+
106
+ selected_tasks = [task.strip().lower() for task in (selected_tasks or []) if task.strip()]
107
+ if not selected_tasks:
108
+ selected_tasks = ["cleaning", "relations", "insights", "visualization"]
109
+
110
+ profile_block = (
111
+ f"\n\n--- DATASET PROFILE (use this — do NOT call read_dataset_head or "
112
+ f"get_dataset_info first) ---\n{profile}\n---"
113
+ if profile else ""
114
+ )
115
+
116
+ # Fresh agents — LLM config is read NOW, not at import time
117
+ cleaner_agent = make_cleaner_agent()
118
+ relation_agent = make_relation_agent()
119
+ insights_agent = make_insights_agent()
120
+ visualizer_agent = make_visualizer_agent()
121
+
122
+ deep_prompt = "\n\nIf deep analysis mode is enabled, provide richer reasoning, deeper causal exploration, and more detailed business implications for each recommendation." if deep_analysis else ""
123
+
124
+ goal_context = f"\nThe user has set the following goal for this project: '{project_goal}'." if project_goal else ""
125
+
126
+ coercion_block = (
127
+ f"\n\n--- AUTOMATIC TYPE CONVERSIONS PERFORMED ---\n{coercion_summary}\n"
128
+ "Explain the business rationale of these automatic type conversions in your final report."
129
+ if coercion_summary else ""
130
+ )
131
+
132
+ cleaning_prompt = (
133
+ f"The dataset working copy is at '{csv_path}'. "
134
+ f"{goal_context} "
135
+ "Identify data quality issues from the profile below, then write and run "
136
+ "Python cleaning code using 'Clean Dataset with Python Code' to fix them. "
137
+ "Explain the business rationale of each cleaning step in the final report in a simple, clear, and readable manner, using easy-to-understand language and avoiding complex jargon."
138
+ f"{coercion_block}"
139
+ f"{deep_prompt}{profile_block}"
140
+ )
141
+
142
+ clean_task = Task(
143
+ agent=cleaner_agent,
144
+ description=cleaning_prompt,
145
+ expected_output=(
146
+ "A plain-text bulleted list of cleaning steps explaining the business purpose. Example:\n"
147
+ "- Imputed missing revenue values with median to prevent statistical skew in sales reports\n"
148
+ "- Standardized country names to enable consistent geographic breakdown"
149
+ ),
150
+ callback=cb,
151
+ )
152
+
153
+ relation_prompt = (
154
+ f"First, examine the 5 sample rows and column details in the dataset profile of '{csv_path}'. "
155
+ "Identify the data type of each column (e.g. Unique ID, Categorical, Continuous Numeric, Timestamp, Key Column). "
156
+ f"Then, identify 5 key column relationships with high business relevance, focusing on correlations or connections that align with the user's project goal: '{project_goal}'. "
157
+ "Format the output STRICTLY as:\n"
158
+ "- X: [Column1] | Y: [Column2] | Type: [PlotType] | Details: [Relationship details, data type mapping of both columns, and business relevance in simple, understandable terms]\n"
159
+ "Output NOTHING else."
160
+ f"{profile_block}"
161
+ )
162
+
163
+ relation_task = Task(
164
+ agent=relation_agent,
165
+ description=relation_prompt,
166
+ expected_output=(
167
+ "Strictly formatted list of relationships. Example:\n"
168
+ "- X: Age | Y: Income | Type: Scatter Plot | Details: Age (Continuous Numeric) vs Income (Continuous Numeric). Displays moderate positive correlation, key for targeting demographics."
169
+ ),
170
+ callback=cb,
171
+ )
172
+
173
+ relations_context = f"\n\n--- TWEAKED SCHEMA & VERIFIED RELATIONSHIPS (use these verified columns & relationships to guide your analysis) ---\n{existing_relations}\n---" if existing_relations else ""
174
+
175
+ goal_prompt = f"Align all insights and strategies directly to address the project goal: '{project_goal}'." if project_goal else ""
176
+ insight_prompt = (
177
+ "Using the dataset profile and identified relationships provided below, "
178
+ "generate a comprehensive structured report focusing on the data, the business context, and the overall dataset. "
179
+ "The main goal of your analysis is to explain not only the raw numbers, but the business context, the overall dataset structure, and the actionable business strategies.\n"
180
+ "Ensure all text is written in an exceptionally clear, readable, and simple manner. "
181
+ "Explain statistics and insights using accessible language that an executive can immediately understand. "
182
+ "Avoid academic jargon, dense mathematical explanations, or overly complex terms.\n"
183
+ f"{goal_prompt}\n"
184
+ "Format the report using markdown headers EXACTLY as follows:\n\n"
185
+ "### Objectives & Goals\n"
186
+ "[Describe the primary objective and business goals of this analysis based on the project goal and dataset profile]\n\n"
187
+ "### Dataset Statistics\n"
188
+ "- Total rows: [row count]\n"
189
+ "- Total columns: [col count]\n"
190
+ "- Numeric columns: [list numeric columns and their min/max values]\n"
191
+ "- Categorical columns: [list categorical columns]\n\n"
192
+ "### Strategic Insights\n"
193
+ "Generate 5 key business insights. Each insight MUST strictly use this structure:\n"
194
+ "1. **Observation**: [Describe the exact trend, anomaly, or correlation from the data]\n"
195
+ " **Business Implication**: [Explain how this impacts profitability, risk, operation, or customers]\n"
196
+ " **Actionable Strategy**: [Outline a concrete recommendation that the organization should implement immediately]\n\n"
197
+ "### Warnings & Alerts\n"
198
+ "[List any warning or alert (e.g. data quality issues, outlier presence, class imbalance, missing values, declining trends) that a data scientist or business user should be aware of]"
199
+ f"{relations_context}"
200
+ f"{profile_block}"
201
+ )
202
+
203
+ insight_task = Task(
204
+ agent=insights_agent,
205
+ description=insight_prompt,
206
+ expected_output="A structured report in markdown format containing Objectives & Goals, Dataset Statistics, Strategic Insights, and Warnings & Alerts.",
207
+ callback=cb,
208
+ )
209
+
210
+ viz_goal_prompt = f"\nFocus visualizations on answering or addressing the project goal: '{project_goal}'." if project_goal else ""
211
+ visualize_prompt = (
212
+ "Examine the columns and data types from the profile below. Using your AI reasoning, select "
213
+ "the 3-4 most insightful relationships, trends, or distributions that characterize this specific dataset.\n"
214
+ f"{viz_goal_prompt}\n"
215
+ "Then, write and execute Python plotting code using 'Execute Visualization Code'.\n\n"
216
+ "ENVIRONMENT NOTE:\n"
217
+ "- The pandas DataFrame is pre-loaded as `df` in your execution environment.\n"
218
+ "- Pre-defined variable `OUTPUT_DIR` contains the target output folder path.\n"
219
+ "- A helper function `save_chart(filename_string)` is available to save the current figure.\n"
220
+ "- Matplotlib and Seaborn are pre-imported. Do NOT load CSVs or create folders yourself!\n\n"
221
+ "CODE REQUIREMENTS:\n"
222
+ "- Set style theme: 'sns.set_theme(style=\"whitegrid\", palette=\"muted\")'\n"
223
+ "- Apply clean white/light styling: set figure facecolor to 'white', axes facecolor to '#f8fafc', grid lines to a subtle light gray, and tick/label text to '#334155'.\n"
224
+ "- Use high-contrast corporate hex colors (e.g. `#4f46e5` for Indigo/Blue, `#06b6d4` for Cyan/Teal, `#ec4899` for Pink, `#10b981` for Emerald).\n"
225
+ "- Set figure size to `(10, 6)` or `(12, 6)`.\n"
226
+ "- Set clear, descriptive titles and wrap long titles: 'plt.title(textwrap.fill(title, 40))'.\n"
227
+ "- Apply 'sns.despine(left=True, bottom=True)' to remove borders.\n"
228
+ "- Save each plot with: `save_chart('chart_name')`.\n"
229
+ "- Call `plt.close()` immediately after each save to clear the state."
230
+ f"{relations_context}"
231
+ f"{profile_block}"
232
+ )
233
+
234
+ visualize_task = Task(
235
+ agent=visualizer_agent,
236
+ description=visualize_prompt,
237
+ expected_output="Summary of the 3-4 custom visualization plots generated and saved.",
238
+ callback=cb,
239
+ )
240
+
241
+ agents = [cleaner_agent, relation_agent, insights_agent, visualizer_agent]
242
+ tasks = [clean_task, relation_task, insight_task, visualize_task]
243
+
244
+ # If a stage is disabled, return placeholder tasks for safe indexing.
245
+ if "cleaning" not in selected_tasks:
246
+ tasks[0] = clean_task
247
+ if "relations" not in selected_tasks:
248
+ tasks[1] = relation_task
249
+ if "insights" not in selected_tasks:
250
+ tasks[2] = insight_task
251
+ if "visualization" not in selected_tasks:
252
+ tasks[3] = visualize_task
253
+
254
+ return agents, tasks