File size: 5,674 Bytes
f857e93
236b28e
 
 
 
 
 
 
f857e93
 
 
 
 
 
236b28e
 
 
 
f857e93
 
 
236b28e
f857e93
236b28e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f857e93
236b28e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f857e93
236b28e
 
 
 
 
f857e93
236b28e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f857e93
 
236b28e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# app.py
import gradio as gr
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from PIL import Image
import io

from transformers import T5Tokenizer, T5ForConditionalGeneration

# Load trained model
model_path = './t5_summarizer'
tokenizer = T5Tokenizer.from_pretrained(model_path)
model = T5ForConditionalGeneration.from_pretrained(model_path)

# --- Local summarizer ---
def summarize_with_local_model(prompt):
    try:
        inputs = tokenizer("summarize: " + prompt, return_tensors="pt", max_length=512, truncation=True)
        summary_ids = model.generate(inputs["input_ids"], max_length=128)
        return tokenizer.decode(summary_ids[0], skip_special_tokens=True)
    except Exception as e:
        return f"Summary Failed: {str(e)}"

# --- Chart generator ---
def generate_static_chart(df, chart_type, x, y=None):
    try:
        plt.figure(figsize=(10, 6))
        if chart_type == "bar":
            if y:
                sns.barplot(data=df, x=x, y=y)
            else:
                df[x].value_counts().plot(kind='bar')
        elif chart_type == "pie":
            df[x].value_counts().plot.pie(autopct='%1.1f%%')
        elif chart_type == "line" and y:
            sns.lineplot(data=df, x=x, y=y)
        elif chart_type == "scatter" and y:
            sns.scatterplot(data=df, x=x, y=y)
        elif chart_type == "hist":
            sns.histplot(df[x], bins=10, kde=True)
        elif chart_type == "correlation heatmap":
            corr = df.select_dtypes(include='number').corr()
            sns.heatmap(corr, annot=True, cmap='coolwarm', fmt=".2f")
        else:
            return None

        plt.title(f"{chart_type.capitalize()} of {x}" + (f" vs {y}" if y else ""))
        if y:
            plt.legend([y])
        plt.tight_layout()
        buf = io.BytesIO()
        plt.savefig(buf, format='png')
        buf.seek(0)
        return Image.open(buf)

    except Exception as e:
        print("Chart error:", e)
        return None

# --- Main logic ---
def visualize(csv_file, chart_type, x_col, y_col):
    if csv_file is None:
        raise gr.Error("Please upload a CSV file.")
    if not chart_type:
        raise gr.Error("Please select a chart type.")

    try:
        df = pd.read_csv(csv_file.name)
    except Exception as e:
        return f"Error reading CSV: {e}", None, "Error loading CSV."

    if x_col not in df.columns or (y_col and y_col not in df.columns):
        return (
            f"Invalid column names. Available columns: {', '.join(df.columns)}",
            None,
            df.to_markdown()
        )

    numeric_required = ["line", "scatter", "hist", "correlation heatmap"]
    if chart_type in numeric_required:
        if not pd.api.types.is_numeric_dtype(df[x_col]) or (y_col and not pd.api.types.is_numeric_dtype(df[y_col])):
            return (
                f"The chart type '{chart_type}' requires numeric columns.",
                None,
                df.to_markdown()
            )

    sample = df[[x_col] + ([y_col] if y_col else [])].head(10).to_csv(index=False)
    prompt = f"Analyze this {chart_type} chart with sample data:\n{sample}\nIdentify trends or insights."
    summary = summarize_with_local_model(prompt)

    chart = generate_static_chart(df, chart_type, x_col, y_col)
    if chart is None:
        return "Chart generation failed. Try different columns.", None, df.to_markdown()

    return summary, chart, df.to_markdown()

# --- Column selector helper ---
def get_columns(csv_file):
    try:
        df = pd.read_csv(csv_file.name)
        cols = list(df.columns)
        has_numeric = not df.select_dtypes(include='number').empty
        chart_choices = ["bar", "pie"] + (["line", "scatter", "hist", "correlation heatmap"] if has_numeric else [])
        return (
            gr.update(choices=cols, visible=True),
            gr.update(choices=cols, visible=True),
            ", ".join(cols),
            gr.update(choices=chart_choices)
        )
    except Exception as e:
        return (
            gr.update(visible=False),
            gr.update(visible=False),
            f"Error: {e}",
            gr.update(choices=[])
        )

def reset_outputs():
    return "", None, "", gr.update(visible=False), gr.update(visible=False), gr.update(choices=[])

# --- Gradio Interface ---
demo = gr.Blocks()

with demo:
    gr.Markdown("## πŸ“Š Smart Data Visualizer with Local AI Summary (T5)")
    gr.Markdown("Upload a CSV and select columns to visualize. AI will describe trends.")

    with gr.Row():
        csv_file = gr.File(label="Upload CSV", file_types=[".csv"])
        chart_type = gr.Dropdown([], label="Chart Type")

    with gr.Row():
        x_input = gr.Dropdown(label="X-axis Column", visible=False)
        y_input = gr.Dropdown(label="Y-axis Column (optional)", visible=False)

    available_cols = gr.Markdown("")

    with gr.Row():
        summary_output = gr.Textbox(label="πŸ“„ AI Summary")
        chart_output = gr.Image(type="pil", label="πŸ“Š Chart")

    with gr.Accordion("πŸ“‹ Full CSV Preview", open=False):
        csv_preview = gr.Markdown("")

    run_btn = gr.Button("Generate Visualization")

    run_btn.click(
        fn=visualize,
        inputs=[csv_file, chart_type, x_input, y_input],
        outputs=[summary_output, chart_output, csv_preview]
    )

    csv_file.change(
        fn=get_columns,
        inputs=csv_file,
        outputs=[x_input, y_input, available_cols, chart_type]
    )

    csv_file.clear(
        fn=reset_outputs,
        inputs=None,
        outputs=[summary_output, chart_output, csv_preview, x_input, y_input, chart_type]
    )

if __name__ == "__main__":
    demo.launch()