Brian045 commited on
Commit
9945bd1
Β·
verified Β·
1 Parent(s): 82c2526

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +61 -49
app.py CHANGED
@@ -5,6 +5,7 @@ import matplotlib.pyplot as plt
5
  from wordcloud import WordCloud
6
  from src.feature_extraction import FeatureExtractor
7
  import os
 
8
 
9
  # Load Model
10
  MODEL_PATH = 'best_svm_model.joblib'
@@ -21,42 +22,54 @@ feature_extractor = FeatureExtractor()
21
  def predict_summary(title, text):
22
  if not title or not text:
23
  return "Please provide both Title and Content.", pd.DataFrame()
24
-
25
  # 1. Extract Features
26
  features_list = feature_extractor.calculate_features(title, text)
27
  if not features_list:
28
  return "Could not extract sentences.", pd.DataFrame()
29
-
30
  df_features = pd.DataFrame(features_list)
31
-
32
  # 2. Prepare X for prediction (ensure correct column order matching training)
33
- # The columns expected by the model are likely:
34
  feature_cols = ['f1_lead', 'f2_judul_sim', 'f3_freq_word', 'f4_sim_sent', 'f5_len_norm', 'f6_overlap']
35
  X_pred = df_features[feature_cols]
36
-
37
  # 3. Predict
38
  if model:
39
  predictions = model.predict(X_pred)
 
 
 
 
 
 
40
  else:
41
  return "Model not loaded.", pd.DataFrame()
42
-
43
  df_features['prediction'] = predictions
44
-
 
45
  # 4. Generate Summary Text
46
  summary_sentences = df_features[df_features['prediction'] == 1]['teks_kalimat'].tolist()
 
 
47
  if not summary_sentences:
48
- summary_text = "No sentences were selected as summary."
49
- else:
50
- summary_text = " ".join(summary_sentences)
51
-
 
 
 
 
52
  # Return Summary and DataFrame
53
- return summary_text, df_features[['teks_kalimat', 'prediction'] + feature_cols]
54
 
55
 
56
  def process_batch_file(file_obj):
57
  if file_obj is None:
58
  return None, None, None, None
59
-
60
  # Read File
61
  try:
62
  if file_obj.name.endswith('.csv'):
@@ -68,39 +81,42 @@ def process_batch_file(file_obj):
68
  except Exception as e:
69
  return None, None, None, None
70
 
71
- # Check columns
72
- # We expect 'title' and 'teks_kalimat' columns.
73
- # WAIT: The training data `korpus_mentah_new.csv` has 'teks_kalimat' as sentences.
74
- # But batch input usually implies articles.
75
- # Let's assume input has 'title' and 'content' (full text).
76
-
77
  required_cols = ['title', 'content']
78
  if not all(col in df.columns for col in required_cols):
79
- # Fallback for user friendliness if they upload something else
80
  return None, None, None, None
81
 
82
  all_results = []
83
-
84
  for idx, row in df.iterrows():
85
  title = str(row['title'])
86
  content = str(row['content'])
87
-
88
  features_list = feature_extractor.calculate_features(title, content)
89
  if not features_list:
90
  continue
91
-
92
  df_feat = pd.DataFrame(features_list)
93
  X_pred = df_feat[['f1_lead', 'f2_judul_sim', 'f3_freq_word', 'f4_sim_sent', 'f5_len_norm', 'f6_overlap']]
94
-
95
  if model:
96
  preds = model.predict(X_pred)
 
 
 
 
 
97
  df_feat['prediction'] = preds
98
- df_feat['article_id'] = idx
99
-
100
- # Reconstruct Summary
101
  summary_sents = df_feat[df_feat['prediction'] == 1]['teks_kalimat'].tolist()
 
 
 
 
 
102
  summary_text = " ".join(summary_sents)
103
-
104
  # Store result for download (Article level)
105
  all_results.append({
106
  'article_id': idx,
@@ -111,28 +127,24 @@ def process_batch_file(file_obj):
111
  'summary_length': len(summary_text.split()),
112
  'compression_ratio': len(summary_text.split()) / len(content.split()) if len(content.split()) > 0 else 0
113
  })
114
-
115
  df_results = pd.DataFrame(all_results)
116
  output_csv = "batch_results.csv"
117
  df_results.to_csv(output_csv, index=False)
118
-
119
  # Analysis
120
- # 1. Summary vs Non-Summary Distribution (sentence level - conceptually, but here we have article level ratios)
121
- # Let's plot Average Compression Ratio
122
  fig1, ax1 = plt.subplots()
123
  ax1.hist(df_results['compression_ratio'], bins=10, color='skyblue', edgecolor='black')
124
  ax1.set_title('Distribution of Compression Ratios')
125
  ax1.set_xlabel('Ratio (Summary Words / Original Words)')
126
  ax1.set_ylabel('Frequency')
127
-
128
- # 2. Length Comparison
129
  fig2, ax2 = plt.subplots()
130
  ax2.scatter(df_results['original_length'], df_results['summary_length'], alpha=0.5)
131
  ax2.set_title('Original Length vs Summary Length')
132
  ax2.set_xlabel('Original Length (words)')
133
  ax2.set_ylabel('Summary Length (words)')
134
-
135
- # 3. Word Cloud of all summaries
136
  all_summary_text = " ".join(df_results['generated_summary'].tolist())
137
  if all_summary_text.strip():
138
  wordcloud = WordCloud(width=800, height=400, background_color='white').generate(all_summary_text)
@@ -153,18 +165,18 @@ def get_template():
153
  # Gradio Interface
154
  with gr.Blocks(title="Balinese News Summarizer") as demo:
155
  gr.Markdown("# πŸ“° Balinese News Summarizer (SVM)")
156
-
157
  with gr.Tab("πŸ“ Manual Input"):
158
  with gr.Row():
159
  with gr.Column():
160
  input_title = gr.Textbox(label="News Title", placeholder="Enter title here...")
161
  input_content = gr.Textbox(label="News Content", placeholder="Enter full news text here...", lines=10)
162
  btn_predict = gr.Button("Summarize", variant="primary")
163
-
164
  with gr.Column():
165
  output_summary = gr.Textbox(label="Generated Summary", lines=5, interactive=False)
166
- output_df = gr.Dataframe(label="Sentence Analysis", headers=['teks_kalimat', 'prediction', 'f1', 'f2', 'f3', 'f4', 'f5', 'f6'])
167
-
168
  btn_predict.click(fn=predict_summary, inputs=[input_title, input_content], outputs=[output_summary, output_df])
169
 
170
  with gr.Tab("πŸ“‚ Batch Analysis"):
@@ -172,21 +184,21 @@ with gr.Blocks(title="Balinese News Summarizer") as demo:
172
  with gr.Row():
173
  file_upload = gr.File(label="Upload File", file_types=['.csv', '.xlsx'])
174
  btn_template = gr.Button("Download Template")
175
- template_file = gr.File(label="Template", interactive=False, visible=False)
176
-
177
- btn_template.click(fn=get_template, inputs=None, outputs=file_upload) # Reuse file upload component to serve download or separate?
178
- # Better to use a separate DownloadButton if available in this version, or File output.
179
- # Using File output for template download:
180
-
181
  btn_process = gr.Button("Process Batch", variant="primary")
182
-
183
  with gr.Row():
184
  download_result = gr.File(label="Download Results")
185
-
186
  with gr.Row():
187
  plot1 = gr.Plot(label="Compression Ratio Distribution")
188
  plot2 = gr.Plot(label="Length Comparison")
189
-
190
  with gr.Row():
191
  plot3 = gr.Plot(label="Word Cloud")
192
 
 
5
  from wordcloud import WordCloud
6
  from src.feature_extraction import FeatureExtractor
7
  import os
8
+ import numpy as np
9
 
10
  # Load Model
11
  MODEL_PATH = 'best_svm_model.joblib'
 
22
  def predict_summary(title, text):
23
  if not title or not text:
24
  return "Please provide both Title and Content.", pd.DataFrame()
25
+
26
  # 1. Extract Features
27
  features_list = feature_extractor.calculate_features(title, text)
28
  if not features_list:
29
  return "Could not extract sentences.", pd.DataFrame()
30
+
31
  df_features = pd.DataFrame(features_list)
32
+
33
  # 2. Prepare X for prediction (ensure correct column order matching training)
 
34
  feature_cols = ['f1_lead', 'f2_judul_sim', 'f3_freq_word', 'f4_sim_sent', 'f5_len_norm', 'f6_overlap']
35
  X_pred = df_features[feature_cols]
36
+
37
  # 3. Predict
38
  if model:
39
  predictions = model.predict(X_pred)
40
+ # Get probabilities for fallback
41
+ if hasattr(model, "predict_proba"):
42
+ probs = model.predict_proba(X_pred)[:, 1] # Probability of class 1
43
+ else:
44
+ # If model doesn't support probability (e.g. LinearSVC), use decision_function
45
+ probs = model.decision_function(X_pred)
46
  else:
47
  return "Model not loaded.", pd.DataFrame()
48
+
49
  df_features['prediction'] = predictions
50
+ df_features['probability'] = probs
51
+
52
  # 4. Generate Summary Text
53
  summary_sentences = df_features[df_features['prediction'] == 1]['teks_kalimat'].tolist()
54
+
55
+ # Fallback Logic: If no sentences selected
56
  if not summary_sentences:
57
+ # Select the sentence with the highest probability
58
+ best_idx = np.argmax(probs)
59
+ summary_sentences = [df_features.iloc[best_idx]['teks_kalimat']]
60
+ # Update prediction for display
61
+ df_features.at[best_idx, 'prediction'] = 1
62
+
63
+ summary_text = " ".join(summary_sentences)
64
+
65
  # Return Summary and DataFrame
66
+ return summary_text, df_features[['teks_kalimat', 'prediction', 'probability'] + feature_cols]
67
 
68
 
69
  def process_batch_file(file_obj):
70
  if file_obj is None:
71
  return None, None, None, None
72
+
73
  # Read File
74
  try:
75
  if file_obj.name.endswith('.csv'):
 
81
  except Exception as e:
82
  return None, None, None, None
83
 
 
 
 
 
 
 
84
  required_cols = ['title', 'content']
85
  if not all(col in df.columns for col in required_cols):
 
86
  return None, None, None, None
87
 
88
  all_results = []
89
+
90
  for idx, row in df.iterrows():
91
  title = str(row['title'])
92
  content = str(row['content'])
93
+
94
  features_list = feature_extractor.calculate_features(title, content)
95
  if not features_list:
96
  continue
97
+
98
  df_feat = pd.DataFrame(features_list)
99
  X_pred = df_feat[['f1_lead', 'f2_judul_sim', 'f3_freq_word', 'f4_sim_sent', 'f5_len_norm', 'f6_overlap']]
100
+
101
  if model:
102
  preds = model.predict(X_pred)
103
+ if hasattr(model, "predict_proba"):
104
+ probs = model.predict_proba(X_pred)[:, 1]
105
+ else:
106
+ probs = model.decision_function(X_pred)
107
+
108
  df_feat['prediction'] = preds
109
+ df_feat['probability'] = probs
110
+
111
+ # Reconstruct Summary with Fallback
112
  summary_sents = df_feat[df_feat['prediction'] == 1]['teks_kalimat'].tolist()
113
+
114
+ if not summary_sents:
115
+ best_idx = np.argmax(probs)
116
+ summary_sents = [df_feat.iloc[best_idx]['teks_kalimat']]
117
+
118
  summary_text = " ".join(summary_sents)
119
+
120
  # Store result for download (Article level)
121
  all_results.append({
122
  'article_id': idx,
 
127
  'summary_length': len(summary_text.split()),
128
  'compression_ratio': len(summary_text.split()) / len(content.split()) if len(content.split()) > 0 else 0
129
  })
130
+
131
  df_results = pd.DataFrame(all_results)
132
  output_csv = "batch_results.csv"
133
  df_results.to_csv(output_csv, index=False)
134
+
135
  # Analysis
 
 
136
  fig1, ax1 = plt.subplots()
137
  ax1.hist(df_results['compression_ratio'], bins=10, color='skyblue', edgecolor='black')
138
  ax1.set_title('Distribution of Compression Ratios')
139
  ax1.set_xlabel('Ratio (Summary Words / Original Words)')
140
  ax1.set_ylabel('Frequency')
141
+
 
142
  fig2, ax2 = plt.subplots()
143
  ax2.scatter(df_results['original_length'], df_results['summary_length'], alpha=0.5)
144
  ax2.set_title('Original Length vs Summary Length')
145
  ax2.set_xlabel('Original Length (words)')
146
  ax2.set_ylabel('Summary Length (words)')
147
+
 
148
  all_summary_text = " ".join(df_results['generated_summary'].tolist())
149
  if all_summary_text.strip():
150
  wordcloud = WordCloud(width=800, height=400, background_color='white').generate(all_summary_text)
 
165
  # Gradio Interface
166
  with gr.Blocks(title="Balinese News Summarizer") as demo:
167
  gr.Markdown("# πŸ“° Balinese News Summarizer (SVM)")
168
+
169
  with gr.Tab("πŸ“ Manual Input"):
170
  with gr.Row():
171
  with gr.Column():
172
  input_title = gr.Textbox(label="News Title", placeholder="Enter title here...")
173
  input_content = gr.Textbox(label="News Content", placeholder="Enter full news text here...", lines=10)
174
  btn_predict = gr.Button("Summarize", variant="primary")
175
+
176
  with gr.Column():
177
  output_summary = gr.Textbox(label="Generated Summary", lines=5, interactive=False)
178
+ output_df = gr.Dataframe(label="Sentence Analysis", headers=['teks_kalimat', 'prediction', 'probability', 'f1', 'f2', 'f3', 'f4', 'f5', 'f6'])
179
+
180
  btn_predict.click(fn=predict_summary, inputs=[input_title, input_content], outputs=[output_summary, output_df])
181
 
182
  with gr.Tab("πŸ“‚ Batch Analysis"):
 
184
  with gr.Row():
185
  file_upload = gr.File(label="Upload File", file_types=['.csv', '.xlsx'])
186
  btn_template = gr.Button("Download Template")
187
+
188
+ # Using a workaround for template download if needed, or just file output
189
+ # Assuming file_upload can display the output file as well
190
+
191
+ btn_template.click(fn=get_template, inputs=None, outputs=file_upload)
192
+
193
  btn_process = gr.Button("Process Batch", variant="primary")
194
+
195
  with gr.Row():
196
  download_result = gr.File(label="Download Results")
197
+
198
  with gr.Row():
199
  plot1 = gr.Plot(label="Compression Ratio Distribution")
200
  plot2 = gr.Plot(label="Length Comparison")
201
+
202
  with gr.Row():
203
  plot3 = gr.Plot(label="Word Cloud")
204