import pandas as pd
from typing import List
from utils import TEMP_DIR
import plotly.express as px
import plotly.io as pio
import os
from functions.chart_functions import scatter_chart_fig, llm_chart_data_scrub, _write_chart
from dotenv import load_dotenv
load_dotenv()
root_url = os.getenv("ROOT_URL", "")
def descriptive_stats_func(session_hash, session_folder, columns: List[str]=[], **kwargs):
print("DESCRIPTIVE STATISTICS")
try:
from html import escape
dir_path = TEMP_DIR / str(session_hash) / str(session_folder)
csv_query_path = f'{dir_path}/query.csv'
df = pd.read_csv(csv_query_path)
if columns:
df = df[[c for c in columns if c in df.columns]]
desc = df.describe().round(4)
header_cells = '
Statistic | ' + ''.join(
f'{escape(str(col))} | ' for col in desc.columns
)
row_html = [
''
+ f'| {escape(str(idx))} | '
+ ''.join(f'{escape(str(val))} | ' for val in row)
+ '
'
for idx, row in desc.iterrows()
]
style = (
''
)
table = (
''
f'{header_cells}
'
'' + '\n'.join(row_html) + ''
'
'
)
return {"reply": style + table}
except Exception as e:
print("DESCRIPTIVE STATS ERROR")
print(e)
return {"reply": f"There was an error generating descriptive statistics. Error: {e}. You should probably try again."}
def kmeans_clustering_func(feature_columns: List[str], x_column: str, y_column: str,
session_hash, session_folder, n_clusters: int = 3,
layout: List[dict] = [{}], **kwargs):
print("KMEANS CLUSTERING")
try:
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
from html import escape
dir_path = TEMP_DIR / str(session_hash) / str(session_folder)
chart_path = f'{dir_path}/chart.html'
csv_query_path = f'{dir_path}/query.csv'
df = pd.read_csv(csv_query_path)
feature_df = df[feature_columns].select_dtypes(include='number').dropna()
if feature_df.shape[1] < 1:
return {"reply": "No numeric feature columns found for clustering. Please refine your query to include numeric columns."}
X_scaled = StandardScaler().fit_transform(feature_df)
labels = KMeans(n_clusters=n_clusters, random_state=42, n_init=10).fit_predict(X_scaled)
df_clustered = df.loc[feature_df.index].copy()
df_clustered['Cluster'] = [f'Cluster {l}' for l in labels]
fig = px.scatter(
df_clustered, x=x_column, y=y_column, color='Cluster',
title=f'K-Means Clustering (k={n_clusters})',
)
fig.update_layout(font=dict(family='Inter, system-ui, sans-serif'))
_, layout_dict = llm_chart_data_scrub({}, layout)
if layout_dict:
fig.update_layout(**layout_dict)
chart_url = f'{root_url}/gradio_api/file/temp/{session_hash}/{session_folder}/chart.html'
iframe = _write_chart(fig, chart_path, chart_url)
cluster_summary = df_clustered.groupby('Cluster')[feature_columns].mean().round(3)
header_cells = 'Cluster | ' + ''.join(
f'{escape(str(col))} | ' for col in cluster_summary.columns
)
row_html = [
''
+ f'| {escape(str(idx))} | '
+ ''.join(f'{escape(str(val))} | ' for val in row)
+ '
'
for idx, row in cluster_summary.iterrows()
]
style = (
''
)
summary_table = (
''
f'{header_cells}
'
'' + '\n'.join(row_html) + ''
'
'
)
return {"reply": f'{iframe}\n\n**Cluster Centroids (feature means per cluster):**\n{style}{summary_table}'}
except Exception as e:
print("KMEANS CLUSTERING ERROR")
print(e)
return {"reply": f"There was an error running K-Means clustering. Error: {e}. You should probably try again."}
def hypothesis_test_func(test_type: str, column: str, session_hash, session_folder,
column2: str = "", group_column: str = "",
group_values: List[str] = [], pop_mean: float = 0.0, **kwargs):
print("HYPOTHESIS TEST")
try:
from scipy import stats
from html import escape
dir_path = TEMP_DIR / str(session_hash) / str(session_folder)
csv_query_path = f'{dir_path}/query.csv'
df = pd.read_csv(csv_query_path)
if test_type == "t_test_independent":
if not group_column or group_column not in df.columns:
return {"reply": "Please specify a valid group_column for the independent t-test."}
unique_groups = df[group_column].dropna().unique().tolist()
if group_values and len(group_values) == 2:
g1_label, g2_label = group_values[0], group_values[1]
elif len(unique_groups) == 2:
g1_label, g2_label = unique_groups[0], unique_groups[1]
else:
return {"reply": f"For an independent t-test, exactly 2 groups are needed. Found: {unique_groups}. Specify group_values with 2 entries."}
g1 = df[df[group_column] == g1_label][column].dropna()
g2 = df[df[group_column] == g2_label][column].dropna()
t_stat, p_value = stats.ttest_ind(g1, g2)
result_rows = [
("Test", "Independent Samples T-Test"),
("Column", column),
("Group Column", group_column),
(f"Group 1", str(g1_label)),
(f"Group 2", str(g2_label)),
(f"Group 1 Mean (n={len(g1)})", f"{g1.mean():.4f}"),
(f"Group 2 Mean (n={len(g2)})", f"{g2.mean():.4f}"),
("T-Statistic", f"{t_stat:.4f}"),
("P-Value", f"{p_value:.6f}"),
("Significant at α=0.05", "Yes ✓" if p_value < 0.05 else "No ✗"),
]
title = f"T-Test: {column} by {group_column}"
elif test_type == "t_test_one_sample":
sample = df[column].dropna()
t_stat, p_value = stats.ttest_1samp(sample, pop_mean)
result_rows = [
("Test", "One-Sample T-Test"),
("Column", column),
("Hypothesized Mean (μ₀)", f"{pop_mean:.4f}"),
(f"Sample Mean (n={len(sample)})", f"{sample.mean():.4f}"),
("Sample Std Dev", f"{sample.std():.4f}"),
("T-Statistic", f"{t_stat:.4f}"),
("P-Value", f"{p_value:.6f}"),
("Significant at α=0.05", "Yes ✓" if p_value < 0.05 else "No ✗"),
]
title = f"One-Sample T-Test: {column} vs μ={pop_mean}"
elif test_type == "chi_square":
if not column2 or column2 not in df.columns:
return {"reply": "Please specify a valid column2 for the chi-square test."}
contingency = pd.crosstab(df[column], df[column2])
chi2, p_value, dof, _ = stats.chi2_contingency(contingency)
result_rows = [
("Test", "Chi-Square Test of Independence"),
("Column 1", column),
("Column 2", column2),
("Chi-Square Statistic", f"{chi2:.4f}"),
("Degrees of Freedom", str(dof)),
("P-Value", f"{p_value:.6f}"),
("Significant at α=0.05", "Yes ✓" if p_value < 0.05 else "No ✗"),
]
title = f"Chi-Square: {column} × {column2}"
else:
return {"reply": f"Unknown test_type '{test_type}'. Use one of: t_test_independent, t_test_one_sample, chi_square."}
style = (
''
)
header_cells = f'{escape(title)} | '
row_html = [
''
+ f'| {escape(label)} | '
+ f'{escape(value)} | '
+ '
'
for label, value in result_rows
]
table = (
''
f'{header_cells}
'
'' + '\n'.join(row_html) + ''
'
'
)
return {"reply": style + table}
except Exception as e:
print("HYPOTHESIS TEST ERROR")
print(e)
return {"reply": f"There was an error running the hypothesis test. Error: {e}. You should probably try again."}
def regression_func(independent_variables: List[str], dependent_variable: str, session_hash, session_folder, category: str='', **kwargs):
print("LINEAR REGRESSION CALCULATION")
print(independent_variables)
print(dependent_variable)
try:
dir_path = TEMP_DIR / str(session_hash) / str(session_folder)
chart_path = f'{dir_path}/chart.html'
csv_query_path = f'{dir_path}/query.csv'
df = pd.read_csv(csv_query_path)
if category in df.columns:
fig = scatter_chart_fig(df=df, x_column=independent_variables,y_column=dependent_variable,
category=category,trendline="ols")
else:
fig = scatter_chart_fig(df=df,x_column=independent_variables,y_column=dependent_variable,
trendline="ols")
chart_url = f'{root_url}/gradio_api/file/temp/{session_hash}/{session_folder}/chart.html'
iframe = _write_chart(fig, chart_path, chart_url)
results_frame = px.get_trendline_results(fig)
print("RESULTS")
print(results_frame)
print(results_frame.at[0, 'px_fit_results'])
results = results_frame.at[0, 'px_fit_results']
print(results.summary())
return {"reply": '{"regression_summary": %s, "regression_chart": %s' % (str(results.summary()), str(iframe))}
except Exception as e:
print("LINEAR REGRESSION ERROR")
print(e)
reply = f"""There was an error generating the linear regression calculation from {independent_variables} and {dependent_variable}
The error is {e},
You should probably try again.
"""
return {"reply": reply}