GoshawkVortexAI commited on
Commit
64018a4
Β·
verified Β·
1 Parent(s): 4203760

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +276 -266
app.py CHANGED
@@ -7,412 +7,422 @@ from transformers import (
7
  AutoModelForSequenceClassification
8
  )
9
 
 
10
 
11
- # ============================================================
12
- # GOSHAWK INSURANCE AI
13
- # DistilBERT - Insurance Classification
14
- # CPU OPTIMIZED
15
- # ============================================================
16
 
17
- MODEL_PATH = "./"
18
- DEVICE = torch.device("cpu")
 
19
 
20
- MAX_LENGTH = 256
 
21
 
 
22
 
23
- # ============================================================
24
- # MODEL YÜKLEME
25
- # ============================================================
 
 
26
 
27
- print("=" * 60)
28
- print("GOSHAWK INSURANCE AI")
29
- print("Model yΓΌkleniyor...")
30
- print("=" * 60)
31
-
32
- try:
33
 
34
- tokenizer = AutoTokenizer.from_pretrained(
35
- MODEL_PATH,
36
- local_files_only=True
37
- )
38
-
39
- model = AutoModelForSequenceClassification.from_pretrained(
40
- MODEL_PATH,
41
- local_files_only=True
42
- )
43
 
44
- model.to(DEVICE)
45
- model.eval()
46
-
47
- except Exception as error:
48
-
49
- print("=" * 60)
50
- print("MODEL YÜKLEME HATASI")
51
- print(error)
52
- print("=" * 60)
53
-
54
- raise error
55
-
56
-
57
- # ============================================================
58
- # MODEL BΔ°LGΔ°LERΔ°
59
- # ============================================================
60
 
61
  print("=" * 60)
62
- print("MODEL BAŞARIYLA YÜKLENDİ")
63
  print("=" * 60)
64
 
65
  print("Device:", DEVICE)
66
- print("Model:", type(model).__name__)
67
- print("Num labels:", model.config.num_labels)
68
 
69
- print("ID2LABEL:")
70
- print(model.config.id2label)
71
 
72
- print("LABEL2ID:")
73
- print(model.config.label2id)
74
 
75
- print("=" * 60)
 
 
76
 
 
77
 
78
- # ============================================================
79
- # LABEL OKUMA
80
- # ============================================================
 
 
 
81
 
82
- def get_label(index):
83
 
84
- label = model.config.id2label.get(
85
- index,
86
- f"LABEL_{index}"
87
  )
88
 
89
- return str(label)
90
-
91
-
92
- # ============================================================
93
- # METΔ°N ANALΔ°ZΔ°
94
- # ============================================================
95
-
96
- def predict(text):
97
-
98
- # Boş metin kontrolü
99
- if text is None or not text.strip():
100
-
101
- return {
102
- "Durum": "HATA",
103
- "Mesaj": "LΓΌtfen bir sigorta metni girin."
104
- }
105
-
106
-
107
- text = text.strip()
108
-
109
-
110
- try:
111
 
112
- # ----------------------------------------------------
113
- # TOKENIZER
114
- # ----------------------------------------------------
115
 
116
- inputs = tokenizer(
117
- text,
118
- return_tensors="pt",
119
- truncation=True,
120
- padding=True,
121
- max_length=MAX_LENGTH
122
- )
123
 
 
124
 
125
- # ----------------------------------------------------
126
- # CPU
127
- # ----------------------------------------------------
 
128
 
129
- inputs = {
130
- key: value.to(DEVICE)
131
- for key, value in inputs.items()
132
- }
133
 
134
 
135
- # ----------------------------------------------------
136
- # MODEL
137
- # ----------------------------------------------------
138
 
139
- with torch.inference_mode():
140
 
141
- outputs = model(**inputs)
 
 
 
 
 
 
 
 
 
 
142
 
143
- logits = outputs.logits[0]
144
 
145
- probabilities = torch.softmax(
146
- logits,
147
- dim=-1
148
- )
149
 
 
 
 
150
 
151
- # ----------------------------------------------------
152
- # TÜM SINIFLAR
153
- # ----------------------------------------------------
154
 
155
- all_results = {}
 
 
 
156
 
157
- for index in range(model.config.num_labels):
158
 
159
- label = get_label(index)
160
 
161
- probability = float(
162
- probabilities[index]
163
- ) * 100
164
 
165
- all_results[label] = round(
166
- probability,
167
- 2
168
- )
169
 
 
170
 
171
- # ----------------------------------------------------
172
- # EN YÜKSEK SINIF
173
- # ----------------------------------------------------
174
 
175
- best_index = int(
176
- torch.argmax(probabilities)
177
- )
178
 
179
- best_label = get_label(best_index)
180
 
181
- best_probability = (
182
- float(probabilities[best_index]) * 100
183
- )
184
 
185
 
186
- # ----------------------------------------------------
187
- # SIRALA
188
- # ----------------------------------------------------
189
 
190
- sorted_results = dict(
191
- sorted(
192
- all_results.items(),
193
- key=lambda item: item[1],
194
- reverse=True
195
- )
196
- )
197
 
 
198
 
199
- # ----------------------------------------------------
200
- # GÜVEN DURUMU
201
- # ----------------------------------------------------
202
 
203
- if best_probability >= 90:
204
 
205
- confidence_status = "Γ‡ok yΓΌksek"
 
 
206
 
207
- elif best_probability >= 70:
208
 
209
- confidence_status = "YΓΌksek"
210
-
211
- elif best_probability >= 50:
212
-
213
- confidence_status = "Orta"
214
-
215
- else:
216
 
217
- confidence_status = "Düşük"
218
 
 
219
 
220
- # ----------------------------------------------------
221
- # NEUTRAL KONTROLÜ
222
- # ----------------------------------------------------
 
 
223
 
224
- neutral_warning = ""
 
 
225
 
226
- if (
227
- "neutral" in best_label.lower()
228
- and best_probability >= 90
229
- ):
 
 
 
230
 
231
- neutral_warning = (
232
- "Model Neutral sΔ±nΔ±fΔ±na Γ§ok yΓΌksek gΓΌven "
233
- "veriyor. FarklΔ± metinlerde de aynΔ± sonuΓ§ "
234
- "oluşuyorsa eğitim/label dağılımı kontrol "
235
- "edilmelidir."
236
- )
237
 
 
 
 
238
 
239
- # ----------------------------------------------------
240
- # SONUÇ
241
- # ----------------------------------------------------
242
 
243
- return {
 
 
244
 
245
- "Tahmin": best_label,
 
 
 
246
 
247
- "GΓΌven": (
248
- f"{best_probability:.2f}%"
249
- ),
250
 
251
- "GΓΌven Durumu": confidence_status,
 
 
 
252
 
253
- "TΓΌm SΔ±nΔ±flar": {
254
- label: f"{score:.2f}%"
255
- for label, score
256
- in sorted_results.items()
257
- },
258
 
259
- "Neutral KontrolΓΌ": neutral_warning,
 
 
 
260
 
261
- "Model Bilgisi": {
262
 
263
- "Model": type(model).__name__,
264
 
265
- "Num Labels": model.config.num_labels,
 
 
266
 
267
- "Device": str(DEVICE),
268
 
269
- "Max Length": MAX_LENGTH
270
 
271
- }
 
 
 
 
272
 
273
- }
274
 
 
275
 
276
- except Exception as error:
 
 
 
277
 
278
- return {
 
 
279
 
280
- "Durum": "MODEL HATASI",
 
 
 
281
 
282
- "Hata": str(error)
 
 
 
 
 
 
 
283
 
284
- }
 
 
 
 
285
 
286
 
287
- # ============================================================
288
- # TEST Γ–RNEKLERΔ°
289
- # ============================================================
290
 
291
  examples = [
292
 
293
  [
294
- "AraΓ§ kazasΔ± sonucunda ΓΆn tampon ve far hasar gΓΆrdΓΌ."
295
- ],
296
-
297
- [
298
- "Sigortalı kasko poliçesi kapsamında hasar başvurusunda bulundu."
299
  ],
300
 
301
  [
302
- "Trafik kazasΔ± nedeniyle araΓ§ta maddi hasar meydana geldi."
303
  ],
304
 
305
  [
306
- "Poliçe kapsamında sağlık giderlerinin karşılanması talep edildi."
307
  ],
308
 
309
  [
310
- "Sigorta şirketi hasar dosyasını inceleyerek âdeme yaptı."
311
  ],
312
 
313
  [
314
- "SigortalΔ±nΔ±n poliΓ§e teminatΔ± kapsamΔ±nda tazminat talebi bulunmaktadΔ±r."
315
  ]
316
-
317
  ]
318
 
319
 
320
- # ============================================================
321
- # GRADIO ARAYÜZÜ
322
- # ============================================================
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
323
 
324
  with gr.Blocks(
325
- title="Goshawk Insurance AI"
326
  ) as demo:
327
 
328
  gr.Markdown(
329
- """
330
- # πŸ›‘οΈ Goshawk Insurance AI
331
-
332
- **Sigorta sektΓΆrΓΌne ΓΆzel DistilBERT yapay zeka modeli**
333
-
334
- Sigorta metnini girin ve modelin hangi sΔ±nΔ±fa
335
- ait olduğunu tahmin etmesini sağlayın.
336
- """
337
  )
338
 
 
 
 
339
 
340
  with gr.Row():
341
 
342
  with gr.Column():
343
 
344
  text_input = gr.Textbox(
345
- label="Sigorta Metni",
346
  placeholder=(
347
- "Γ–rneğin: "
348
- "AraΓ§ kazasΔ± nedeniyle ΓΆn tampon hasar gΓΆrdΓΌ..."
 
349
  ),
350
- lines=8
351
  )
352
 
353
-
354
- with gr.Row():
355
-
356
- analyze_button = gr.Button(
357
- "πŸ” Analiz Et",
358
- variant="primary"
359
- )
360
-
361
- clear_button = gr.Button(
362
- "πŸ—‘οΈ Temizle"
363
- )
364
-
365
 
366
  with gr.Column():
367
 
368
- output = gr.JSON(
369
- label="Model Sonucu"
 
370
  )
371
 
 
 
 
 
372
 
373
- # --------------------------------------------------------
374
- # Γ–RNEKLER
375
- # --------------------------------------------------------
 
376
 
377
- gr.Examples(
378
- examples=examples,
379
  inputs=text_input,
380
- label="Γ–rnek Sigorta Metinleri"
 
 
 
 
381
  )
382
 
383
-
384
- # --------------------------------------------------------
385
- # BUTONLAR
386
- # --------------------------------------------------------
387
-
388
- analyze_button.click(
389
- fn=predict,
390
  inputs=text_input,
391
- outputs=output
 
 
 
 
 
 
 
 
 
392
  )
393
 
 
 
 
 
 
394
 
395
- clear_button.click(
396
- fn=lambda: "",
397
- inputs=None,
398
- outputs=text_input
 
 
 
399
  )
400
 
401
 
402
- # ============================================================
403
- # SERVER
404
- # ============================================================
405
 
406
  if __name__ == "__main__":
407
 
408
- port = int(
409
- os.environ.get(
410
- "PORT",
411
- 7860
412
- )
413
- )
414
-
415
  demo.launch(
416
  server_name="0.0.0.0",
417
- server_port=port
 
 
 
 
 
 
418
  )
 
7
  AutoModelForSequenceClassification
8
  )
9
 
10
+ from peft import PeftModel
11
 
 
 
 
 
 
12
 
13
+ # ================================================================
14
+ # CONFIG
15
+ # ================================================================
16
 
17
+ BASE_MODEL = "distilbert-base-uncased"
18
+ ADAPTER_PATH = "."
19
 
20
+ MAX_LENGTH = 128
21
 
22
+ LABELS = {
23
+ 0: "negative",
24
+ 1: "neutral",
25
+ 2: "positive"
26
+ }
27
 
 
 
 
 
 
 
28
 
29
+ # ================================================================
30
+ # DEVICE
31
+ # ================================================================
 
 
 
 
 
 
32
 
33
+ DEVICE = torch.device(
34
+ "cuda" if torch.cuda.is_available() else "cpu"
35
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
  print("=" * 60)
38
+ print("INSURANCE SENTIMENT AI")
39
  print("=" * 60)
40
 
41
  print("Device:", DEVICE)
 
 
42
 
43
+ if torch.cuda.is_available():
44
+ print("GPU:", torch.cuda.get_device_name(0))
45
 
 
 
46
 
47
+ # ================================================================
48
+ # CHECK FILES
49
+ # ================================================================
50
 
51
+ print("\nChecking model files...")
52
 
53
+ required_files = [
54
+ "adapter_config.json",
55
+ "adapter_model.safetensors",
56
+ "tokenizer.json",
57
+ "tokenizer_config.json"
58
+ ]
59
 
60
+ for file in required_files:
61
 
62
+ path = os.path.join(
63
+ ADAPTER_PATH,
64
+ file
65
  )
66
 
67
+ print(
68
+ file,
69
+ "->",
70
+ "OK" if os.path.exists(path) else "MISSING"
71
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
 
 
 
 
73
 
74
+ # ================================================================
75
+ # TOKENIZER
76
+ # ================================================================
 
 
 
 
77
 
78
+ print("\nLoading tokenizer...")
79
 
80
+ tokenizer = AutoTokenizer.from_pretrained(
81
+ ADAPTER_PATH,
82
+ use_fast=True
83
+ )
84
 
85
+ print("Tokenizer loaded.")
 
 
 
86
 
87
 
88
+ # ================================================================
89
+ # BASE MODEL
90
+ # ================================================================
91
 
92
+ print("\nLoading base DistilBERT...")
93
 
94
+ base_model = AutoModelForSequenceClassification.from_pretrained(
95
+ BASE_MODEL,
96
+ num_labels=3,
97
+ id2label=LABELS,
98
+ label2id={
99
+ "negative": 0,
100
+ "neutral": 1,
101
+ "positive": 2
102
+ },
103
+ ignore_mismatched_sizes=True
104
+ )
105
 
106
+ print("Base model loaded.")
107
 
 
 
 
 
108
 
109
+ # ================================================================
110
+ # LOAD LoRA
111
+ # ================================================================
112
 
113
+ print("\nLoading LoRA adapter...")
 
 
114
 
115
+ model = PeftModel.from_pretrained(
116
+ base_model,
117
+ ADAPTER_PATH
118
+ )
119
 
120
+ print("LoRA adapter loaded.")
121
 
 
122
 
123
+ # ================================================================
124
+ # MERGE LoRA
125
+ # ================================================================
126
 
127
+ print("\nMerging LoRA adapter...")
 
 
 
128
 
129
+ try:
130
 
131
+ model = model.merge_and_unload()
 
 
132
 
133
+ print("LoRA merged successfully.")
 
 
134
 
135
+ except Exception as e:
136
 
137
+ print("Merge skipped:", str(e))
 
 
138
 
139
 
140
+ # ================================================================
141
+ # DEVICE
142
+ # ================================================================
143
 
144
+ model = model.to(DEVICE)
 
 
 
 
 
 
145
 
146
+ model.eval()
147
 
148
+ print("\nModel ready.")
 
 
149
 
 
150
 
151
+ # ================================================================
152
+ # PREDICTION
153
+ # ================================================================
154
 
155
+ def predict_sentiment(text):
156
 
157
+ if text is None:
158
+ return {
159
+ "negative": 0.0,
160
+ "neutral": 0.0,
161
+ "positive": 0.0
162
+ }
 
163
 
164
+ text = str(text).strip()
165
 
166
+ if not text:
167
 
168
+ return {
169
+ "negative": 0.0,
170
+ "neutral": 0.0,
171
+ "positive": 0.0
172
+ }
173
 
174
+ # ------------------------------------------------------------
175
+ # Tokenize
176
+ # ------------------------------------------------------------
177
 
178
+ inputs = tokenizer(
179
+ text,
180
+ return_tensors="pt",
181
+ truncation=True,
182
+ max_length=MAX_LENGTH,
183
+ padding=True
184
+ )
185
 
186
+ inputs = {
187
+ key: value.to(DEVICE)
188
+ for key, value in inputs.items()
189
+ }
 
 
190
 
191
+ # ------------------------------------------------------------
192
+ # Inference
193
+ # ------------------------------------------------------------
194
 
195
+ with torch.inference_mode():
 
 
196
 
197
+ outputs = model(
198
+ **inputs
199
+ )
200
 
201
+ probabilities = torch.softmax(
202
+ outputs.logits,
203
+ dim=-1
204
+ )[0]
205
 
206
+ # ------------------------------------------------------------
207
+ # Results
208
+ # ------------------------------------------------------------
209
 
210
+ result = {
211
+ "negative": float(
212
+ probabilities[0].item()
213
+ ),
214
 
215
+ "neutral": float(
216
+ probabilities[1].item()
217
+ ),
 
 
218
 
219
+ "positive": float(
220
+ probabilities[2].item()
221
+ )
222
+ }
223
 
224
+ return result
225
 
 
226
 
227
+ # ================================================================
228
+ # DETAILED PREDICTION
229
+ # ================================================================
230
 
231
+ def analyze_news(text):
232
 
233
+ if text is None or not str(text).strip():
234
 
235
+ return (
236
+ "Please enter an insurance news headline.",
237
+ "",
238
+ ""
239
+ )
240
 
241
+ text = str(text).strip()
242
 
243
+ probabilities = predict_sentiment(text)
244
 
245
+ predicted_label = max(
246
+ probabilities,
247
+ key=probabilities.get
248
+ )
249
 
250
+ confidence = (
251
+ probabilities[predicted_label] * 100
252
+ )
253
 
254
+ result_text = (
255
+ f"Prediction: {predicted_label.upper()}\n"
256
+ f"Confidence: {confidence:.2f}%"
257
+ )
258
 
259
+ probability_text = (
260
+ f"Negative: "
261
+ f"{probabilities['negative'] * 100:.2f}%\n"
262
+ f"Neutral: "
263
+ f"{probabilities['neutral'] * 100:.2f}%\n"
264
+ f"Positive: "
265
+ f"{probabilities['positive'] * 100:.2f}%"
266
+ )
267
 
268
+ return (
269
+ result_text,
270
+ probability_text,
271
+ text
272
+ )
273
 
274
 
275
+ # ================================================================
276
+ # EXAMPLES
277
+ # ================================================================
278
 
279
  examples = [
280
 
281
  [
282
+ "Insurance companies reported strong financial results."
 
 
 
 
283
  ],
284
 
285
  [
286
+ "The insurer suffered major losses after severe claims."
287
  ],
288
 
289
  [
290
+ "The insurance company maintained stable operations."
291
  ],
292
 
293
  [
294
+ "The insurer reported record profits and strong growth."
295
  ],
296
 
297
  [
298
+ "Insurance claims increased significantly after the disaster."
299
  ]
 
300
  ]
301
 
302
 
303
+ # ================================================================
304
+ # GRADIO UI
305
+ # ================================================================
306
+
307
+ DESCRIPTION = """
308
+ # πŸ›‘οΈ Insurance Sentiment AI
309
+
310
+ AI-powered sentiment analysis for **insurance news headlines**.
311
+
312
+ ### Classes
313
+
314
+ 🟒 **Positive** β€” favorable insurance/business news
315
+ βšͺ **Neutral** β€” factual or balanced news
316
+ πŸ”΄ **Negative** β€” unfavorable insurance/business news
317
+
318
+ Model: **DistilBERT + LoRA**
319
+
320
+ Validation Macro F1: **78.06%**
321
+ """
322
+
323
 
324
  with gr.Blocks(
325
+ title="Insurance Sentiment AI"
326
  ) as demo:
327
 
328
  gr.Markdown(
329
+ DESCRIPTION
 
 
 
 
 
 
 
330
  )
331
 
332
+ gr.Markdown(
333
+ "Enter an English insurance news headline:"
334
+ )
335
 
336
  with gr.Row():
337
 
338
  with gr.Column():
339
 
340
  text_input = gr.Textbox(
341
+ label="Insurance News",
342
  placeholder=(
343
+ "Example: "
344
+ "Insurance companies reported "
345
+ "strong financial results."
346
  ),
347
+ lines=5
348
  )
349
 
350
+ analyze_button = gr.Button(
351
+ "πŸ” Analyze Sentiment",
352
+ variant="primary"
353
+ )
 
 
 
 
 
 
 
 
354
 
355
  with gr.Column():
356
 
357
+ prediction_output = gr.Textbox(
358
+ label="Prediction",
359
+ lines=3
360
  )
361
 
362
+ probability_output = gr.Textbox(
363
+ label="Probabilities",
364
+ lines=4
365
+ )
366
 
367
+ analyzed_text = gr.Textbox(
368
+ label="Analyzed Headline",
369
+ lines=3
370
+ )
371
 
372
+ analyze_button.click(
373
+ fn=analyze_news,
374
  inputs=text_input,
375
+ outputs=[
376
+ prediction_output,
377
+ probability_output,
378
+ analyzed_text
379
+ ]
380
  )
381
 
382
+ text_input.submit(
383
+ fn=analyze_news,
 
 
 
 
 
384
  inputs=text_input,
385
+ outputs=[
386
+ prediction_output,
387
+ probability_output,
388
+ analyzed_text
389
+ ]
390
+ )
391
+
392
+ gr.Examples(
393
+ examples=examples,
394
+ inputs=text_input
395
  )
396
 
397
+ gr.Markdown(
398
+ """
399
+ ---
400
+
401
+ ### Model Information
402
 
403
+ - **Base:** DistilBERT
404
+ - **Fine-tuning:** LoRA / PEFT
405
+ - **Task:** Insurance News Sentiment Classification
406
+ - **Labels:** Negative / Neutral / Positive
407
+ - **Validation Accuracy:** 79.75%
408
+ - **Validation Macro F1:** 78.06%
409
+ """
410
  )
411
 
412
 
413
+ # ================================================================
414
+ # LAUNCH
415
+ # ================================================================
416
 
417
  if __name__ == "__main__":
418
 
 
 
 
 
 
 
 
419
  demo.launch(
420
  server_name="0.0.0.0",
421
+ server_port=int(
422
+ os.environ.get(
423
+ "PORT",
424
+ 7860
425
+ )
426
+ ),
427
+ show_error=True
428
  )