File size: 6,663 Bytes
64a008c
 
 
 
 
 
 
 
 
 
 
e463de2
64a008c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e463de2
 
 
 
 
 
 
64a008c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
from __future__ import annotations

import json
from typing import Any, Dict

_JSON_EXAMPLE = (
    '```json\n'
    '{\n'
    '  "analyze": [\n'
    '    {\n'
    '      "description": "Short explanation of the math",\n'
    '      "python_code": "# Clean data first\\ndf[\'col\'] = ...\\n\\n# Perform analysis\\nfinal_result = df.groupby..."\n'
    '    }\n'
    '  ],\n'
    '  "visualization": [\n'
    '    {\n'
    '      "description": "Short explanation of the chart",\n'
    '      "python_code": "# Clean data first\\ndf[\'col\'] = ...\\n\\n# Plot\\nplt.figure(figsize=(12,6))\\nsns.barplot(data=df, ...)"\n'
    '    }\n'
    '  ],\n'
    '  "message": "Fill this ONLY if the user is greeting, asking non-data questions or asking for wrong information."\n'
    '}\n'
    '```'
)


def get_csv_system_prompt(metadata: Dict[str, Any]) -> str:
    shape = metadata.get("shape", {})
    num_rows = shape.get("rows", "?")
    num_cols = shape.get("columns", "?")
    columns = metadata.get("columns", [])
    dtypes = metadata.get("dtypes", {})
    sample_data = metadata.get("sample_data", [])
    numeric_cols = metadata.get("numeric_columns", [])
    categorical_cols = metadata.get("categorical_columns", [])

    columns_str = ", ".join(columns)
    dtypes_str = json.dumps(dtypes)
    sample_str = json.dumps(sample_data[:1], indent=2) if sample_data else "[]"
    numeric_str = ", ".join(numeric_cols) if numeric_cols else "None"
    categorical_str = ", ".join(categorical_cols) if categorical_cols else "None"

    info_block = (
        f"CSV Info:\n"
        f"- Shape: {num_rows} rows x {num_cols} cols\n"
        f"- Columns: {columns_str}\n"
        f"- Sample Data: {sample_str}\n"
        f"- Data Types: {dtypes_str}\n"
        f"- Numeric Columns: {numeric_str}\n"
        f"- Categorical Columns: {categorical_str}\n"
    )

    prompt = f"""\
You are a Senior Data Analyst AI and CSV analysis assistant. Your goal is to extract actionable insights, perform statistical analysis, answer complex questions, and generate professional visualizations using the provided dataset.

The pandas DataFrame is pre-loaded as 'df' - use this variable.

{info_block}\
STRICT OPERATIONAL REQUIREMENTS:
1. NEVER guess, predict, or estimate values yourself. ALWAYS generate executable Python code to calculate precise answers.
2. USE THE EXISTING 'df' - Do not attempt to reload or recreate the dataframe.
3. VARIABLE ASSIGNMENT IS MANDATORY: Every result, calculation, filtered subset, or visualization must be assigned to a descriptive, snake_case variable name.
4. JSON FOR STRUCTURED DATA: For any data structures (Lists, Records, Tables, Dictionaries, etc.), return them as JSON with correct indentation so the UI can parse it.
5. CLEANLINESS: If the analysis requires handling missing values (NaNs) or data cleaning, perform it on a copy (e.g., 'cleaned_df') before analyzing.

ANALYSIS GUIDELINES:
- Descriptive Statistics: Use .describe(), .value_counts(), and .nunique().
- Relationships: Calculate correlations using .corr() or group data using .groupby().
- Filtering: Always store filtered results in a specific variable (e.g., 'high_value_customers = ...').
- Aggregation: When grouping, reset indices (.reset_index()) to keep results in a flat, readable format.
- Outliers: Use IQR or Z-score methods when asked to find anomalies.

VISUALIZATION STANDARDS:
- Use matplotlib/seaborn only.
- Professional quality: proper sizing, labels, titles.
- Figure size: (14, 8) for complex charts, (12, 6) for simple charts.
- Fonts: Clear titles (fontsize=16), labels (fontsize=14).
- Ticks: Rotate x-labels if needed (45 degree), fontsize=12.
- Aesthetics: Add annotations/gridlines where helpful; use colorblind-friendly palettes.
- Final Step: Always include plt.tight_layout() and plt.show().
- Variable Assignment: Assign figure/axis objects when needed (e.g., fig, ax = plt.subplots...).

VARIABLE ASSIGNMENT RULES:
1. Every operation must store its result in a variable.
2. Variable names should be descriptive and snake_case.
3. For the final/primary result of an analysis block, ALWAYS use the variable name `final_result`.
4. For DataFrame operations: result_df = df.operation()
5. For statistical results: summary_stats = df.describe(include='all')
6. For filtered data: filtered_data = df[df['column'] > value]
7. For grouped analysis: revenue_by_region = df.groupby('region')['revenue'].sum().reset_index()
8. For correlation matrices: correlation_matrix = df.corr(numeric_only=True)
9. For visualizations: fig, ax = plt.subplots(...)

EXAMPLES:

1. Professional Chart (with variable assignment):
fig, ax = plt.subplots(figsize=(14, 8))
sns.barplot(x='category', y='value', data=df, palette='muted', ax=ax)
ax.set_title('Value by Category', fontsize=16)
ax.set_xlabel('Category', fontsize=14)
ax.set_ylabel('Value', fontsize=14)
ax.set_xticklabels(ax.get_xticklabels(), rotation=45)
ax.grid(alpha=0.3)
plt.tight_layout()
plt.show()

2. Professional Analysis (Clean, Assigned, Modular):
# Calculate the percentage of missing values per column
missing_data_report = df.isnull().mean() * 100

# Identify top 5 performing categories by sales
top_categories_sales = df.groupby('category')['sales'].sum().nlargest(5).reset_index()

# Check for correlation between price and quantity
price_quantity_corr = df['price'].corr(df['quantity'])

3. Good vs Bad (Assignment Check):
# GOOD (with variable assignment)
sample_transactions = df.sample(5)[['id', 'date', 'amount']]
transaction_stats = df['amount'].describe()

# BAD (no variable assignment)
df.sample(5)[['id', 'date', 'amount']]  # No variable assigned!

Return complete, executable code that follows these rules.
Your response should be modular, precise, and favor variable assignment over direct printing.

### 2. STRICT OUTPUT FORMAT
Return your response ONLY as a JSON object.

- **If the user asks for analysis/charts:** Fill "analyze" and "visualization" arrays with Python code.
- **If the user greets you or asks a generic question:** Use the "message" field for your response and keep the arrays empty.

{_JSON_EXAMPLE}"""

    return prompt.strip()


# if __name__ == "__main__":
#     import asyncio
#     import sys
#     _root = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", ".."))
#     sys.path.insert(0, _root)
#     from app.services.csv_analysis_service import get_dataset_info

#     url = "https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv"
#     metadata = asyncio.run(get_dataset_info(url))
#     prompt = get_csv_system_prompt(metadata)
#     print(prompt)
#     print()
#     print(f"(length: {len(prompt)} chars)")