tyty-cli-guy commited on
Commit
d07eb95
Β·
verified Β·
1 Parent(s): f305c4c

Upload folder using huggingface_hub

Browse files
Files changed (3) hide show
  1. __pycache__/app.cpython-311.pyc +0 -0
  2. app.py +502 -80
  3. requirements.txt +5 -3
__pycache__/app.cpython-311.pyc ADDED
Binary file (29 kB). View file
 
app.py CHANGED
@@ -1,14 +1,19 @@
1
  import io
2
  import random
3
  from typing import List, Tuple
4
-
5
  import aiohttp
6
  import panel as pn
 
 
 
7
  from PIL import Image
8
  from transformers import CLIPModel, CLIPProcessor
 
9
 
10
- pn.extension(design="bootstrap", sizing_mode="stretch_width")
 
11
 
 
12
  ICON_URLS = {
13
  "brand-github": "https://github.com/holoviz/panel",
14
  "brand-twitter": "https://twitter.com/Panel_Org",
@@ -17,15 +22,61 @@ ICON_URLS = {
17
  "brand-discord": "https://discord.gg/AXRHnJU6sP",
18
  }
19
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
 
21
- async def random_url(_):
22
- pet = random.choice(["cat", "dog"])
23
- api_url = f"https://api.the{pet}api.com/v1/images/search"
24
- async with aiohttp.ClientSession() as session:
25
- async with session.get(api_url) as resp:
26
- return (await resp.json())[0]["url"]
27
-
28
 
 
29
  @pn.cache
30
  def load_processor_model(
31
  processor_name: str, model_name: str
@@ -34,13 +85,13 @@ def load_processor_model(
34
  model = CLIPModel.from_pretrained(model_name)
35
  return processor, model
36
 
37
-
38
  async def open_image_url(image_url: str) -> Image:
39
  async with aiohttp.ClientSession() as session:
40
  async with session.get(image_url) as resp:
 
 
41
  return Image.open(io.BytesIO(await resp.read()))
42
 
43
-
44
  def get_similarity_scores(class_items: List[str], image: Image) -> List[float]:
45
  processor, model = load_processor_model(
46
  "openai/clip-vit-base-patch32", "openai/clip-vit-base-patch32"
@@ -48,100 +99,471 @@ def get_similarity_scores(class_items: List[str], image: Image) -> List[float]:
48
  inputs = processor(
49
  text=class_items,
50
  images=[image],
51
- return_tensors="pt", # pytorch tensors
52
  )
53
  outputs = model(**inputs)
54
  logits_per_image = outputs.logits_per_image
55
  class_likelihoods = logits_per_image.softmax(dim=1).detach().numpy()
56
  return class_likelihoods[0]
57
 
 
58
 
59
- async def process_inputs(class_names: List[str], image_url: str):
60
- """
61
- High level function that takes in the user inputs and returns the
62
- classification results as panel objects.
63
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  try:
65
- main.disabled = True
66
- if not image_url:
67
- yield "##### ⚠️ Provide an image URL"
68
- return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
 
70
- yield "##### βš™ Fetching image and running model..."
71
- try:
72
- pil_img = await open_image_url(image_url)
73
- img = pn.pane.Image(pil_img, height=400, align="center")
74
- except Exception as e:
75
- yield f"##### πŸ˜” Something went wrong, please try a different URL!"
76
- return
77
 
78
- class_items = class_names.split(",")
79
- class_likelihoods = get_similarity_scores(class_items, pil_img)
80
 
81
- # build the results column
82
- results = pn.Column("##### πŸŽ‰ Here are the results!", img)
 
83
 
84
- for class_item, class_likelihood in zip(class_items, class_likelihoods):
85
- row_label = pn.widgets.StaticText(
86
- name=class_item.strip(), value=f"{class_likelihood:.2%}", align="center"
87
- )
88
- row_bar = pn.indicators.Progress(
89
- value=int(class_likelihood * 100),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  sizing_mode="stretch_width",
91
- bar_color="secondary",
92
- margin=(0, 10),
93
- design=pn.theme.Material,
94
  )
95
- results.append(pn.Column(row_label, row_bar))
96
- yield results
97
- finally:
98
- main.disabled = False
99
-
 
100
 
101
- # create widgets
102
- randomize_url = pn.widgets.Button(name="Randomize URL", align="end")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
 
104
- image_url = pn.widgets.TextInput(
105
- name="Image URL to classify",
106
- value=pn.bind(random_url, randomize_url),
107
- )
108
- class_names = pn.widgets.TextInput(
109
- name="Comma separated class names",
110
- placeholder="Enter possible class names, e.g. cat, dog",
111
- value="cat, dog, parrot",
112
  )
113
 
114
- input_widgets = pn.Column(
115
- "##### 😊 Click randomize or paste a URL to start classifying!",
116
- pn.Row(image_url, randomize_url),
117
- class_names,
118
- )
119
 
120
- # add interactivity
121
- interactive_result = pn.panel(
122
- pn.bind(process_inputs, image_url=image_url, class_names=class_names),
123
- height=600,
124
- )
125
 
126
- # add footer
127
  footer_row = pn.Row(pn.Spacer(), align="center")
128
  for icon, url in ICON_URLS.items():
129
- href_button = pn.widgets.Button(icon=icon, width=35, height=35)
130
  href_button.js_on_click(code=f"window.open('{url}')")
131
  footer_row.append(href_button)
132
  footer_row.append(pn.Spacer())
133
 
134
- # create dashboard
135
- main = pn.WidgetBox(
136
- input_widgets,
137
- interactive_result,
138
- footer_row,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  )
140
 
141
- title = "Panel Demo - Image Classification"
142
- pn.template.BootstrapTemplate(
143
- title=title,
144
- main=main,
145
- main_max_width="min(50%, 698px)",
146
- header_background="#F08080",
147
- ).servable(title=title)
 
1
  import io
2
  import random
3
  from typing import List, Tuple
 
4
  import aiohttp
5
  import panel as pn
6
+ import pandas as pd
7
+ import plotly.express as px
8
+ import numpy as np
9
  from PIL import Image
10
  from transformers import CLIPModel, CLIPProcessor
11
+ from datetime import datetime, timedelta
12
 
13
+ # Enable panel extensions
14
+ pn.extension(design="fast", sizing_mode="stretch_width")
15
 
16
+ # Icons list
17
  ICON_URLS = {
18
  "brand-github": "https://github.com/holoviz/panel",
19
  "brand-twitter": "https://twitter.com/Panel_Org",
 
22
  "brand-discord": "https://discord.gg/AXRHnJU6sP",
23
  }
24
 
25
+ # --- 1. SAMPLE DATA GENERATION ---
26
+ def generate_sample_data():
27
+ np.random.seed(42)
28
+ start_date = datetime(2024, 1, 1)
29
+ dates = [start_date + timedelta(days=i) for i in range(540)] # 1.5 years of daily data
30
+
31
+ regions = ['North', 'East', 'South', 'West']
32
+ categories = ['Electronics', 'Furniture', 'Office Supplies']
33
+ subcategories = {
34
+ 'Electronics': ['Phones', 'Laptops', 'Accessories'],
35
+ 'Furniture': ['Chairs', 'Tables', 'Bookcases'],
36
+ 'Office Supplies': ['Paper', 'Art', 'Binders']
37
+ }
38
+
39
+ data = []
40
+ for date in dates:
41
+ num_orders = np.random.randint(1, 5)
42
+ for _ in range(num_orders):
43
+ region = np.random.choice(regions)
44
+ cat = np.random.choice(categories)
45
+ subcat = np.random.choice(subcategories[cat])
46
+
47
+ if cat == 'Electronics':
48
+ base_sales = np.random.uniform(200, 1500)
49
+ profit_factor = np.random.uniform(0.1, 0.25)
50
+ elif cat == 'Furniture':
51
+ base_sales = np.random.uniform(100, 800)
52
+ profit_factor = np.random.uniform(0.02, 0.15)
53
+ else:
54
+ base_sales = np.random.uniform(10, 150)
55
+ profit_factor = np.random.uniform(0.2, 0.45)
56
+
57
+ if date.month in [11, 12]:
58
+ base_sales *= np.random.uniform(1.2, 1.5)
59
+
60
+ sales = round(base_sales, 2)
61
+ profit = round(sales * profit_factor, 2)
62
+ quantity = np.random.randint(1, 8)
63
+
64
+ data.append({
65
+ 'Date': date,
66
+ 'Region': region,
67
+ 'Category': cat,
68
+ 'Sub-Category': subcat,
69
+ 'Sales': sales,
70
+ 'Profit': profit,
71
+ 'Quantity': quantity,
72
+ 'Year': date.year
73
+ })
74
+
75
+ return pd.DataFrame(data)
76
 
77
+ df_data = generate_sample_data()
 
 
 
 
 
 
78
 
79
+ # --- 2. CLIP ML CLASSIFIER MODEL CACHING ---
80
  @pn.cache
81
  def load_processor_model(
82
  processor_name: str, model_name: str
 
85
  model = CLIPModel.from_pretrained(model_name)
86
  return processor, model
87
 
 
88
  async def open_image_url(image_url: str) -> Image:
89
  async with aiohttp.ClientSession() as session:
90
  async with session.get(image_url) as resp:
91
+ if resp.status != 200:
92
+ raise Exception(f"HTTP status {resp.status}")
93
  return Image.open(io.BytesIO(await resp.read()))
94
 
 
95
  def get_similarity_scores(class_items: List[str], image: Image) -> List[float]:
96
  processor, model = load_processor_model(
97
  "openai/clip-vit-base-patch32", "openai/clip-vit-base-patch32"
 
99
  inputs = processor(
100
  text=class_items,
101
  images=[image],
102
+ return_tensors="pt",
103
  )
104
  outputs = model(**inputs)
105
  logits_per_image = outputs.logits_per_image
106
  class_likelihoods = logits_per_image.softmax(dim=1).detach().numpy()
107
  return class_likelihoods[0]
108
 
109
+ # --- 3. WIDGET DEFINITIONS ---
110
 
111
+ # Global Sidebar Filters
112
+ date_min = df_data['Date'].min().to_pydatetime()
113
+ date_max = df_data['Date'].max().to_pydatetime()
114
+
115
+ date_range_slider = pn.widgets.DateRangeSlider(
116
+ name='Filter Date Range',
117
+ start=date_min,
118
+ end=date_max,
119
+ value=(date_min, date_max),
120
+ sizing_mode="stretch_width"
121
+ )
122
+
123
+ regions_list = sorted(list(df_data['Region'].unique()))
124
+ region_select = pn.widgets.MultiChoice(
125
+ name='Filter Regions',
126
+ options=regions_list,
127
+ value=regions_list,
128
+ sizing_mode="stretch_width"
129
+ )
130
+
131
+ categories_list = sorted(list(df_data['Category'].unique()))
132
+ category_checkboxes = pn.widgets.CheckBoxGroup(
133
+ name='Filter Categories',
134
+ options=categories_list,
135
+ value=categories_list,
136
+ inline=False
137
+ )
138
+
139
+ # Overview Tab Widgets
140
+ name_input = pn.widgets.TextInput(name="Enter your name", value="Developer", placeholder="Type name here...", sizing_mode="stretch_width")
141
+ color_picker = pn.widgets.ColorPicker(name="Choose card theme color", value="#20B2AA", sizing_mode="stretch_width")
142
+ size_slider = pn.widgets.IntSlider(name="Font size adjustment", start=12, end=28, value=16, sizing_mode="stretch_width")
143
+
144
+ # ML Tab Widgets
145
+ image_selector = pn.widgets.Select(
146
+ name="Select a sample image",
147
+ options={
148
+ "Cat": "https://images.unsplash.com/photo-1514888286974-6c03e2ca1dba?q=80&w=600&auto=format&fit=crop",
149
+ "Dog": "https://images.unsplash.com/photo-1543466835-00a7907e9de1?q=80&w=600&auto=format&fit=crop",
150
+ "Parrot": "https://images.unsplash.com/photo-1552728089-57bdde30ebd3?q=80&w=600&auto=format&fit=crop",
151
+ "Sports Car": "https://images.unsplash.com/photo-1503376780353-7e6692767b70?q=80&w=600&auto=format&fit=crop",
152
+ "Mountain Landscape": "https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?q=80&w=600&auto=format&fit=crop",
153
+ "Custom URL (Enter below)": "custom"
154
+ },
155
+ value="https://images.unsplash.com/photo-1514888286974-6c03e2ca1dba?q=80&w=600&auto=format&fit=crop",
156
+ sizing_mode="stretch_width"
157
+ )
158
+
159
+ custom_url_input = pn.widgets.TextInput(
160
+ name="Custom Image URL",
161
+ placeholder="Paste any public image URL here...",
162
+ visible=False,
163
+ sizing_mode="stretch_width"
164
+ )
165
+
166
+ def update_custom_url_visibility(val):
167
+ custom_url_input.visible = (val == "custom")
168
+
169
+ image_selector.param.watch(lambda event: update_custom_url_visibility(event.new), 'value')
170
+
171
+ class_names_input = pn.widgets.TextInput(
172
+ name="Candidate Classes (comma-separated)",
173
+ value="cat, dog, parrot, car, mountain",
174
+ placeholder="e.g. cat, dog, parrot",
175
+ sizing_mode="stretch_width"
176
+ )
177
+
178
+ classify_btn = pn.widgets.Button(name="Run CLIP Inference", button_type="primary", sizing_mode="stretch_width")
179
+
180
+ # Playground Tab Widgets
181
+ latex_input = pn.widgets.TextInput(
182
+ name="LaTeX Equation Editor",
183
+ value=r"f(x) = \int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}"
184
+ )
185
+ latex_pane = pn.pane.LaTeX(
186
+ pn.bind(lambda eq: f"$$\\text{{Output: }} {eq}$$", latex_input),
187
+ align="center"
188
+ )
189
+
190
+ markdown_editor = pn.widgets.TextAreaInput(
191
+ name="Markdown Editor",
192
+ value="### Markdown Live Preview!\n- **Bold text**\n- *Italics*\n- [Link to Panel](https://panel.holoviz.org)",
193
+ height=120
194
+ )
195
+ markdown_pane = pn.pane.Markdown(pn.bind(lambda val: val, markdown_editor))
196
+
197
+ file_input = pn.widgets.FileInput(name="Upload File (CSV/Text)", accept=".csv,.txt")
198
+
199
+ def file_details(data):
200
+ if data is None:
201
+ return "*No file uploaded yet. Upload a .csv or .txt file to view details.*"
202
  try:
203
+ file_len = len(data)
204
+ text_preview = data[:150].decode('utf-8', errors='ignore')
205
+ return f"**File Size**: {file_len} bytes\n\n**First 150 characters**:\n```\n{text_preview}\n```"
206
+ except Exception as e:
207
+ return f"Failed to parse file: {str(e)}"
208
+
209
+ file_details_pane = pn.pane.Markdown(pn.bind(file_details, file_input))
210
+
211
+ video_widget = pn.widgets.Video(
212
+ value="https://assets.mixkit.co/videos/preview/mixkit-forest-stream-in-the-sunlight-529-large.mp4",
213
+ loop=True, autoplay=False, sizing_mode="stretch_width", height=200
214
+ )
215
+
216
+ # --- 4. REACTIVE FUNCTIONS & CARD GENERATORS ---
217
+
218
+ # KPI Cards generator
219
+ def make_kpi_card(title, value, color="#20B2AA", icon="πŸ’΅"):
220
+ return pn.pane.HTML(f"""
221
+ <div style="
222
+ background: rgba(128, 128, 128, 0.08);
223
+ border-left: 5px solid {color};
224
+ border-radius: 8px;
225
+ padding: 15px 20px;
226
+ box-shadow: 0 4px 10px rgba(0,0,0,0.05);
227
+ display: flex;
228
+ align-items: center;
229
+ justify-content: space-between;
230
+ min-width: 180px;
231
+ flex: 1;
232
+ ">
233
+ <div>
234
+ <span style="font-size: 13px; opacity: 0.7; text-transform: uppercase; font-weight: 600; display: block; margin-bottom: 5px;">{title}</span>
235
+ <span style="font-size: 22px; font-weight: bold; color: var(--neutral-foreground-rest);">{value}</span>
236
+ </div>
237
+ <span style="font-size: 28px; line-height: 1;">{icon}</span>
238
+ </div>
239
+ """, sizing_mode="stretch_width")
240
+
241
+ # Overview Greeting Card
242
+ def greeting_card(name, color, size):
243
+ style_content = f"""
244
+ <div style="
245
+ background: linear-gradient(135deg, {color}, #2c3e50);
246
+ padding: 30px;
247
+ border-radius: 12px;
248
+ text-align: center;
249
+ color: white;
250
+ box-shadow: 0 10px 25px rgba(0,0,0,0.15);
251
+ font-size: {size}px;
252
+ transition: all 0.3s ease;
253
+ margin-top: 10px;
254
+ ">
255
+ <h3 style="margin: 0; color: white;">Welcome to Panel, {name if name else "Developer"}! πŸš€</h3>
256
+ <p style="font-size: 14px; opacity: 0.85; margin: 12px 0 0 0;">
257
+ This card is updating in real time using Panel reactive bindings.
258
+ </p>
259
+ </div>
260
+ """
261
+ return pn.pane.HTML(style_content, sizing_mode="stretch_width")
262
+
263
+ overview_interactive_card = pn.bind(greeting_card, name=name_input, color=color_picker, size=size_slider)
264
+
265
+ # Data Dashboard generator
266
+ def get_dashboard_layout(df_filtered):
267
+ if df_filtered.empty:
268
+ return pn.pane.Markdown("### ⚠️ No data matches the selected filters. Please adjust them in the sidebar.")
269
+
270
+ total_sales = df_filtered['Sales'].sum()
271
+ total_profit = df_filtered['Profit'].sum()
272
+ margin = (total_profit / total_sales) if total_sales > 0 else 0
273
+ total_qty = df_filtered['Quantity'].sum()
274
 
275
+ kpi1 = make_kpi_card("Total Sales", f"${total_sales:,.2f}", "#20B2AA", "πŸ’°")
276
+ kpi2 = make_kpi_card("Total Profit", f"${total_profit:,.2f}", "#4CAF50" if total_profit >= 0 else "#F44336", "πŸ“ˆ")
277
+ kpi3 = make_kpi_card("Profit Margin", f"{margin:.1%}", "#FF9800", "πŸ“Š")
278
+ kpi4 = make_kpi_card("Products Sold", f"{total_qty:,}", "#9C27B0", "πŸ“¦")
 
 
 
279
 
280
+ kpis = pn.Row(kpi1, kpi2, kpi3, kpi4, sizing_mode="stretch_width", margin=(0, 0, 20, 0))
 
281
 
282
+ # 1. Line chart: Monthly trend
283
+ df_monthly = df_filtered.groupby(df_filtered['Date'].dt.to_period('M')).agg({'Sales': 'sum', 'Profit': 'sum'}).reset_index()
284
+ df_monthly['Date'] = df_monthly['Date'].dt.to_timestamp()
285
 
286
+ fig_line = px.line(
287
+ df_monthly, x='Date', y='Sales', title="Monthly Sales Trend",
288
+ labels={'Sales': 'Sales ($)', 'Date': 'Month'},
289
+ template="plotly_white"
290
+ )
291
+ fig_line.update_traces(line_color="#20B2AA", line_width=3)
292
+ fig_line.update_layout(
293
+ margin=dict(l=40, r=40, t=40, b=40),
294
+ paper_bgcolor="rgba(0,0,0,0)",
295
+ plot_bgcolor="rgba(0,0,0,0)",
296
+ font=dict(color="gray")
297
+ )
298
+ chart_line = pn.pane.Plotly(fig_line, sizing_mode="stretch_width", height=350)
299
+
300
+ # 2. Bar chart: Category
301
+ df_cat = df_filtered.groupby(['Category', 'Sub-Category']).agg({'Sales': 'sum'}).reset_index()
302
+ fig_bar = px.bar(
303
+ df_cat, x='Sub-Category', y='Sales', color='Category',
304
+ title="Sales by Category & Sub-Category",
305
+ labels={'Sales': 'Sales ($)', 'Sub-Category': 'Sub-Category'},
306
+ color_discrete_sequence=["#20B2AA", "#FF9800", "#9C27B0"],
307
+ template="plotly_white"
308
+ )
309
+ fig_bar.update_layout(
310
+ margin=dict(l=40, r=40, t=40, b=40),
311
+ paper_bgcolor="rgba(0,0,0,0)",
312
+ plot_bgcolor="rgba(0,0,0,0)",
313
+ font=dict(color="gray")
314
+ )
315
+ chart_bar = pn.pane.Plotly(fig_bar, sizing_mode="stretch_width", height=350)
316
+
317
+ # 3. Scatter plot
318
+ fig_scatter = px.scatter(
319
+ df_filtered, x='Sales', y='Profit', color='Category', size='Quantity',
320
+ hover_data=['Sub-Category', 'Date'], title="Transaction Profitability (Sales vs Profit)",
321
+ color_discrete_sequence=["#20B2AA", "#FF9800", "#9C27B0"],
322
+ opacity=0.7, template="plotly_white"
323
+ )
324
+ fig_scatter.update_layout(
325
+ margin=dict(l=40, r=40, t=40, b=40),
326
+ paper_bgcolor="rgba(0,0,0,0)",
327
+ plot_bgcolor="rgba(0,0,0,0)",
328
+ font=dict(color="gray")
329
+ )
330
+ chart_scatter = pn.pane.Plotly(fig_scatter, sizing_mode="stretch_width", height=350)
331
+
332
+ layout = pn.Column(
333
+ kpis,
334
+ pn.Row(chart_line, chart_bar, sizing_mode="stretch_width", margin=(0, 0, 20, 0)),
335
+ pn.Row(chart_scatter, sizing_mode="stretch_width"),
336
+ sizing_mode="stretch_width"
337
+ )
338
+ return layout
339
+
340
+ def filter_and_render_dashboard(date_range, regions, categories):
341
+ df_filtered = df_data.copy()
342
+ start_dt, end_dt = date_range
343
+ df_filtered = df_filtered[(df_filtered['Date'] >= start_dt) & (df_filtered['Date'] <= end_dt)]
344
+ if regions:
345
+ df_filtered = df_filtered[df_filtered['Region'].isin(regions)]
346
+ else:
347
+ df_filtered = df_filtered[df_filtered['Region'].isin([])]
348
+ if categories:
349
+ df_filtered = df_filtered[df_filtered['Category'].isin(categories)]
350
+ else:
351
+ df_filtered = df_filtered[df_filtered['Category'].isin([])]
352
+
353
+ return get_dashboard_layout(df_filtered)
354
+
355
+ interactive_dashboard = pn.panel(
356
+ pn.bind(filter_and_render_dashboard, date_range=date_range_slider, regions=region_select, categories=category_checkboxes),
357
+ sizing_mode="stretch_width"
358
+ )
359
+
360
+ # ML Classification generator
361
+ async def classify_image(url, classes_str):
362
+ if not url or url == "custom":
363
+ yield "##### ⚠️ Please provide a valid image URL."
364
+ return
365
+
366
+ try:
367
+ yield "##### βš™ Fetching image..."
368
+ pil_img = await open_image_url(url)
369
+ img_pane = pn.pane.Image(pil_img, height=280, align="center")
370
+ except Exception as e:
371
+ yield f"##### πŸ˜” Failed to load image from URL: `{url}`. Error: {str(e)}"
372
+ return
373
+
374
+ yield "##### βš™ Running CLIP Model (openai/clip-vit-base-patch32)..."
375
+ try:
376
+ class_items = [c.strip() for c in classes_str.split(",") if c.strip()]
377
+ if not class_items:
378
+ yield "##### ⚠️ Please specify at least one class name."
379
+ return
380
+
381
+ scores = get_similarity_scores(class_items, pil_img)
382
+
383
+ results_col = pn.Column(
384
+ "##### πŸŽ‰ Classification Results",
385
+ img_pane,
386
+ sizing_mode="stretch_width"
387
+ )
388
+
389
+ for name, score in zip(class_items, scores):
390
+ bar = pn.indicators.Progress(
391
+ value=int(score * 100),
392
  sizing_mode="stretch_width",
393
+ bar_color="success" if score > 0.5 else "info",
394
+ height=15
 
395
  )
396
+ label = pn.pane.Markdown(f"**{name}**: {score:.2%}", margin=(5, 0, 0, 0))
397
+ results_col.append(pn.Column(label, bar, margin=(5, 0)))
398
+
399
+ yield results_col
400
+ except Exception as e:
401
+ yield f"##### πŸ˜” Classification failed. Error: {str(e)}"
402
 
403
+ def run_classification_on_click(clicks):
404
+ url = image_selector.value
405
+ if url == "custom":
406
+ url = custom_url_input.value
407
+
408
+ classes = class_names_input.value
409
+
410
+ if clicks == 0:
411
+ if url and url != "custom":
412
+ try:
413
+ img_pane = pn.pane.Image(url, height=280, align="center")
414
+ return pn.Column("##### Image Preview", img_pane)
415
+ except:
416
+ pass
417
+ return "##### πŸ’‘ Click 'Run CLIP Inference' to start classification."
418
+
419
+ return pn.panel(classify_image(url, classes))
420
 
421
+ classification_output_area = pn.panel(
422
+ pn.bind(run_classification_on_click, clicks=classify_btn),
423
+ sizing_mode="stretch_width"
 
 
 
 
 
424
  )
425
 
426
+ # Reset output when inputs change
427
+ def reset_clicks(event):
428
+ classify_btn.clicks = 0
 
 
429
 
430
+ image_selector.param.watch(reset_clicks, 'value')
431
+ custom_url_input.param.watch(reset_clicks, 'value')
432
+ class_names_input.param.watch(reset_clicks, 'value')
 
 
433
 
434
+ # --- 5. FOOTER SOCIAL LINKS ---
435
  footer_row = pn.Row(pn.Spacer(), align="center")
436
  for icon, url in ICON_URLS.items():
437
+ href_button = pn.widgets.Button(icon=icon, width=38, height=38, button_type="light")
438
  href_button.js_on_click(code=f"window.open('{url}')")
439
  footer_row.append(href_button)
440
  footer_row.append(pn.Spacer())
441
 
442
+ # --- 6. TEMPLATE ASSEMBLING ---
443
+ template = pn.template.FastListTemplate(
444
+ title="HoloViz Panel Interactive Showcase",
445
+ sidebar=[
446
+ "## Dashboard Filters",
447
+ "*(These filters apply to the **Data Analytics Dashboard** tab)*",
448
+ date_range_slider,
449
+ pn.Spacer(height=10),
450
+ region_select,
451
+ pn.Spacer(height=10),
452
+ category_checkboxes,
453
+ pn.Spacer(height=25),
454
+ "### About HoloViz Panel",
455
+ "Panel is a powerful Python library that lets you build high-performance interactive web applications, dashboards, and data portals entirely in Python.",
456
+ "[Documentation](https://panel.holoviz.org)",
457
+ "[GitHub Repository](https://github.com/holoviz/panel)"
458
+ ],
459
+ main=[
460
+ pn.Tabs(
461
+ ("πŸš€ Overview & Basics", pn.Column(
462
+ pn.pane.Markdown("""
463
+ # Welcome to the HoloViz Panel Showcase! πŸ“ˆ
464
+
465
+ This Space demonstrates how to build premium, fully interactive dashboards and web applications directly in Python using **Panel**.
466
+
467
+ ### Why choose Panel?
468
+ - **No HTML/CSS/JS required**: Build complex frontends completely in Python.
469
+ - **Rich Ecosystem Integration**: Seamlessly connect Bokeh, Plotly, Altair, Matplotlib, PyTorch, and Hugging Face models.
470
+ - **Reactive and Callback APIs**: Simple decorators or bindings to link widgets directly to code.
471
+ - **Out-of-the-box templates**: Stunning themes like Fast, Material, and Bootstrap that support Dark/Light mode switching.
472
+ """),
473
+ pn.Spacer(height=15),
474
+ pn.Row(
475
+ pn.Column(
476
+ "### 1. Interactive Greetings Widget",
477
+ "Change the inputs below and watch the card update instantly.",
478
+ name_input,
479
+ color_picker,
480
+ size_slider,
481
+ margin=(0, 15)
482
+ ),
483
+ pn.Column(
484
+ "### Live Preview",
485
+ overview_interactive_card,
486
+ margin=(0, 15)
487
+ ),
488
+ sizing_mode="stretch_width"
489
+ ),
490
+ pn.Spacer(height=20),
491
+ pn.pane.Markdown("""
492
+ ### Check out other tabs:
493
+ - **πŸ“Š Data Analytics Dashboard**: A full sales dashboard using Plotly Express linked dynamically to the sidebar filters.
494
+ - **πŸ€– CLIP Image Classifier**: Real-time AI classification using an OpenAI CLIP model cached in memory.
495
+ - **πŸ›  Widget Playground**: Live LaTeX editing, Markdown previewing, and file uploads.
496
+ """)
497
+ )),
498
+ ("πŸ“Š Data Analytics Dashboard", pn.Column(
499
+ "## Real-time Superstore Analytics",
500
+ "Use the filters in the **left sidebar** to refine this dashboard in real-time.",
501
+ pn.Spacer(height=10),
502
+ interactive_dashboard
503
+ )),
504
+ ("πŸ€– CLIP Image Classifier", pn.Column(
505
+ "## AI Image Classification with CLIP",
506
+ "This tab runs **OpenAI CLIP (clip-vit-base-patch32)** to classify images based on natural language descriptors.",
507
+ pn.Spacer(height=10),
508
+ pn.Row(
509
+ pn.Column(
510
+ image_selector,
511
+ custom_url_input,
512
+ class_names_input,
513
+ pn.Spacer(height=10),
514
+ classify_btn,
515
+ width=320,
516
+ margin=(0, 15)
517
+ ),
518
+ pn.Column(
519
+ classification_output_area,
520
+ margin=(0, 15)
521
+ ),
522
+ sizing_mode="stretch_width"
523
+ )
524
+ )),
525
+ ("πŸ›  Widget Playground", pn.Column(
526
+ "## Panel Interactive Playground",
527
+ "Explore some of Panel's diverse widgets and dynamic rendering capabilities.",
528
+ pn.Spacer(height=15),
529
+ pn.Row(
530
+ pn.Column(
531
+ "### Live LaTeX Renderer",
532
+ latex_input,
533
+ latex_pane,
534
+ margin=(0, 15)
535
+ ),
536
+ pn.Column(
537
+ "### Live Markdown Editor",
538
+ markdown_editor,
539
+ markdown_pane,
540
+ margin=(0, 15)
541
+ ),
542
+ sizing_mode="stretch_width"
543
+ ),
544
+ pn.Spacer(height=20),
545
+ pn.Row(
546
+ pn.Column(
547
+ "### File Upload Inspector",
548
+ file_input,
549
+ file_details_pane,
550
+ margin=(0, 15)
551
+ ),
552
+ pn.Column(
553
+ "### Embedded Video Player",
554
+ video_widget,
555
+ margin=(0, 15)
556
+ ),
557
+ sizing_mode="stretch_width"
558
+ )
559
+ ))
560
+ ),
561
+ pn.Spacer(height=40),
562
+ footer_row
563
+ ],
564
+ accent_base_color="#20B2AA",
565
+ header_background="#20B2AA",
566
+ theme_toggle=True
567
  )
568
 
569
+ template.servable()
 
 
 
 
 
 
requirements.txt CHANGED
@@ -1,6 +1,8 @@
1
  panel
2
- jupyter
3
- transformers
4
  numpy
 
5
  torch
6
- aiohttp
 
 
1
  panel
2
+ pandas
3
+ plotly
4
  numpy
5
+ transformers
6
  torch
7
+ aiohttp
8
+ pillow