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.
- package/.dockerignore +12 -0
- package/.gitattributes +2 -0
- package/CHANGELOG.md +86 -0
- package/Dockerfile +21 -0
- package/LICENSE +21 -0
- package/README.md +139 -0
- package/USAGE.md +106 -0
- package/agents/__init__.py +0 -0
- package/agents/cleaner.py +38 -0
- package/agents/insights.py +44 -0
- package/agents/relation.py +36 -0
- package/agents/visualizer.py +41 -0
- package/assets/badge_crewai.svg +4 -0
- package/assets/badge_matplotlib.svg +4 -0
- package/assets/badge_ollama.svg +4 -0
- package/assets/badge_pandas.svg +4 -0
- package/assets/badge_seaborn.svg +4 -0
- package/assets/branding_image.png +0 -0
- package/assets/complete_workflow.svg +216 -0
- package/assets/favicon.png +0 -0
- package/assets/logo.png +0 -0
- package/assets/stars.svg +12 -0
- package/bin/crewlyze.js +79 -0
- package/config/README.md +129 -0
- package/config/__init__.py +1 -0
- package/config/context.py +16 -0
- package/config/llm_config.py +300 -0
- package/config/metrics_tracker.py +70 -0
- package/crew.py +870 -0
- package/crewlyze-3.1.0.tgz +0 -0
- package/fix_syntax.py +54 -0
- package/main.py +1279 -0
- package/package.json +22 -0
- package/pyproject.toml +32 -0
- package/requirements.txt +33 -0
- package/tools/__init__.py +0 -0
- package/tools/dataset_tools.py +803 -0
- package/ui/__init__.py +3 -0
- package/ui/copilot.py +200 -0
- package/ui/export.py +800 -0
- package/update_appjs.py +54 -0
- package/update_llm.py +21 -0
- package/update_main.py +20 -0
- package/web/app.js +3142 -0
- package/web/index.html +1105 -0
- package/web/style.css +2561 -0
- package/workflows/__init__.py +0 -0
- 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
|