mobadara commited on
Commit
92b802f
·
verified ·
1 Parent(s): 23748fd

Sync from GitHub via hub-sync

Browse files
app/database.py CHANGED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from sqlalchemy import create_engine
3
+ from sqlalchemy.orm import declarative_base, sessionmaker
4
+ from dotenv import load_dotenv
5
+
6
+ load_dotenv()
7
+
8
+
9
+ DATABASE_URL = os.getenv('DATABASE_URL')
10
+ engine = create_engine(DATABASE_URL)
11
+
12
+ SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
13
+ Base = declarative_base()
14
+
15
+ def get_db():
16
+ db = SessionLocal()
17
+ try:
18
+ yield db
19
+ finally:
20
+ db.close()
app/main.py CHANGED
@@ -1,7 +1,49 @@
1
- from fastapi import FastAPI
 
 
2
 
3
- app = FastAPI()
 
 
 
4
 
5
- @app.get('/')
6
- def index():
7
- return {"app": "App working successfully"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, Depends, HttpException
2
+ from sqlalchemy.orm import Session
3
+ from datetime import datetime, timezone
4
 
5
+ from .database import get_db
6
+ from .models import InferenceLog
7
+ from .schemas import SentimentRequest, SentimentResponse
8
+ from . import ml_model
9
 
10
+ app = FastAPI(
11
+ title='FinBERT Sentiment Analyzer API',
12
+ description='An API for analyzing the sentiment of financial news articles using FinBERT.',
13
+ version='1.0.0'
14
+ )
15
+
16
+ @app.post('/predict', response_model=SentimentResponse)
17
+ def predict_sentiment(request: SentimentRequest, db: Session = Depends(get_db)):
18
+ try:
19
+ prediction_result = ml_model.predict(request.text)
20
+ log_entry = InferenceLog(
21
+ input_text=request.text,
22
+ sentiment_prediction=prediction_result['sentiment'],
23
+ confidence_score=prediction_result['confidence'],
24
+ timestamp=datetime.now(timezone.utc)
25
+ )
26
+
27
+ db.add(log_entry)
28
+ db.commit()
29
+ db.close()
30
+
31
+ return SentimentResponse(
32
+ input_text=request.text,
33
+ sentiment=prediction_result['sentiment'],
34
+ confidence=prediction_result['confidence'],
35
+ timestamp=log_entry.timestamp
36
+ )
37
+ except Exception as e:
38
+ raise HttpException(status_code=500, detail=str(e))
39
+
40
+
41
+ @app.get('/logs')
42
+ def get_inference_logs(db: Session = Depends(get_db)):
43
+ logs = db.query(InferenceLog).order_by(InferenceLog.timestamp.desc()).all()
44
+ return logs
45
+
46
+
47
+ @app.get('/health')
48
+ def health_check():
49
+ return {"status": "ok", "timestamp": datetime.now(timezone.utc)}
app/ml_model.py CHANGED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ import torch
3
+ import torch.nn.functional as F
4
+ from transformers import AutoModelForSequenceClassification, AutoTokenizer
5
+
6
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
7
+ # Target your specific Hugging Face repository
8
+ HF_MODEL_REPO = 'mobadara/finbert-finetuned'
9
+
10
+ logging.info(f'Initializing NLP pipeline from {HF_MODEL_REPO}...')
11
+
12
+ # Load tokenizer and model weights
13
+ tokenizer = AutoTokenizer.from_pretrained(HF_MODEL_REPO)
14
+ model = AutoModelForSequenceClassification.from_pretrained(HF_MODEL_REPO)
15
+ model.eval() # Lock the model in evaluation mode for inference
16
+
17
+ # Map model output indices to our target classes
18
+ LABEL_MAPPING = {0: 'Negative', 1: 'Neutral', 2: "Positive"}
19
+
20
+ def predict(text: str) -> dict:
21
+ """
22
+ Takes raw text, tokenizes it, runs it through FinBERT,
23
+ and returns the predicted sentiment and confidence score.
24
+
25
+ Args:
26
+ text (str): The input text to analyze.
27
+
28
+ Returns:
29
+ dict: A dictionary containing the predicted sentiment and confidence score.
30
+
31
+ Throws:
32
+ ValueError: If the input text is empty or None.
33
+ """
34
+ if not text:
35
+ raise ValueError("Input text cannot be empty or None.")
36
+
37
+ # Tokenize the incoming text
38
+ inputs = tokenizer(
39
+ text,
40
+ return_tensors='pt',
41
+ truncation=True,
42
+ padding=True,
43
+ max_length=512
44
+ )
45
+
46
+ # Perform inference without tracking gradients (saves memory/time)
47
+ with torch.no_grad():
48
+ outputs = model(**inputs)
49
+ logits = outputs.logits
50
+
51
+ # Convert raw logits to probabilities
52
+ probabilities = F.softmax(logits, dim=-1)
53
+
54
+ # Extract the highest probability and its index
55
+ confidence_score, predicted_class_idx = torch.max(probabilities, dim=1)
56
+
57
+ sentiment_label = LABEL_MAPPING[predicted_class_idx.item()]
58
+ confidence_float = round(confidence_score.item(), 4)
59
+
60
+ return {
61
+ 'sentiment': sentiment_label,
62
+ 'confidence': confidence_float
63
+ }
app/models.py CHANGED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sqlalchemy import Column, Integer, String, Float, DateTime
2
+ from datetime import datetime, timezone
3
+
4
+ from .database import Base
5
+
6
+ class InferenceLog(Base):
7
+ __tablename__ = 'inference_logs'
8
+
9
+ id = Column(Integer, primary_key=True, index=True)
10
+ input_text = Column(String, index=True)
11
+ sentiment_prediction = Column(String, index=True)
12
+ confidence_score = Column(Float)
13
+ timestamp = Column(DateTime, default=lambda: datetime.now(timezone.utc))
app/schemas.py CHANGED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel
2
+ from datetime import datetime
3
+
4
+ class SentimentRequest(BaseModel):
5
+ text: StopIteration
6
+
7
+ class SentimentResponse(BaseModel):
8
+ input_text: str
9
+ sentiment: str
10
+ confidence: float
11
+ timestamp: datetime
12
+
13
+
notebooks/01_eda_and_data_engineering.ipynb CHANGED
@@ -1,26 +1,10 @@
1
  {
2
- "nbformat": 4,
3
- "nbformat_minor": 0,
4
- "metadata": {
5
- "colab": {
6
- "provenance": [],
7
- "authorship_tag": "ABX9TyN9T0T3HM5FCsd5NQ18TNLI",
8
- "include_colab_link": true
9
- },
10
- "kernelspec": {
11
- "name": "python3",
12
- "display_name": "Python 3"
13
- },
14
- "language_info": {
15
- "name": "python"
16
- }
17
- },
18
  "cells": [
19
  {
20
  "cell_type": "markdown",
21
  "metadata": {
22
- "id": "view-in-github",
23
- "colab_type": "text"
24
  },
25
  "source": [
26
  "<a href=\"https://colab.research.google.com/github/mobadara/finbert-sentiment-analyzer-api/blob/main/notebooks/01_eda_and_data_engineering.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
@@ -28,6 +12,9 @@
28
  },
29
  {
30
  "cell_type": "markdown",
 
 
 
31
  "source": [
32
  "# **FINANCIAL NEWS SENTIMENT ANALYSIS**\n",
33
  "## 📈 **EDA & Data Engineering**\n",
@@ -46,23 +33,20 @@
46
  "* **Source:** `financial_phrasebank` (via Hugging Face Datasets)\n",
47
  "* **Configuration:** `sentences_allagree` (Using only sentences where 100% of human annotators agreed on the sentiment)\n",
48
  "* **Labels:** 0 (Negative), 1 (Neutral), 2 (Positive)"
49
- ],
50
- "metadata": {
51
- "id": "175c_DpCsGNf"
52
- }
53
  },
54
  {
55
  "cell_type": "markdown",
56
- "source": [
57
- "### **Setup**"
58
- ],
59
  "metadata": {
60
  "id": "Gt4uyJvPtv-s"
61
- }
 
 
 
62
  },
63
  {
64
  "cell_type": "code",
65
- "execution_count": 1,
66
  "metadata": {
67
  "id": "oHA_z_6krqFa"
68
  },
@@ -86,32 +70,30 @@
86
  },
87
  {
88
  "cell_type": "code",
89
- "source": [
90
- "os.makedirs('figures', exist_ok=True)\n",
91
- "os.makedirs('datasets', exist_ok=True)"
92
- ],
93
  "metadata": {
94
  "id": "EpCL1HxowTni"
95
  },
96
- "execution_count": 2,
97
- "outputs": []
 
 
 
98
  },
99
  {
100
  "cell_type": "code",
101
- "source": [
102
- "dataset = load_dataset('FinanceMTEB/financial_phrasebank')"
103
- ],
104
  "metadata": {
105
  "id": "rLHOtOKrvMwg"
106
  },
107
- "execution_count": 3,
108
- "outputs": []
 
 
109
  },
110
  {
111
  "cell_type": "code",
112
- "source": [
113
- "dataset"
114
- ],
115
  "metadata": {
116
  "colab": {
117
  "base_uri": "https://localhost:8080/"
@@ -119,48 +101,27 @@
119
  "id": "BC7Xjb0IvRhf",
120
  "outputId": "bfe8f5b4-9a17-42b5-bb14-ac6ecd1cbd0f"
121
  },
122
- "execution_count": 4,
123
- "outputs": [
124
- {
125
- "output_type": "execute_result",
126
- "data": {
127
- "text/plain": [
128
- "DatasetDict({\n",
129
- " train: Dataset({\n",
130
- " features: ['text', 'label_text', 'label'],\n",
131
- " num_rows: 1264\n",
132
- " })\n",
133
- " test: Dataset({\n",
134
- " features: ['text', 'label_text', 'label'],\n",
135
- " num_rows: 1000\n",
136
- " })\n",
137
- "})"
138
- ]
139
- },
140
- "metadata": {},
141
- "execution_count": 4
142
- }
143
  ]
144
  },
145
  {
146
  "cell_type": "markdown",
 
 
 
147
  "source": [
148
  "The dataset has two splits:\n",
149
  "1. Train Dataset contains 1264 instances.\n",
150
  "2. Test Dataset contains 1000 instances.\n",
151
  "\n",
152
  "We need to convert the train dataset to a pandas datafrome exploration."
153
- ],
154
- "metadata": {
155
- "id": "KkoS3g2KxDfk"
156
- }
157
  },
158
  {
159
  "cell_type": "code",
160
- "source": [
161
- "df_train = dataset['train'].to_pandas()\n",
162
- "df_train.head()"
163
- ],
164
  "metadata": {
165
  "colab": {
166
  "base_uri": "https://localhost:8080/",
@@ -169,184 +130,32 @@
169
  "id": "Fd4_eL-PwUNw",
170
  "outputId": "2da09fc8-938d-4479-9460-da7cf774a1d4"
171
  },
172
- "execution_count": 5,
173
- "outputs": [
174
- {
175
- "output_type": "execute_result",
176
- "data": {
177
- "text/plain": [
178
- " text label_text label\n",
179
- "0 The Samsung Mobile Applications Store was laun... neutral 1\n",
180
- "1 F-Secure , a developer of security solutions a... neutral 1\n",
181
- "2 The company serves customers in various indust... neutral 1\n",
182
- "3 The company reported net sales of 302 mln euro... neutral 1\n",
183
- "4 Microsoft last week also issued the first patc... neutral 1"
184
- ],
185
- "text/html": [
186
- "\n",
187
- " <div id=\"df-1def2767-92a3-4c60-8c46-59087082dc12\" class=\"colab-df-container\">\n",
188
- " <div>\n",
189
- "<style scoped>\n",
190
- " .dataframe tbody tr th:only-of-type {\n",
191
- " vertical-align: middle;\n",
192
- " }\n",
193
- "\n",
194
- " .dataframe tbody tr th {\n",
195
- " vertical-align: top;\n",
196
- " }\n",
197
- "\n",
198
- " .dataframe thead th {\n",
199
- " text-align: right;\n",
200
- " }\n",
201
- "</style>\n",
202
- "<table border=\"1\" class=\"dataframe\">\n",
203
- " <thead>\n",
204
- " <tr style=\"text-align: right;\">\n",
205
- " <th></th>\n",
206
- " <th>text</th>\n",
207
- " <th>label_text</th>\n",
208
- " <th>label</th>\n",
209
- " </tr>\n",
210
- " </thead>\n",
211
- " <tbody>\n",
212
- " <tr>\n",
213
- " <th>0</th>\n",
214
- " <td>The Samsung Mobile Applications Store was laun...</td>\n",
215
- " <td>neutral</td>\n",
216
- " <td>1</td>\n",
217
- " </tr>\n",
218
- " <tr>\n",
219
- " <th>1</th>\n",
220
- " <td>F-Secure , a developer of security solutions a...</td>\n",
221
- " <td>neutral</td>\n",
222
- " <td>1</td>\n",
223
- " </tr>\n",
224
- " <tr>\n",
225
- " <th>2</th>\n",
226
- " <td>The company serves customers in various indust...</td>\n",
227
- " <td>neutral</td>\n",
228
- " <td>1</td>\n",
229
- " </tr>\n",
230
- " <tr>\n",
231
- " <th>3</th>\n",
232
- " <td>The company reported net sales of 302 mln euro...</td>\n",
233
- " <td>neutral</td>\n",
234
- " <td>1</td>\n",
235
- " </tr>\n",
236
- " <tr>\n",
237
- " <th>4</th>\n",
238
- " <td>Microsoft last week also issued the first patc...</td>\n",
239
- " <td>neutral</td>\n",
240
- " <td>1</td>\n",
241
- " </tr>\n",
242
- " </tbody>\n",
243
- "</table>\n",
244
- "</div>\n",
245
- " <div class=\"colab-df-buttons\">\n",
246
- "\n",
247
- " <div class=\"colab-df-container\">\n",
248
- " <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-1def2767-92a3-4c60-8c46-59087082dc12')\"\n",
249
- " title=\"Convert this dataframe to an interactive table.\"\n",
250
- " style=\"display:none;\">\n",
251
- "\n",
252
- " <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\">\n",
253
- " <path d=\"M120-120v-720h720v720H120Zm60-500h600v-160H180v160Zm220 220h160v-160H400v160Zm0 220h160v-160H400v160ZM180-400h160v-160H180v160Zm440 0h160v-160H620v160ZM180-180h160v-160H180v160Zm440 0h160v-160H620v160Z\"/>\n",
254
- " </svg>\n",
255
- " </button>\n",
256
- "\n",
257
- " <style>\n",
258
- " .colab-df-container {\n",
259
- " display:flex;\n",
260
- " gap: 12px;\n",
261
- " }\n",
262
- "\n",
263
- " .colab-df-convert {\n",
264
- " background-color: #E8F0FE;\n",
265
- " border: none;\n",
266
- " border-radius: 50%;\n",
267
- " cursor: pointer;\n",
268
- " display: none;\n",
269
- " fill: #1967D2;\n",
270
- " height: 32px;\n",
271
- " padding: 0 0 0 0;\n",
272
- " width: 32px;\n",
273
- " }\n",
274
- "\n",
275
- " .colab-df-convert:hover {\n",
276
- " background-color: #E2EBFA;\n",
277
- " box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
278
- " fill: #174EA6;\n",
279
- " }\n",
280
- "\n",
281
- " .colab-df-buttons div {\n",
282
- " margin-bottom: 4px;\n",
283
- " }\n",
284
- "\n",
285
- " [theme=dark] .colab-df-convert {\n",
286
- " background-color: #3B4455;\n",
287
- " fill: #D2E3FC;\n",
288
- " }\n",
289
- "\n",
290
- " [theme=dark] .colab-df-convert:hover {\n",
291
- " background-color: #434B5C;\n",
292
- " box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
293
- " filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
294
- " fill: #FFFFFF;\n",
295
- " }\n",
296
- " </style>\n",
297
- "\n",
298
- " <script>\n",
299
- " const buttonEl =\n",
300
- " document.querySelector('#df-1def2767-92a3-4c60-8c46-59087082dc12 button.colab-df-convert');\n",
301
- " buttonEl.style.display =\n",
302
- " google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
303
- "\n",
304
- " async function convertToInteractive(key) {\n",
305
- " const element = document.querySelector('#df-1def2767-92a3-4c60-8c46-59087082dc12');\n",
306
- " const dataTable =\n",
307
- " await google.colab.kernel.invokeFunction('convertToInteractive',\n",
308
- " [key], {});\n",
309
- " if (!dataTable) return;\n",
310
- "\n",
311
- " const docLinkHtml = 'Like what you see? Visit the ' +\n",
312
- " '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n",
313
- " + ' to learn more about interactive tables.';\n",
314
- " element.innerHTML = '';\n",
315
- " dataTable['output_type'] = 'display_data';\n",
316
- " await google.colab.output.renderOutput(dataTable, element);\n",
317
- " const docLink = document.createElement('div');\n",
318
- " docLink.innerHTML = docLinkHtml;\n",
319
- " element.appendChild(docLink);\n",
320
- " }\n",
321
- " </script>\n",
322
- " </div>\n",
323
- "\n",
324
- "\n",
325
- " </div>\n",
326
- " </div>\n"
327
- ],
328
- "application/vnd.google.colaboratory.intrinsic+json": {
329
- "type": "dataframe",
330
- "variable_name": "df_train",
331
- "summary": "{\n \"name\": \"df_train\",\n \"rows\": 1264,\n \"fields\": [\n {\n \"column\": \"text\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 1263,\n \"samples\": [\n \"R&D Loan ) .\",\n \"Mr. Mikko Saavalainen , head of Comptel 's Global Sales concludes : `` Gibtelecom provides a perfect illustration of the variety of business , technical and regulatory challenges operators are facing in their OSS today .\",\n \"The decision reflects the underutilisation of the line , which produces nonwovens used in medical and wipes applications as well as for the automotive industry .\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"label_text\",\n \"properties\": {\n \"dtype\": \"category\",\n \"num_unique_values\": 3,\n \"samples\": [\n \"neutral\",\n \"positive\",\n \"negative\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"label\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": 0,\n \"max\": 2,\n \"num_unique_values\": 3,\n \"samples\": [\n 1,\n 2,\n 0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}"
332
- }
333
- },
334
- "metadata": {},
335
- "execution_count": 5
336
- }
337
  ]
338
  },
339
  {
340
  "cell_type": "markdown",
341
- "source": [
342
- "### **Data Check and Cleaning**"
343
- ],
344
  "metadata": {
345
  "id": "8G472RswiiTH"
346
- }
 
 
 
347
  },
348
  {
349
  "cell_type": "code",
 
 
 
 
 
 
 
 
 
350
  "source": [
351
  "# Check for `null` values\n",
352
  "nulls_per_column = df_train.isna().sum()\n",
@@ -358,33 +167,13 @@
358
  "print(nulls_per_column)\n",
359
  "print(\"-\" * 30)\n",
360
  "print(f\"Number of Duplicated Instances: {duplicated_instances}\")"
361
- ],
362
- "metadata": {
363
- "colab": {
364
- "base_uri": "https://localhost:8080/"
365
- },
366
- "id": "rotrrtnxishA",
367
- "outputId": "8c8a8437-5c03-43f8-9292-0fb453b3c594"
368
- },
369
- "execution_count": 6,
370
- "outputs": [
371
- {
372
- "output_type": "stream",
373
- "name": "stdout",
374
- "text": [
375
- "Null Values Per Column:\n",
376
- "text 0\n",
377
- "label_text 0\n",
378
- "label 0\n",
379
- "dtype: int64\n",
380
- "------------------------------\n",
381
- "Number of Duplicated Instances: 1\n"
382
- ]
383
- }
384
  ]
385
  },
386
  {
387
  "cell_type": "markdown",
 
 
 
388
  "source": [
389
  "We see that our dataset (in tabular form) contains three columns: **text**, **label_text** and **label**.\n",
390
  "\n",
@@ -395,38 +184,45 @@
395
  "-----------|-----\n",
396
  "negative | `0`\n",
397
  "neutral | `1`\n",
398
- "positive | `1`\n",
399
  "\n",
400
  "\n",
401
  "We see from our result that one instance in the dataset is exactly repeated. We drop the duplicated values in the following cell."
402
- ],
403
- "metadata": {
404
- "id": "1T4BUAkbyjp0"
405
- }
406
  },
407
  {
408
  "cell_type": "code",
409
- "source": [
410
- "df_train.drop_duplicates(inplace=True)\n",
411
- "assert df_train.duplicated().sum() == 0"
412
- ],
413
  "metadata": {
414
  "id": "HWZSAfqTkgtU"
415
  },
416
- "execution_count": 7,
417
- "outputs": []
 
 
 
418
  },
419
  {
420
  "cell_type": "markdown",
421
- "source": [
422
- "Now that the duplicated entries are removed, we need to visualize our class distribution."
423
- ],
424
  "metadata": {
425
  "id": "NzLiGGnnl2D2"
426
- }
 
 
 
427
  },
428
  {
429
  "cell_type": "code",
 
 
 
 
 
 
 
 
 
 
430
  "source": [
431
  "plt.figure(figsize=(8, 5))\n",
432
  "ax = sns.countplot(data=df_train,\n",
@@ -447,60 +243,48 @@
447
  "\n",
448
  "plt.savefig('figures/class_distribution.png')\n",
449
  "plt.show()"
450
- ],
451
- "metadata": {
452
- "colab": {
453
- "base_uri": "https://localhost:8080/",
454
- "height": 492
455
- },
456
- "id": "FQs0xwBqyPP8",
457
- "outputId": "0c838bcf-645b-4825-81d8-76ed1e442e3b"
458
- },
459
- "execution_count": 8,
460
- "outputs": [
461
- {
462
- "output_type": "display_data",
463
- "data": {
464
- "text/plain": [
465
- "<Figure size 800x500 with 1 Axes>"
466
- ],
467
- "image/png": "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1atXR8+ePfHbb79hx44dGD16dIlt4+Pj0bhxY2RmZqJTp07o1asXMjMzcfv2baxYsQLff/89LCwsMG3aNKxduxb379/HtGnTxOcHBwdr9RcbG4umTZuibt26GDRoEJ4+fVqqI44LFy5EVFQUevXqhU6dOuHAgQNYtGgRTp06haNHj0IqlZZ5O8jlckybNg2LFi0CAHz22WfispedXBATE4OWLVsiKSkJXbp0Qe3atXHt2jWsWbMGf/75J44fP47AwMAiz+vTpw/OnDmDDh06wNzcHJs3b8bIkSMhlUoxbNiwUuX96aefYunSpfD29saHH34IANi2bRsGDx6MixcvYvHixVpjeH58crn8hf0X/PQZExNTqnyAZ1Nl3nnnHRw+fBjBwcH48MMPoVKpsHv3bnTt2hVLly4t9uftL774AkeOHEHnzp3Rvn177NixA9OnT0deXh7mzJkDAHjvvfeQmpqKP/74A127di3yN/Uyp0+fxvz589G+fXt8/PHHOHToEH788UekpaWhS5cuGDRoELp27YpmzZph9+7d+O6772BnZ4epU6dq9TNx4kR888038Pb2xvvvvw9HR0ccO3YMX3zxBU6fPo0tW7YUWffOnTuxe/dudOnSBc2bN8fRo0cRERGBO3fu4Pjx4wCe7SNjxozB4sWLERQUhPfee098fsEXk/DwcGzevBn16tXD4MGDIZPJ8PDhQxw6dAhnz55FUFBQmbbJ80rzOrwKpd0/jh49igULFuCtt95CkyZNIJVKcfHiRfz444/4+++/ceHChWKnSpRlnJ9//jkWLlwIZ2dnvPfee3B3d8fDhw9x4MABvPnmm6hTp84LxzJy5EgEBQWhbdu2cHNzw+PHj7Fjxw60bdsWkZGR6Nq1q342WgmeP39CpVKhXbt2UCgU6N69O7KysrBx40b07NkTf/31F9q1a1ekj9GjR+PUqVPo1KkTunTpAnd3dwBl2/6CIKB9+/Y4ffo0WrRogXfeeQdmZma4f/8+du7ciQEDBsDX11ds269fP2zYsAHVqlVD3759YWlpif379+PDDz9EdHQ0vv/++1KN//79+7h16xZ8fHzEvAvo8tqcPXsW3377Ldq0aYOPP/4YFy9exI4dO3D16lVcu3YNVlZWJeaiUqkwaNAgrF+/Hp999hkWLlz4Wp7fYhACUTHu3bsnABDat2//wnarV68W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6NFDbNO1a1fk5uZi5cqVyMrKQo0aNTBp0iStN+hPP/0Uq1evxsyZMyGRPLupxJAhQwwxJCIinTRq1Ah37tzRit29exfe3t7l6rdhw4bYsWMHNBqN+Eva3bt34eHhUaTQBYDFixcjNDQUdevWxbVr15Cfny8uU6lU0Gg05cqHiKiiGdUJasYmKSlJ68Q1IqJX5dKlS+jatSs+//xzdOnSBZcuXcIXX3yBb7/9Fu+//z6AZ2ckP378GP/++y8GDhyIFStWoGrVqnB3d4e7uzuAZ1/+PT09xekQjx8/RlhYGD744AMMHjwY9+7dw+eff44hQ4ZgzJgxWjnExMRgyJAh2LdvH2xsbJCdnY1GjRph8uTJcHNzw0cffYQTJ05o3cGSiOhVKe0Jaix2X4DFLhEZ0v79+/HNN9/g3r17eOONN/DRRx+hX79+4vJNmzaJ82wLGzduHD7//HMAQI8ePeDj44NFixaJy8+dO4fp06cjOjoalSpVQu/evcWrMRQQBAHdunXDyJEj8fbbb2vlNHnyZOTl5eHLL79E3759K2DkREQvx2JXD1jsEhERERmn0ha7RnW7YCIiIiIifTKqE9SIiJ7XokWeoVMg0nLiRNET+YjIePHILhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJsvC0AkUNnLkSCQlJRWJt2vXDkOHDkVeXh4iIiJw8uRJqFQqBAUFYejQoZDL5WLb5ORk/PLLL7h+/TqsrKwQEhKCvn37wtzc/BWOhIiIiIiMgVEVu/PmzYNGoxEfP3jwALNnz0azZs0AAOvWrcOFCxcwbtw42NjYYPXq1ViwYAFmzZoFANBoNJg3bx7kcjlmz54NhUKBZcuWwdzcHH379jXImIiIiIjIcIxqGoODgwPkcrn478KFC/Dw8ECtWrWQlZWFgwcPIjw8HHXq1IG/vz9GjBiBW7duISYmBgBw+fJlPHr0CKNHj4afnx/q16+PXr164e+//4ZarTbw6IiIiIjoVTOqYrcwtVqNY8eOoU2bNpBIJLh79y7y8/NRt25dsY23tzdcXV3FYjcmJgaVK1fWmtYQHByM7OxsPHz4sMR1qVQqZGVlif+ys7PFZRKJBBKJRKt9Qaw88cIxfcX1nSPHxDEZw5iIjM3rvD+Z4nsEx/TfHVNpGdU0hsLOnDmDzMxMhIaGAgBSU1NhYWEBW1tbrXaOjo5ITU0V2xQudAuWFywryfbt27F161bxcZUqVTB//nw4ODhAEAQAQG5uLjIzM2FrawuZTCa2zc7ORnZ2Nuzt7SGVSsV4ZmYmcnNz4ejoqDVfOD09HSqVCnK5XOsFUyqV0Gg0cHJy0spNoVDAzMxMHAcACIIAhUIBqVQKe3t7MZ6fnw+lUgmZTKa1nVQqFdLT02FtbQ1ra2sxzjFxTK/HmBJAZEycnJxe4/3JFN8jOKb/6pgcHBxQGhKhoJozMnPmzIG5uTm++uorAMDx48exYsUKrF+/XqvdxIkTUbt2bfTv3x8rV65EcnIyJk+eLC7Pzc3FgAEDMHHiRNSvX7/YdalUKqhUKvGxRCKBtbU1kpKSxOkPhTdT4RdC1/jz30z0Edd3jhwTx2QMY2rePBdExuTkSdlruz+VJs4xcUyvy5ikUinc3NzwMkZ5ZDcpKQlXrlzB+PHjxZhcLodarRa/QRRQKpXi0Vy5XI7Y2FitvpRKpbisJFKpVOubR2HFfRco6ftBWeL66MPY4saUi77ixpSLvuLGlIsucSJDK/y3aWz7B98jOKbXOV5RnwdGOWf30KFDcHR0RIMGDcSYv78/zM3NcfXqVTEWHx+P5ORkBAYGAgACAwPx4MEDscAFgCtXrsDa2ho+Pj6vbgBEREREZBSM7siuRqPB4cOHERISojWfw8bGBmFhYYiIiICdnR1sbGywZs0aBAYGisVuUFAQfHx8sGzZMvTr1w+pqanYuHEj2rdvX+KRWyIiIiIyXUZX7F69ehXJyclo06ZNkWXh4eGQSCRYsGAB1Gq1eFOJAmZmZvjqq6+watUqTJkyBTKZDCEhIejVq9erHAIRERERGQmjPUHNGCQlJWmduEZEr16LFnmGToFIy4kTloZOgYhQ+hPUjHLOLhERERGRPrDYJSIiIiKTxWKXiIiIiEwWi10iIiIiMlksdomIiIjIZLHYJSIiIiKTxWKXiIiIiEwWi10iIiIiMlksdomIiIjIZLHYJSIiIiKTxWKXiIiIiEwWi10iIiIiMlksdomIiIjIZLHYJSIiIiKTxWKXiIiIiEwWi10iIiIiMlksdomIiIjIZLHYJSIiIiKTxWKXiIiIiEwWi10iIiIiMlksdomIiIjIZLHYJSIiIiKTxWKXiIiIiEwWi10iIiIiMlksdomIiIjIZLHYJSIiIiKTxWKXiIiIiEwWi10iIiIiMlksdomIiIjIZLHYJSIiIiKTxWKXiIiIiEwWi10iIiIiMlksdomIiIjIZLHYJSIiIiKTxWKXiIiIiEwWi10iIiIiMlkWhk7geSkpKfjf//6HS5cuITc3F5UqVcKIESNQtWpVAIAgCNi8eTOioqKQmZmJGjVqYOjQofD09BT7yMjIwJo1a3D+/HlIJBI0adIEgwcPhpWVlaGGRUREREQGIBEEQTB0EgUyMjIwYcIE1K5dG+3atYODgwOePHkCDw8PVKpUCQCwY8cO7NixAyNHjoS7uzs2bdqEBw8eYOHChbC0tAQAzJ07FwqFAh999BHy8/OxYsUKVK1aFWPGjClTPklJSVCpVHofJxGVXosWeYZOgUjLiROWhk6BiABIpVK4ubm9tJ1RTWP4448/4OLighEjRiAgIADu7u4ICgoSC11BELBnzx68//77aNSoEXx9fTFq1CgoFAqcPXsWAPDo0SNcunQJw4cPR7Vq1VCjRg0MGTIEJ0+eREpKiiGHR0RERESvmFFNYzh37hyCgoKwcOFCREdHw9nZGe3atUPbtm0BAImJiUhNTUW9evXE59jY2CAgIAAxMTFo0aIFYmJiYGtrK057AIC6detCIpEgNjYWjRs3LrJelUqldQRXIpHA2tpa/H/gWaFdeHkBXeOFY/qK6ztHjoljMpYxERkTiUTyWu9PpvgewTH9N8dUWkZV7CYmJmL//v3o1KkTunXrhjt37uDXX3+FhYUFQkNDkZqaCgBwdHTUep6jo6O4LDU1FQ4ODlrLzc3NYWdnJ7Z53vbt27F161bxcZUqVTB//nw4ODiIGzQ3NxeZmZmwtbWFTCYT22ZnZyM7Oxv29vaQSqViPDMzE7m5uXB0dIS5ubkYT09Ph0qlglwu13rxlEolNBoNnJyctHJTKBQwMzPTGrMgCFAoFJBKpbC3txfj+fn5UCqVkMlksLW1FeMqlQrp6emwtrYWi3iOiWN6fcaUACJj4uTk9BrvT6b4HsEx/VfH9Hy9VxKjmrPbp08fVK1aFbNnzxZja9aswZ07dzBnzhzcunULX3/9NVauXKk18IULF0IikWDs2LGIjIzEkSNHsHjxYq2+hw4dip49e6Jdu3ZF1lvSkd2kpCSo1WoAhv/2YorfyDgmjqk08ebNc0FkTE6elL22+1Np4hwTx/S6jKm0c3b1emRXrVZDrVbrfNUDJycn+Pj4aMV8fHxw+vRpAIBcLgfwrNIvXOwqlUr4+fmJbdLS0rT6yM/PR0ZGhvj850mlUq1vHoUV912gpO8HZYnrow9jixtTLvqKG1Mu+oobUy66xIkMrfDfprHtH3yP4Jhe53hFfR7odILaiRMnsHbtWq3Yli1bMGDAAAwePBjfffcdcnJyytxv9erVER8frxWLj48Xq3Z3d3fI5XJcvXpVXJ6VlYXY2FgEBgYCAAIDA5GZmYm7d++Kba5duwZBEBAQEFDmnIiIiIjo9aVTsbtr1y7k5v7/T4u3bt3C1q1bERQUhE6dOuHSpUuIjIwsc7+dOnXC7du3ERkZiYSEBBw/fhxRUVFo3749gGeHsTt27IjIyEicO3cODx48wLJly+Dk5IRGjRoBeHYkODg4GCtXrkRsbCxu3ryJNWvWoHnz5nB2dtZluERERET0mtJpGkNCQgJCQkLEx8ePH4dcLscXX3wBc3NzaDQanD59Gn379i1TvwEBARg/fjzWr1+Pbdu2wd3dHeHh4WjVqpXYpmvXrsjNzcXKlSuRlZWFGjVqYNKkSeI1dgHg008/xerVqzFz5kxIJM9uKjFkyBBdhkpERERErzGdil21Wq01x/XKlSsIDg4Wz6zz8fHBvn37dErozTffxJtvvlnicolEgl69eqFXr14ltrGzsyvzDSSIiIiIyPToNI3B3d1dnDd7584dJCQkIDg4WFyuVCp5a14iIiIiMjidjuy2bdsWa9euxaNHj/D06VM4OztrHY29desW3njjDb0lSURERESkC52K3Q4dOkAqleLixYvw9/dH165dxTmzGRkZSE1Nxdtvv63XRImIiIiIysqobiphbJKSkrRuNkFEr16LFnmGToFIy4kTli9vREQV7pXcVEKlUuHevXtQKpWoXr16qW/bRkRERET0Kuhc7O7ZswdbtmxBVlYWAODrr79GnTp1kJaWhrFjx6Jfv34ICwvTW6JERERERGWl09UYDh06hHXr1iE4OBiffPKJ1jIHBwfUrl0bJ0+e1EuCRERERES60vkOag0bNsSYMWOKvSauv78/Hj58WO7kiIiIiIjKQ6diNyEhAfXr1y9xuZ2dHTIyMnROioiIiIhIH3Qqdm1sbJCWllbi8kePHkEul+uaExERERGRXuhU7NavXx9RUVHIzMwssuzhw4eIiop64S1/iYiIiIheBZ2uxtC7d29MnjwZn3/+uVjUHj58GAcPHsTp06fh5OSEHj166DVRIiIiIqKy0vmmEkqlEhs2bMDp06fFy49ZWVmhSZMm6NevHxwdHfWaqCHwphJEhsebSpCx4U0liIxDaW8qoZc7qKWlpUGj0cDBwQFmZjrNjDBKLHaJDI/FLhkbFrtExuGV3EGtAO+cRkRERETGSKfDsBs3bsQXX3xR4vIvv/wSW7Zs0TkpIiIiIiJ90KnYPXXq1Auvs1u/fn3eQY2IiIiIDE6nYjc5ORkeHh4lLnd3d0dycrLOSRERERER6YNOxa6VlRWSkpJKXJ6YmAipVKpzUkRERERE+qBTsVurVi0cOHAAKSkpRZYlJyfjwIEDqF27drmTIyIiIiIqD51vKjFx4kSMGzcOYWFh8PHxAfDs7mmHDh2CIAjo1auXXhMlIiIiIiorna+ze//+faxZswY3b97UitesWRODBw+Gr6+vXhI0JF5nl8jweJ1dMja8zi6RcXhlN5VIS0tDYmIigGcnppnSNXdZ7BIZHotdMjYsdomMwyu7qYSDg4NJFbhEREREZDp0LnY1Gg0uXbqExMREZGRkFNumR48eOidGRERERFReOhW7d+7cwYIFC/D06dMXtmOxS0RERESGpFOxu2rVKuTl5eGLL75AzZo1YWtrq++8iIiIiIjKTadi98GDB+jduzcaNmyo73yIiIiIiPRGp5tKODs7o5wXcSAiIiIiqnA6Fbtdu3ZFVFQUsrKy9J0PEREREZHe6DSNIScnB1ZWVvj000/RvHlzuLq6wsysaN3cuXPncidIRERERKQrnYrd3377Tfz/v//+u8R2LHaJiIiIyJB0KnaXLVum7zyIiIiIiPROp2K3NLdmIyIiIiIytHLdLjglJQXR0dFIS0tDkyZN4OLiAo1Gg6ysLNjY2BQ7j5eIiIiI6FXRqdgVBAERERH466+/oNFoAACVK1eGi4sLcnJyMHLkSPTs2ROdOnXSa7JERERERGWhU7G7c+dO7NmzB127dkXdunUxe/ZscZmNjQ0aN26M06dPl7nY3bx5M7Zu3aoV8/LywqJFiwAAeXl5iIiIwMmTJ6FSqRAUFIShQ4dCLpeL7ZOTk/HLL7/g+vXrsLKyQkhICPr27Qtzc3NdhkpERERErzGdit2oqCixiExPTy+y3NfXF5cuXdIpoTfeeANff/21+LjwVIh169bhwoULGDduHGxsbLB69WosWLAAs2bNAgBoNBrMmzcPcrkcs2fPhkKhwLJly2Bubo6+ffvqlA8RERERvb50mlT79OlTBAYGlrhcJpPpfMMJMzMzyOVy8Z+DgwMAICsrCwcPHkR4eDjq1KkDf39/jBgxArdu3UJMTAwA4PLly3j06BFGjx4NPz8/1K9fH7169cLff/8NtVqtUz5ERERE9PrS6ciug4MDnj59WuLyu3fvwtXVVaeEEhIS8PHHH0MqlSIwMBB9+/aFq6sr7t69i/z8fNStW1ds6+3tDVdXV8TExCAwMBAxMTGoXLmy1rSG4OBgrFq1Cg8fPkSVKlWKXadKpYJKpRIfSyQSWFtbi/8PQOv2yAWx8sQLx/QV13eOHBPHZCxjIjImEonktd6fTPE9gmP6b46ptHQqdps0aYL9+/cjNDQUNjY2WssuX76Mw4cPo2vXrmXut1q1ahgxYgS8vLygUCiwdetWTJ06FQsWLEBqaiosLCxga2ur9RxHR0ekpqYCAFJTU7UK3YLlBctKsn37dq25wlWqVMH8+fPh4OAgbtDc3FxkZmbC1tYWMplMbJudnY3s7GzY29tDKpWK8czMTOTm5sLR0VFrvnB6ejpUKhXkcrnWi6dUKqHRaODk5KSVm0KhgJmZmTgO4NmLrFAoIJVKYW9vL8bz8/OhVCohk8m0tpNKpUJ6ejqsra3FIp5j4phenzElgMiYODk5vcb7kym+R3BM/9UxFfz6/zISoazlMZ5NKZg2bRoSExNRo0YNXLp0CfXq1UNOTg5iYmJQpUoVzJgxQ2vgusjMzMSIESMQHh4OS0tLrFixAuvXr9dqM3HiRNSuXRv9+/fHypUrkZycjMmTJ4vLc3NzMWDAAEycOBH169cvdj0lHdlNSkoSpz8Y+tuLKX4j45g4ptLEmzfPBZExOXlS9truT6WJc0wc0+syJqlUWqp7P+h0ZNfGxgZz5szBn3/+iVOnTsHS0hLR0dGoVKkSPvjgA7z77ruwtLTUpWsttra28PLyQkJCAurVqwe1Wi1+gyigVCrFo7lyuRyxsbFafSiVSnFZSaRSqdY3j8KK+y5Q0veDssT10YexxY0pF33FjSkXfcWNKRdd4kSGVvhv09j2D75HcEyvc7yiPg90vqmEpaUlunfvju7du5crgRfJyclBQkICWrVqBX9/f5ibm+Pq1ato2rQpACA+Ph7JycniyXKBgYGIjIyEUqkUD9dfuXIF1tbW8PHxqbA8iYiIiMg46XQ1hhkzZuDq1aslLr927RpmzJhR5n4jIiIQHR2NxMRE3Lp1C9999x3MzMzQsmVL2NjYICwsDBEREbh27Rru3r2LFStWIDAwUCx2g4KC4OPjg2XLliEuLg6XLl3Cxo0b0b59+xKP3BIRERGR6dLpyG50dDTeeuutEpenpaUhOjq6zP2mpKRg8eLFSE9Ph4ODA2rUqIE5c+aIE5DDw8MhkUiwYMECqNVq8aYSBczMzPDVV19h1apVmDJlCmQyGUJCQtCrV6+yD5KIiIiIXns6T2N4kYSEBK2z9Urrs88+e+FyS0tLDB06VKvAfZ6bmxsmTpxY5nUTERERkekpdbF7+PBhHDlyRHwcGRmJqKioIu2ysrJw//79Eq98QERERET0qpS62M3Ly0NaWpr4ODs7u8ilICQSCWQyGd5++2306NFDf1kSEREREelAp+vsjhw5EoMHD0bDhg0rIiejkZSUpHX9XSJ69Vq0yDN0CkRaTpwo/6U1iaj8KvQ6u8uXL9flaUREREREr1S5TlDLzs5GUlISMjMzi73gb61atcrTPRERERFRuehU7KalpWHNmjU4ffo0NBpNie02bdqkc2JEREREROWlU7H7888/4/z58+jQoQNq1KgBOzs7fedFRERERFRuOhW7ly9fRqdOndC/f39950NEREREpDc63S5YJpOV6uw3IiIiIiJD0qnYbdWqFc6cOaPvXIiIiIiI9EqnaQxNmzZFdHQ05syZg7Zt28LFxQVmZkXrZn9//3InSERERESkK52K3alTp4r/f+XKlRLb8WoMRERERGRIOhW7n3zyib7zICIiIiLSO52K3dDQUD2nQURERESkfzqdoFaYQqFAXFwccnJy9JEPEREREZHe6Fzsnj17Fp999hmGDx+OCRMmIDY2FsCzu6t9+eWXvFoDERERERmcTsXuuXPn8P3338Pe3h4ffPCB1jIHBwc4Ozvj8OHD+siPiIiIiEhnOhW727ZtQ61atTBr1iy0b9++yPLAwEDcu3ev3MkREREREZWHTsXugwcP0KxZsxKXOzo6Ii0tTeekiIiIiIj0QefbBb/ohLR///0XdnZ2OidFRERERKQPOhW7tWvXxpEjR5Cfn19kWWpqKqKiohAUFFTu5IiIiIiIykOnYrdPnz5ISUnBxIkTsX//fgDApUuXsHHjRnz++ecAgB49eugvSyIiIiIiHUgEQRB0eeLDhw+xdu1aXLt2TSteq1YtfPjhh/Dx8dFLgoaUlJQElUpl6DSI/tNatMgzdApEWk6csDR0CkQEQCqVws3N7aXtdC52C2RkZCAhIQGCIMDDwwMODg7l6c6osNglMjwWu2RsWOwSGYfSFrs63S64MDs7OwQEBJS3GyIiIiIivSt1sZuamor4+Hj4+/vDyspKjKvVamzbtg3Hjx+HQqGAt7c3PvjgAzRs2LBCEiYiIiIiKq1Sn6C2Y8cO/PDDD7Cw0K6PIyIiEBkZiYyMDLzxxhuIj4/HggULEB0drfdkiYiIiIjKotRHdqOjo/Hmm29qFbtpaWnYt28ffHx8MHPmTNja2iIpKQlTpkzBrl27UKtWrQpJmoiIiIioNEp9ZPfp06dFrrBw/vx5CIKALl26wNbWFgDg5uaG0NBQ3L59W7+ZEhERERGVUamL3by8PK25ugBw48YNAECdOnW04h4eHsjMzNRDekREREREuit1sevu7o64uDit2PXr1+Hm5gZXV1eteE5ODm8XTEREREQGV+pit0mTJjhy5AhOnjyJ5ORkREZGIjk5Gc2aNSvS9vbt2/Dw8NBrokREREREZVXqE9TeffddnD9/HosXLxZjXl5eeP/997Xapaen49y5c3j33Xf1lyURERERkQ5KXexaWVlh7ty5OHPmDP7991+4ubmhUaNGsLTUvpNMSkoKevbsiaZNm+o9WSIiIiKisijTHdTMzc2LnbZQmK+vL3x9fcuVFBERERGRPpR6zi4RERER0eumTEd2X6UdO3Zg/fr16NixIwYNGgTg2eXPIiIicPLkSahUKgQFBWHo0KGQy+Xi85KTk/HLL7/g+vXrsLKyQkhICPr27Qtzc3PDDISIiIiIDMYoj+zGxsZi//79RaZDrFu3DufPn8e4ceMwY8YMKBQKLFiwQFyu0Wgwb948qNVqzJ49GyNHjsThw4exadOmVz0EIiIiIjICRlfs5uTkYOnSpfj444/Fu7IBQFZWFg4ePIjw8HDUqVMH/v7+GDFiBG7duoWYmBgAwOXLl/Ho0SOMHj0afn5+qF+/Pnr16oW///4barXaUEMiIiIiIgMpVbG7Z88exMfHV3QuAIBVq1ahfv36qFevnlb87t27yM/PR926dcWYt7c3XF1dxWI3JiYGlStX1prWEBwcjOzsbDx8+LDEdapUKmRlZYn/srOzxWUSiQQSiUSrfUGsPPHCMX3F9Z0jx8QxGcOYiIzN67w/meJ7BMf03x1TaZVqzu66devg4OAALy8vAECvXr0wevRotGzZsswrfJETJ07g3r17mDdvXpFlqampsLCw0DraCwCOjo5ITU0V2xQudAuWFywryfbt27F161bxcZUqVTB//nw4ODhAEAQAQG5uLjIzM2FrawuZTCa2zc7ORnZ2Nuzt7SGVSsV4ZmYmcnNz4ejoqDVfOD09HSqVCnK5XOsFUyqV0Gg0cHJy0spNoVDAzMxMHAcACIIAhUIBqVQKe3t7MZ6fnw+lUgmZTKa1nVQqFdLT02FtbQ1ra2sxzjFxTK/HmBJAZEycnJxe4/3JFN8jOKb/6pgcHBxQGqUqdu3s7F5YLOpDcnIy1q5diylTphS5dm9F69atGzp37iw+LtjQaWlp4vSHgqI3MzMTWVlZYtuCeHp6utYLVBBXKpXFxp/fngVxhUJRJJ6fn18kDjz74yscL1yY5+XlFYlnZ2cjJyenSJxj4piMfUxExkShULzW+5MpvkdwTP/NMaWlpcHNza3IuJ5XqmK3Vq1a2LJlC+Li4mBjYwMAOHLkiDh9oDgSiQSDBw8uTfcAnk1TUCqVmDBhghjTaDS4ceMG/vrrL0yePBlqtVr8BlFAqVSKR3PlcjliY2O1+lUqleKykkilUq1vHoUVbOiXxcoa10cfxhY3plz0FTemXPQVN6ZcdIkTGVrhv01j2z/4HsExvc7xivo8KFWxO3ToUKxduxZXrlwRi8crV67gypUrL3xeWYrdunXr4vvvv9eK/fjjj/Dy8kLXrl3h6uoKc3NzXL16Vbw7W3x8PJKTkxEYGAgACAwMRGRkJJRKpXi4/sqVK7C2toaPj0+pcyEiIiIi01CqYtfR0RFjxowRH1fEnF1ra2tUrlxZKyaTyWBvby/Gw8LCEBERATs7O9jY2GDNmjUIDAwUi92goCD4+Phg2bJl6NevH1JTU7Fx40a0b9++xCO3RERERGS6dLqpxCeffCIWmK9SeHg4JBIJFixYALVaLd5UooCZmRm++uorrFq1ClOmTIFMJkNISAh69er1ynMlIiIiIsOTCOWcCPHo0SMkJSUBANzc3ExqukBSUhJUKpWh0yD6T2vRIu/ljYheoRMnXu1J1ERUPKlUqr8T1Ipz9uxZREREIDExUSvu7u6O8PBwNGzYUNeuiYiIiIj0Qqdi98KFC1iwYAHc3NzQp08f8Wjuo0ePEBUVhe+//x5fffUVgoOD9ZkrEREREVGZ6FTsbtu2Db6+vpgxYwasrKzEeMOGDfHOO+9g6tSp2LJlC4tdIiIiIjKoUt0u+HkPHjxASEiIVqFbwMrKCqGhoXjw4EG5kyMiIiIiKg+dil2pVIqMjIwSl2dkZPBSX0RERERkcDoVu3Xq1MGePXuKvYPa7du3sXfvXtStW7fcyRERERERlYdOc3b79++PyZMn4+uvv0ZAQAC8vLwAPLujWWxsLBwdHdGvXz+9JkpEREREVFY6X2dXqVRi+/btuHTpktZ1duvXr4/33ntPvF3v64zX2SUyPF5nl4wNr7NLZBwq/Dq7jo6OGDRokK5PJyIiIiKqcDrN2SUiIiIieh2w2CUiIiIik8Vil4iIiIhMFotdIiIiIjJZLHaJiIiIyGSVudjNzc3FhAkTsG/fvorIh4iIiIhIb8pc7MpkMiQmJkIikVREPkREREREeqPTNIbg4GBcvnxZ37kQEREREemVTsVu9+7d8eTJEyxduhQ3b95ESkoKMjIyivwjIiIiIjIkne6g9vnnnwMAHj16hOPHj5fYbtOmTbplRURERESkBzoVu927d+ecXSIiIjIqS5cuxd69exEbGwsrKys0bNgQkyZNQkBAgNimR48e+Oeff7Se179/f8yfP7/EfhcsWIA//vgD8fHxsLS0RN26dTFhwgQ0aNAAwLOT98ePH499+/bBzc0Nc+fORevWrcXn//jjj3j8+DFmz56t5xFTaehU7Pbs2VPfeRARERGVy6lTpxAeHo7g4GCo1Wp888036Nu3Lw4fPgwbGxuxXb9+/TB+/HjxsbW19Qv79ff3x+zZs+Hr64ucnBz88ssv6Nu3L06cOAEXFxf8/vvvuHr1Knbu3IlDhw5h1KhRuHz5MiQSCR48eIDff/8de/furbBx04vpVOw+LysrC1ZWVjAz42V7iYiIyDB+//13rceLFi1CvXr1cOXKFTRt2lSMW1lZwd3dvdT9duvWTevxtGnTsGHDBkRHR6NVq1a4ffs22rVrh+rVq6Ny5cqYNWsWUlJS4OLigokTJ2Ly5Mmwt7cv3+BIZzpXp3fu3MGcOXPQv39/DBkyBNHR0QCAtLQ0fPvtt7h+/brekiQiIiIqq7S0NACAXC7Xim/fvh116tRBWFgY5s2bh+zs7FL3mZeXh99//x0ODg6oXbs2AKBWrVo4c+YMsrOzceTIEXh4eMDZ2RmRkZGQyWTo0KGD3sZEZafTkd1bt25h5syZcHZ2RqtWrXDw4EFxmYODA7KysrB//37xj4CIiIjoVdJoNJg2bRoaNWqEGjVqiPH33nsPPj4+8PDwwI0bNzBnzhzcuXMHq1atemF/+/fvx4gRI5CdnQ0PDw9s2LABzs7OAIDevXvjxo0baNOmDZydnfHTTz8hNTUV33//PbZs2YL58+dj586d8PX1xYIFC+Dp6VmhYydtOhW7GzZsgLe3N+bMmYPs7GytYhcAateujSNHjuglQSIiIqKymjRpEm7duoXt27drxfv37y/+f82aNeHu7o5evXohLi4Ofn5+JfbXokUL7Nu3DykpKVi/fj2GDx+OXbt2wdXVFVKpFHPnztVqP3bsWAwZMgTXr1/H33//jf3792PFihWYOnUqfvnlF72OlV5Mp2kMd+7cQWhoKKRSabFXZXB2dkZqamp5cyMiIiIqs8mTJ+PAgQPYsmULvLy8Xti24IoKcXFxL2xnY2ODKlWq4M0338SCBQtgbm6ODRs2FNv2xIkTiImJweDBg3Hy5EmEhYXBxsYGXbp0wcmTJ3UaE+lOpyO75ubmEAShxOUpKSmwsrLSOSkiIiKishIEAVOmTMFff/2FLVu2oHLlyi99TsE5RmU5Ya1gXXl5eUXiOTk5mDx5MpYtWwZzc3NoNBqoVCoAgEqlgkajKdN6qPx0OrJbrVo1nDp1qthlOTk5OHz4MGrVqlWuxIiIiIjKYtKkSYiMjMSyZctgZ2eHxMREJCYmiiegxcXF4YcffsCVK1fw8OFD7Nu3D2PGjEHTpk216pbWrVuLlwrLysrCvHnzcP78eTx69AhXrlzBuHHjkJCQgM6dOxfJYdGiRQgLC0OdOnUAAA0bNsTevXsRHR2NtWvXomHDhq9gS1BhOl9nd/r06Zg3bx5atGgB4Nkf0L///os///wTaWlp6N69u14TJSIiInqRiIgIAM9uHFHYwoUL0atXL0ilUhw/fhyrVq1CdnY2PD090bFjR4wZM0ar/Z07d8QrOZiZmeHOnTv46KOPkJKSAicnJwQFBSEyMhLVq1fXet7Nmzfx559/Yv/+/WKsc+fO+Oeff/D++++jatWqWLZsWUUMnV5AIrxoPsILXLt2Db/88gsSEhK04h4eHhg+fLhJHNlNSkoSf3ogIsNo0aLoz4REhnTihKWhUyAiAFKpFG5ubi9tp3OxW+DevXtISEiAIAjw8PCAv7+/ydxKmMUukeGx2CVjw2KXyDiUttgt9x3UqlSpgipVqpS3GyIiItIjflEkY2OoL4o6F7sqlQpRUVG4ePEiEhMTATw7k7F+/foICwuDpSW/+RIRERGRYelU7D59+hSzZ89GfHw85HI5KlWqBODZSWqXLl3CX3/9ha+//houLi56TZaIiIiIqCx0KnZXr16NpKQkjB07Fk2bNtVa9s8//2D58uVYvXo1vvzyS70kSURERESkC52K3atXr6JTp05FCl0AaNasGe7duyden46IiIiIyFB0Knatra3h6OhY4nK5XA5ra+sy97tv3z7s27cPSUlJAAAfHx/06NED9evXBwDk5eUhIiICJ0+ehEqlQlBQEIYOHQq5XC72kZycjF9++QXXr1+HlZUVQkJC0LdvX5ibm5c5HyIiIiJ6vel0B7XQ0FAcPnwYubm5RZbl5OTg0KFDCAsLK3O/zs7O6Nu3L7755hvMmzcPderUwbfffouHDx8CANatW4fz589j3LhxmDFjBhQKBRYsWCA+X6PRYN68eVCr1Zg9ezZGjhyJw4cPY9OmTboMk4iIiIhec6U6snv69Gmtx1WqVMHFixfx2WefISQkRDxBLSEhAUeOHIGdnV2p7kf9vOdvodenTx/s27cPt2/fhouLCw4ePIgxY8aIt+AbMWIExo4di5iYGAQGBuLy5ct49OgRvv76a8jlcvj5+aFXr174/fff0bNnT1hYlPtKa0RERET0GilV9bdw4cISl23fvr1ILCUlBYsXL0bz5s11Tkyj0eCff/5Bbm4uAgMDcffuXeTn56Nu3bpiG29vb7i6uorFbkxMDCpXrqw1rSE4OBirVq3Cw4cPS7wesEql0rp5hEQiEadhFNwgo/C9NwrfNEPX+PM33tBHXN85ckwck7GMiciYSCSS12J/IjJm+vh8Kq1SFbvTpk0rU6fl8eDBA0yePBkqlQpWVlYYP348fHx8EBcXBwsLC9ja2mq1d3R0RGpqKgAgNTVVq9AtWF6wrCTbt2/H1q1bxcdVqlTB/Pnz4eDgIG7Q3NxcZGZmwtbWFjKZTGybnZ2N7Oxs2NvbQyqVivHMzEzk5ubC0dFRa75weno6VCoV5HK51ounVCqh0Wjg5OSklZtCoYCZmZnWHGlBEKBQKCCVSmFvby/G8/PzoVQqIZPJtLaTSqVCeno6rK2tteZSc0wc0+sxJu1bkhMZmpOT02uxP3HfIWMjk8n0+vnk4OBQqvWWqtitVatWqTrTBy8vL3z33XfIysrCqVOnsHz5csyYMaNC19mtWzd07txZfFywodPS0qBWqwH8/7eIzMxMZGVliW0L4unp6cV+S1EqlcXGny++C+IKhaJIPD8/v0gcePbGVzheuDDPy8srEs/OzkZOTk6ROMfEMRn7mIiMiUKheC32JyJjU3Cul74+n9LS0l7N7YL1zcLCQpwD7O/vjzt37mDPnj1o3rw51Gq1+O21gFKpFI/myuVyxMbGavWnVCrFZSWRSqVaR8YKK+5QeUmHz8sS10cfxhY3plz0FTemXPQVN6ZcdIkTGVrhv01j2z+439DrQh+fT6Wlc7F78+ZNHDx4EImJicjMzCySiEQiwXfffVeu5IBnc3dVKhX8/f1hbm6Oq1evitf3jY+PR3JyMgIDAwEAgYGBiIyMhFKpFH8qunLlCqytreHj41PuXIiIiIjo9aJTsbtr1y789ttvsLS0hJeXF+zs7PSSzPr16xEcHAxXV1fk5OTg+PHjiI6OxuTJk2FjY4OwsDBERETAzs4ONjY2WLNmDQIDA8ViNygoCD4+Pli2bBn69euH1NRUbNy4Ee3bty/xyC0RERERmS6JoMOx4Y8++gienp6YMGECbGxs9JbMjz/+iGvXrkGhUMDGxga+vr7o2rUr6tWrB+D/bypx4sQJqNXqYm8qkZSUhFWrVuH69euQyWQICQlBv379dLqpRFJSktZVGojo1WvRIu/ljYheoRMnLA2dQqlw3yFjo+99RyqVlmrOrk7Fbnh4OPr374+3335bp+ReFyx2iQyPH9hkbFjsEunGUMWuTndQq127Nh48eKDLU4mIiIiIXhmdit0hQ4bg2rVr2LlzJzIyMvSdExERERGRXuh0gpqrqyvatm2L3377Db///jssLS1hZla0bl63bl25EyQiIiIi0pVOxe6mTZsQGRkJZ2dnVK1aVa8nqRERERER6YtOxe7+/fvRoEEDfPHFF8Ue0SUiIiIiMgY6VapqtRoNGjRgoUtERERERk2narVBgwa4ceOGvnMhIiIiItIrnYrdDz74AI8fP8aqVatw9+5dpKWlISMjo8g/IiIiIiJD0mnO7meffQYAiIuLw/79+0tst2nTJp2SIiIiIiLSB52K3e7du0Mikeg7FyIiIiIivdKp2O3Zs6e+8yAiIiIi0jteToGIiIiITJZOR3a3bt1aqnY9evTQpXsiIiIiIr3QqdjdsmVLqdqx2CUiIiIiQ9L5dsHP02g0SE5Oxl9//YUbN25g0qRJ5U6OiIiIiKg89DZn18zMDO7u7hg4cCA8PT2xZs0afXVNRERERKSTCjlBrWbNmrh48WJFdE1EREREVGoVUuzeuXOH1+ElIiIiIoPTac7ukSNHio1nZmbixo0bOHPmDMLCwsqVGBERERFReelU7K5YsaLEZfb29ujatSuvxEBEREREBqdTsbts2bIiMYlEAltbW1hbW5c7KSIiIiIifdCp2HVzc9N3HkREREREesfbBRMRERGRySr1kd3x48eXqWOJRILvvvuuzAkREREREelLqYtdOzu7Ul1OLDU1FfHx8eVKioiIiIhIH0pd7E6fPv2Fy1NTU7Fjxw7cvn0bZmZmaNWqVXlzIyIiIiIqF51OUCusoMiNioqCWq1Gq1at8P7776NSpUr6yI+IiIiISGc6F7vFFbndu3eHh4eHPvMjIiIiItJZmYvd54vc1q1bo3v37nB3d6+I/IiIiIiIdFbqYlehUIhFbn5+PkJCQvD++++zyCUiIiIio1XqYnf06NFQqVTw8/NDt27d4O7ujoyMDGRkZJT4HH9/f70kSURERESki1IXuyqVCgAQFxeHH374oVTP2bRpk25ZERERERHpQamL3U8++aQi8yAiIiIi0rtSF7uhoaEVmAYRERERkf6ZGToBIiIiIqKKwmKXiIiIiEwWi10iIiIiMlnlvl2wPm3fvh1nzpzB48ePYWlpicDAQPTv3x9eXl5im7y8PERERODkyZNQqVQICgrC0KFDIZfLxTbJycn45ZdfcP36dVhZWSEkJAR9+/aFubm5AUZFRERERIZiVEd2o6Oj0b59e8yZMwdTpkxBfn4+Zs+ejZycHLHNunXrcP78eYwbNw4zZsyAQqHAggULxOUajQbz5s2DWq3G7NmzMXLkSBw+fJiXQSMiIiL6DzKqYnfy5MkIDQ3FG2+8AT8/P4wcORLJycm4e/cuACArKwsHDx5EeHg46tSpA39/f4wYMQK3bt1CTEwMAODy5ct49OgRRo8eDT8/P9SvXx+9evXC33//DbVaXex6VSoVsrKyxH/Z2dniMolEAolEotW+IFaeeOGYvuL6zpFj4piMYUxExuZ13J+IjI0+9pvSMqppDM/LysoCANjZ2QEA7t69i/z8fNStW1ds4+3tDVdXV8TExCAwMBAxMTGoXLmy1rSG4OBgrFq1Cg8fPkSVKlWKrGf79u3YunWr+LhKlSqYP38+HBwcIAgCACA3NxeZmZmwtbWFTCYT22ZnZyM7Oxv29vaQSqViPDMzE7m5uXB0dNSaPpGeng6VSgW5XK71gimVSmg0Gjg5OWnlplAoYGZmBkdHRzEmCAIUCgWkUins7e3FeH5+PpRKJWQyGWxtbcW4SqVCeno6rK2tYW1tLcY5Jo7p9RhTAoiMiZOT02uxP3HfIWMjk8n0+vnk4OBQqvUabbGr0Wiwdu1aVK9eHZUrVwYApKamwsLCQmvnBwBHR0ekpqaKbQoXugXLC5YVp1u3bujcubP4uGBDp6WliUeDC4rezMxMsQgvHE9PT9d6gQriSqWy2PjzuRTEFQpFkXh+fn6ROPDsja9wvHBhnpeXVySenZ2tNSWEY+KYXpcxERkThULxWuxPRMYmNzcXgP4+n9LS0uDm5vbS9Rptsbt69Wo8fPgQM2fOrPB1SaVSrSNjhRVs6JfFyhrXRx/GFjemXPQVN6Zc9BU3plx0iRMZWuG/TWPbP7jf0OtCH59PpWVUc3YLrF69GhcuXMC0adPg4uIixuVyOdRqNTIzM7XaK5VK8WiuXC4v8s1AqVSKy4iIiIjov8Ooil1BELB69WqcOXMGU6dOhbu7u9Zyf39/mJub4+rVq2IsPj4eycnJCAwMBAAEBgbiwYMHYoELAFeuXIG1tTV8fHxezUCIiIiIyCgYVbG7evVqHDt2DGPGjIG1tTVSU1ORmpoqzlmysbFBWFgYIiIicO3aNdy9excrVqxAYGCgWOwGBQXBx8cHy5YtQ1xcHC5duoSNGzeiffv2JU5VoIp16tQphIeHo0GDBvD29sZff/2ltXzBggVo3bo1AgICUKtWLfTq1QsXLlwoV58A8NNPP6FevXqoV68efvrpJ61lFy5cwDvvvFPiFTqIiIjINBjVnN19+/YBAKZPn64VHzFiBEJDQwEA4eHhkEgkWLBgAdRqtXhTiQJmZmb46quvsGrVKkyZMgUymQwhISHo1avXqxoGPScrKwu1atVC7969tV6rAv7+/pg9ezZ8fX2Rk5ODX375BX379sWJEye0prGUpc/o6Gh89913WLduHQRBwKBBgxASEoKaNWtCrVbjq6++wrfffgsLC6PaBYiIiEjPjOqTfvPmzS9tY2lpiaFDhxZb4BRwc3PDxIkT9ZkalUNYWBjCwsJKXN6tWzetx9OmTcOGDRsQHR2NVq1a6dRnbGwsatasiZYtWwIAatasKcZ+/PFHNG3aFMHBwWUfDBEREb1WjKrYJcrLy8Pvv/8OBwcH1K5dW+d+atasiXv37uHx48cQBAF3795FjRo1EBcXh02bNhU77YGIiIhMD4tdMgr79+/HiBEjkJ2dDQ8PD2zYsAHOzs4691etWjVMmDABvXv3BgB89dVXqFatGnr16oUpU6bg8OHDWLhwISwsLDBz5kw0bdpUX0MhIiIiI8Jil4xCixYtsG/fPqSkpGD9+vUYPnw4du3aBVdXV537HDhwIAYOHCg+3rx5M+zs7PDmm2+idevW2L17N548eYIRI0bgn3/+ee7OQ0RERGQKjOpqDPTfZWNjgypVquDNN9/EggULYG5ujg0bNuit/5SUFPzwww+YNWsWLl68CH9/f/j7+6NFixZQqVS4e/eu3tZFRERExoPFLhklQRC0bpNZXtOmTcOwYcPg5eWF/Px8qFQqcVl+fj7y8/P1ti4iIiIyHpzGQBUuMzMT9+7dEx8/ePAA165dg5OTE5ycnLB48WK0a9cOHh4eSElJwdq1a5GQkIDOnTuLz+nZsyc6dOiAwYMHv7RPb29vrfUfPXoU9+7dw+LFiwE8uxbznTt3cPDgQcTHx8PMzAxVq1atyE1AREREBsJilyrc5cuX8cEHH4iPZ8yYAQD44IMP8M033+DOnTv46KOPkJKSAicnJwQFBSEyMhLVq1cXn3P//n2kpKSUqs9FixaJ8ezsbEyePBk//vgjzMye/ZDh5eWFWbNmYdy4cbC0tMSiRYtgbW1dIWMnIiIiw5IIgiAYOgljlZSUpPVzNxG9ei1a6G86C5E+nDhhaegUSoX7Dhkbfe87UqkUbm5uL23HObtEREREZLI4jeEV4TdsMkavyxEqIiIiXfHILhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyLAydQGHR0dHYuXMn7t27B4VCgfHjx6Nx48bickEQsHnzZkRFRSEzMxM1atTA0KFD4enpKbbJyMjAmjVrcP78eUgkEjRp0gSDBw+GlZWVIYZERERERAZkVEd2c3Nz4efnhw8//LDY5X/88Qf27t2LYcOGYe7cuZDJZJgzZw7y8vLENkuWLMHDhw8xZcoUfPXVV7hx4wZWrlz5qoZAREREREbEqIrd+vXro3fv3lpHcwsIgoA9e/bg/fffR6NGjeDr64tRo0ZBoVDg7NmzAIBHjx7h0qVLGD58OKpVq4YaNWpgyJAhOHnyJFJSUl71cIiIiIjIwIyq2H2RxMREpKamol69emLMxsYGAQEBiImJAQDExMTA1tYWVatWFdvUrVsXEokEsbGxJfatUqmQlZUl/svOzhaXSSQSSCQSrfYFsbLEiYxR4b/Nwn+/ZY0/36c+40TGRl/7zavcn4iMjT72m9Iyqjm7L5KamgoAcHR01Io7OjqKy1JTU+Hg4KC13NzcHHZ2dmKb4mzfvh1bt24VH1epUgXz58+Hg4MDBEEA8GyKRWZmJmxtbSGTycS22dnZyM7Ohr29PaRSqRjPzMxEbm4uHB0dYW5uDiBBh1ETVSwnJyco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\n"
468
- },
469
- "metadata": {}
470
- }
471
  ]
472
  },
473
  {
474
  "cell_type": "markdown",
475
- "source": [
476
- "Now that we understand our dataset and we have cleaned it, we need to save the cleaned dataset for future use."
477
- ],
478
  "metadata": {
479
  "id": "3vRxV6KQnNIR"
480
- }
 
 
 
481
  },
482
  {
483
  "cell_type": "code",
484
- "source": [
485
- "df_train.to_csv('datasets/cleaned_financial_phrasebank.csv', index=False)"
486
- ],
487
  "metadata": {
488
  "id": "YbIbJHKfjX-c"
489
  },
490
- "execution_count": 9,
491
- "outputs": []
 
 
492
  },
493
  {
494
  "cell_type": "markdown",
495
- "source": [
496
- "The following cell will only run if woring in colab."
497
- ],
498
  "metadata": {
499
  "id": "y6W5yvKS1yDA"
500
- }
 
 
 
501
  },
502
  {
503
  "cell_type": "code",
 
 
 
 
 
 
 
 
 
504
  "source": [
505
  "if IN_COLAB:\n",
506
  " REPO_NAME = 'finbert-sentiment-analyzer-api'\n",
@@ -530,37 +314,28 @@
530
  " print(f\" - Error moving Figure: {e}\")\n",
531
  "else:\n",
532
  " print('Cell skipped (Not running in Google Colab environment).')"
533
- ],
534
- "metadata": {
535
- "colab": {
536
- "base_uri": "https://localhost:8080/"
537
- },
538
- "id": "Hmctrq6KpQgY",
539
- "outputId": "112e118b-c63b-40dd-e891-513158a1aca7"
540
- },
541
- "execution_count": 10,
542
- "outputs": [
543
- {
544
- "output_type": "stream",
545
- "name": "stdout",
546
- "text": [
547
- " - CSV file successfully updated in repo.\n",
548
- " - Figure successfully updated in repo.\n"
549
- ]
550
- }
551
  ]
552
  },
553
  {
554
  "cell_type": "markdown",
555
- "source": [
556
- "### **Add new files to the repositoy**"
557
- ],
558
  "metadata": {
559
  "id": "KOtwYfds1fZv"
560
- }
 
 
 
561
  },
562
  {
563
  "cell_type": "code",
 
 
 
 
 
 
 
 
 
564
  "source": [
565
  "if IN_COLAB:\n",
566
  " print(\"Executing Git commands using explicit repository targeting...\")\n",
@@ -575,73 +350,42 @@
575
  " print(\"\\n✅ Done! Check your GitHub repository to see the updated files.\")\n",
576
  "else:\n",
577
  " print('Cell skipped (Not running in Google Colab environment).')"
578
- ],
579
- "metadata": {
580
- "colab": {
581
- "base_uri": "https://localhost:8080/"
582
- },
583
- "id": "vDT7YUz2s2jx",
584
- "outputId": "f11c3b69-3cd8-4c92-fbd9-14c61f29dcb1"
585
- },
586
- "execution_count": 11,
587
- "outputs": [
588
- {
589
- "output_type": "stream",
590
- "name": "stdout",
591
- "text": [
592
- "Executing Git commands using explicit repository targeting...\n",
593
- "On branch main\n",
594
- "Your branch is ahead of 'origin/main' by 1 commit.\n",
595
- " (use \"git push\" to publish your local commits)\n",
596
- "\n",
597
- "nothing to commit, working tree clean\n",
598
- "On branch main\n",
599
- "Your branch is ahead of 'origin/main' by 1 commit.\n",
600
- " (use \"git push\" to publish your local commits)\n",
601
- "\n",
602
- "nothing to commit, working tree clean\n",
603
- "remote: Enumerating objects: 11, done.\u001b[K\n",
604
- "remote: Counting objects: 100% (11/11), done.\u001b[K\n",
605
- "remote: Compressing objects: 100% (8/8), done.\u001b[K\n",
606
- "remote: Total 8 (delta 4), reused 0 (delta 0), pack-reused 0 (from 0)\u001b[K\n",
607
- "Unpacking objects: 100% (8/8), 2.46 KiB | 132.00 KiB/s, done.\n",
608
- "From https://github.com/mobadara/finbert-sentiment-analyzer-api\n",
609
- " * branch main -> FETCH_HEAD\n",
610
- " 3cadbf6..ed946f7 main -> origin/main\n",
611
- "\u001b[KSuccessfully rebased and updated refs/heads/main.\n",
612
- "Enumerating objects: 7, done.\n",
613
- "Counting objects: 100% (7/7), done.\n",
614
- "Delta compression using up to 2 threads\n",
615
- "Compressing objects: 100% (4/4), done.\n",
616
- "Writing objects: 100% (4/4), 6.12 KiB | 521.00 KiB/s, done.\n",
617
- "Total 4 (delta 2), reused 0 (delta 0), pack-reused 0\n",
618
- "remote: Resolving deltas: 100% (2/2), completed with 2 local objects.\u001b[K\n",
619
- "To https://github.com/mobadara/finbert-sentiment-analyzer-api.git\n",
620
- " ed946f7..ee223d3 main -> main\n",
621
- "\n",
622
- "✅ Done! Check your GitHub repository to see the updated files.\n"
623
- ]
624
- }
625
  ]
626
  },
627
  {
628
  "cell_type": "markdown",
 
 
 
629
  "source": [
630
  "___\n",
631
  "Muyiwa J. Obadara"
632
- ],
633
- "metadata": {
634
- "id": "xkHLyIZNBibU"
635
- }
636
  },
637
  {
638
  "cell_type": "code",
639
- "source": [],
640
  "metadata": {
641
  "id": "FaTADiWUBm0U"
642
  },
643
- "execution_count": 11,
644
- "outputs": []
645
  }
646
- ]
647
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  "cells": [
3
  {
4
  "cell_type": "markdown",
5
  "metadata": {
6
+ "colab_type": "text",
7
+ "id": "view-in-github"
8
  },
9
  "source": [
10
  "<a href=\"https://colab.research.google.com/github/mobadara/finbert-sentiment-analyzer-api/blob/main/notebooks/01_eda_and_data_engineering.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
 
12
  },
13
  {
14
  "cell_type": "markdown",
15
+ "metadata": {
16
+ "id": "175c_DpCsGNf"
17
+ },
18
  "source": [
19
  "# **FINANCIAL NEWS SENTIMENT ANALYSIS**\n",
20
  "## 📈 **EDA & Data Engineering**\n",
 
33
  "* **Source:** `financial_phrasebank` (via Hugging Face Datasets)\n",
34
  "* **Configuration:** `sentences_allagree` (Using only sentences where 100% of human annotators agreed on the sentiment)\n",
35
  "* **Labels:** 0 (Negative), 1 (Neutral), 2 (Positive)"
36
+ ]
 
 
 
37
  },
38
  {
39
  "cell_type": "markdown",
 
 
 
40
  "metadata": {
41
  "id": "Gt4uyJvPtv-s"
42
+ },
43
+ "source": [
44
+ "### **Setup**"
45
+ ]
46
  },
47
  {
48
  "cell_type": "code",
49
+ "execution_count": null,
50
  "metadata": {
51
  "id": "oHA_z_6krqFa"
52
  },
 
70
  },
71
  {
72
  "cell_type": "code",
73
+ "execution_count": null,
 
 
 
74
  "metadata": {
75
  "id": "EpCL1HxowTni"
76
  },
77
+ "outputs": [],
78
+ "source": [
79
+ "os.makedirs('figures', exist_ok=True)\n",
80
+ "os.makedirs('datasets', exist_ok=True)"
81
+ ]
82
  },
83
  {
84
  "cell_type": "code",
85
+ "execution_count": null,
 
 
86
  "metadata": {
87
  "id": "rLHOtOKrvMwg"
88
  },
89
+ "outputs": [],
90
+ "source": [
91
+ "dataset = load_dataset('FinanceMTEB/financial_phrasebank')"
92
+ ]
93
  },
94
  {
95
  "cell_type": "code",
96
+ "execution_count": null,
 
 
97
  "metadata": {
98
  "colab": {
99
  "base_uri": "https://localhost:8080/"
 
101
  "id": "BC7Xjb0IvRhf",
102
  "outputId": "bfe8f5b4-9a17-42b5-bb14-ac6ecd1cbd0f"
103
  },
104
+ "outputs": [],
105
+ "source": [
106
+ "dataset"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  ]
108
  },
109
  {
110
  "cell_type": "markdown",
111
+ "metadata": {
112
+ "id": "KkoS3g2KxDfk"
113
+ },
114
  "source": [
115
  "The dataset has two splits:\n",
116
  "1. Train Dataset contains 1264 instances.\n",
117
  "2. Test Dataset contains 1000 instances.\n",
118
  "\n",
119
  "We need to convert the train dataset to a pandas datafrome exploration."
120
+ ]
 
 
 
121
  },
122
  {
123
  "cell_type": "code",
124
+ "execution_count": null,
 
 
 
125
  "metadata": {
126
  "colab": {
127
  "base_uri": "https://localhost:8080/",
 
130
  "id": "Fd4_eL-PwUNw",
131
  "outputId": "2da09fc8-938d-4479-9460-da7cf774a1d4"
132
  },
133
+ "outputs": [],
134
+ "source": [
135
+ "df_train = dataset['train'].to_pandas()\n",
136
+ "df_train.head()"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  ]
138
  },
139
  {
140
  "cell_type": "markdown",
 
 
 
141
  "metadata": {
142
  "id": "8G472RswiiTH"
143
+ },
144
+ "source": [
145
+ "### **Data Check and Cleaning**"
146
+ ]
147
  },
148
  {
149
  "cell_type": "code",
150
+ "execution_count": null,
151
+ "metadata": {
152
+ "colab": {
153
+ "base_uri": "https://localhost:8080/"
154
+ },
155
+ "id": "rotrrtnxishA",
156
+ "outputId": "8c8a8437-5c03-43f8-9292-0fb453b3c594"
157
+ },
158
+ "outputs": [],
159
  "source": [
160
  "# Check for `null` values\n",
161
  "nulls_per_column = df_train.isna().sum()\n",
 
167
  "print(nulls_per_column)\n",
168
  "print(\"-\" * 30)\n",
169
  "print(f\"Number of Duplicated Instances: {duplicated_instances}\")"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
  ]
171
  },
172
  {
173
  "cell_type": "markdown",
174
+ "metadata": {
175
+ "id": "1T4BUAkbyjp0"
176
+ },
177
  "source": [
178
  "We see that our dataset (in tabular form) contains three columns: **text**, **label_text** and **label**.\n",
179
  "\n",
 
184
  "-----------|-----\n",
185
  "negative | `0`\n",
186
  "neutral | `1`\n",
187
+ "positive | `2`\n",
188
  "\n",
189
  "\n",
190
  "We see from our result that one instance in the dataset is exactly repeated. We drop the duplicated values in the following cell."
191
+ ]
 
 
 
192
  },
193
  {
194
  "cell_type": "code",
195
+ "execution_count": null,
 
 
 
196
  "metadata": {
197
  "id": "HWZSAfqTkgtU"
198
  },
199
+ "outputs": [],
200
+ "source": [
201
+ "df_train.drop_duplicates(inplace=True)\n",
202
+ "assert df_train.duplicated().sum() == 0"
203
+ ]
204
  },
205
  {
206
  "cell_type": "markdown",
 
 
 
207
  "metadata": {
208
  "id": "NzLiGGnnl2D2"
209
+ },
210
+ "source": [
211
+ "Now that the duplicated entries are removed, we need to visualize our class distribution."
212
+ ]
213
  },
214
  {
215
  "cell_type": "code",
216
+ "execution_count": null,
217
+ "metadata": {
218
+ "colab": {
219
+ "base_uri": "https://localhost:8080/",
220
+ "height": 492
221
+ },
222
+ "id": "FQs0xwBqyPP8",
223
+ "outputId": "0c838bcf-645b-4825-81d8-76ed1e442e3b"
224
+ },
225
+ "outputs": [],
226
  "source": [
227
  "plt.figure(figsize=(8, 5))\n",
228
  "ax = sns.countplot(data=df_train,\n",
 
243
  "\n",
244
  "plt.savefig('figures/class_distribution.png')\n",
245
  "plt.show()"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
246
  ]
247
  },
248
  {
249
  "cell_type": "markdown",
 
 
 
250
  "metadata": {
251
  "id": "3vRxV6KQnNIR"
252
+ },
253
+ "source": [
254
+ "Now that we understand our dataset and we have cleaned it, we need to save the cleaned dataset for future use."
255
+ ]
256
  },
257
  {
258
  "cell_type": "code",
259
+ "execution_count": null,
 
 
260
  "metadata": {
261
  "id": "YbIbJHKfjX-c"
262
  },
263
+ "outputs": [],
264
+ "source": [
265
+ "df_train.to_csv('datasets/cleaned_financial_phrasebank.csv', index=False)"
266
+ ]
267
  },
268
  {
269
  "cell_type": "markdown",
 
 
 
270
  "metadata": {
271
  "id": "y6W5yvKS1yDA"
272
+ },
273
+ "source": [
274
+ "The following cell will only run if woring in colab."
275
+ ]
276
  },
277
  {
278
  "cell_type": "code",
279
+ "execution_count": null,
280
+ "metadata": {
281
+ "colab": {
282
+ "base_uri": "https://localhost:8080/"
283
+ },
284
+ "id": "Hmctrq6KpQgY",
285
+ "outputId": "112e118b-c63b-40dd-e891-513158a1aca7"
286
+ },
287
+ "outputs": [],
288
  "source": [
289
  "if IN_COLAB:\n",
290
  " REPO_NAME = 'finbert-sentiment-analyzer-api'\n",
 
314
  " print(f\" - Error moving Figure: {e}\")\n",
315
  "else:\n",
316
  " print('Cell skipped (Not running in Google Colab environment).')"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
317
  ]
318
  },
319
  {
320
  "cell_type": "markdown",
 
 
 
321
  "metadata": {
322
  "id": "KOtwYfds1fZv"
323
+ },
324
+ "source": [
325
+ "### **Add new files to the repositoy**"
326
+ ]
327
  },
328
  {
329
  "cell_type": "code",
330
+ "execution_count": null,
331
+ "metadata": {
332
+ "colab": {
333
+ "base_uri": "https://localhost:8080/"
334
+ },
335
+ "id": "vDT7YUz2s2jx",
336
+ "outputId": "f11c3b69-3cd8-4c92-fbd9-14c61f29dcb1"
337
+ },
338
+ "outputs": [],
339
  "source": [
340
  "if IN_COLAB:\n",
341
  " print(\"Executing Git commands using explicit repository targeting...\")\n",
 
350
  " print(\"\\n✅ Done! Check your GitHub repository to see the updated files.\")\n",
351
  "else:\n",
352
  " print('Cell skipped (Not running in Google Colab environment).')"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
353
  ]
354
  },
355
  {
356
  "cell_type": "markdown",
357
+ "metadata": {
358
+ "id": "xkHLyIZNBibU"
359
+ },
360
  "source": [
361
  "___\n",
362
  "Muyiwa J. Obadara"
363
+ ]
 
 
 
364
  },
365
  {
366
  "cell_type": "code",
367
+ "execution_count": null,
368
  "metadata": {
369
  "id": "FaTADiWUBm0U"
370
  },
371
+ "outputs": [],
372
+ "source": []
373
  }
374
+ ],
375
+ "metadata": {
376
+ "colab": {
377
+ "authorship_tag": "ABX9TyN9T0T3HM5FCsd5NQ18TNLI",
378
+ "include_colab_link": true,
379
+ "provenance": []
380
+ },
381
+ "kernelspec": {
382
+ "display_name": "Python 3",
383
+ "name": "python3"
384
+ },
385
+ "language_info": {
386
+ "name": "python"
387
+ }
388
+ },
389
+ "nbformat": 4,
390
+ "nbformat_minor": 0
391
+ }
notebooks/02_fine_tuning.ipynb CHANGED
The diff for this file is too large to render. See raw diff
 
notebooks/eda_and_data_engineering.ipynb DELETED
@@ -1,462 +0,0 @@
1
- {
2
- "nbformat": 4,
3
- "nbformat_minor": 0,
4
- "metadata": {
5
- "colab": {
6
- "provenance": [],
7
- "authorship_tag": "ABX9TyPMJfuOSBpHVnJTEJsqSxBA",
8
- "include_colab_link": true
9
- },
10
- "kernelspec": {
11
- "name": "python3",
12
- "display_name": "Python 3"
13
- },
14
- "language_info": {
15
- "name": "python"
16
- }
17
- },
18
- "cells": [
19
- {
20
- "cell_type": "markdown",
21
- "metadata": {
22
- "id": "view-in-github",
23
- "colab_type": "text"
24
- },
25
- "source": [
26
- "<a href=\"https://colab.research.google.com/github/mobadara/finbert-sentiment-analyzer-api/blob/main/notebooks/eda_and_data_engineering.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
27
- ]
28
- },
29
- {
30
- "cell_type": "markdown",
31
- "source": [
32
- "# **FINANCIAL NEWS SENTIMENT ANALYSIS**\n",
33
- "## 📈 **EDA & Data Engineering**\n",
34
- "\n",
35
- "\n",
36
- "**Author:** [Muyiwa J. Obadara](https://portfolio-frontend-livid.vercel.app)\n",
37
- "\n",
38
- "**Project:** FinBERT Sentiment API Backend\n",
39
- "\n",
40
- "### **Objective**\n",
41
- "The goal of this notebook is to perform Exploratory Data Analysis (EDA) and preprocess the **[Financial PhraseBank](https://huggingface.co/datasets/FinanceMTEB/financial_phrasebank)** dataset. Financial text is highly specialized; words that represent positive sentiment in a general context might represent risk in a financial context.\n",
42
- "\n",
43
- "By analyzing the class distributions and cleaning the text, we will create a highly optimized dataset ready to fine-tune the `ProsusAI/finbert` model in the next phase of this pipeline.\n",
44
- "\n",
45
- "### **Dataset Details**\n",
46
- "* **Source:** `financial_phrasebank` (via Hugging Face Datasets)\n",
47
- "* **Configuration:** `sentences_allagree` (Using only sentences where 100% of human annotators agreed on the sentiment)\n",
48
- "* **Labels:** 0 (Negative), 1 (Neutral), 2 (Positive)"
49
- ],
50
- "metadata": {
51
- "id": "175c_DpCsGNf"
52
- }
53
- },
54
- {
55
- "cell_type": "markdown",
56
- "source": [
57
- "### **Setup**"
58
- ],
59
- "metadata": {
60
- "id": "Gt4uyJvPtv-s"
61
- }
62
- },
63
- {
64
- "cell_type": "code",
65
- "execution_count": 1,
66
- "metadata": {
67
- "id": "oHA_z_6krqFa"
68
- },
69
- "outputs": [],
70
- "source": [
71
- "from datasets import load_dataset\n",
72
- "import pandas as pd\n",
73
- "import matplotlib.pyplot as plt\n",
74
- "import seaborn as sns\n",
75
- "plt.style.use('ggplot')\n",
76
- "plt.rcParams['axes.prop_cycle'] = plt.cycler(color=['blue'])"
77
- ]
78
- },
79
- {
80
- "cell_type": "code",
81
- "source": [
82
- "dataset = load_dataset('FinanceMTEB/financial_phrasebank')"
83
- ],
84
- "metadata": {
85
- "id": "rLHOtOKrvMwg"
86
- },
87
- "execution_count": 2,
88
- "outputs": []
89
- },
90
- {
91
- "cell_type": "code",
92
- "source": [
93
- "dataset"
94
- ],
95
- "metadata": {
96
- "colab": {
97
- "base_uri": "https://localhost:8080/"
98
- },
99
- "id": "BC7Xjb0IvRhf",
100
- "outputId": "a72c0d4d-9e8b-422f-eb27-3b26608fd0ab"
101
- },
102
- "execution_count": 3,
103
- "outputs": [
104
- {
105
- "output_type": "execute_result",
106
- "data": {
107
- "text/plain": [
108
- "DatasetDict({\n",
109
- " train: Dataset({\n",
110
- " features: ['text', 'label_text', 'label'],\n",
111
- " num_rows: 1264\n",
112
- " })\n",
113
- " test: Dataset({\n",
114
- " features: ['text', 'label_text', 'label'],\n",
115
- " num_rows: 1000\n",
116
- " })\n",
117
- "})"
118
- ]
119
- },
120
- "metadata": {},
121
- "execution_count": 3
122
- }
123
- ]
124
- },
125
- {
126
- "cell_type": "markdown",
127
- "source": [
128
- "The dataset has two splits:\n",
129
- "1. Train Dataset contains 1264 instances.\n",
130
- "2. Test Dataset contains 1000 instances.\n",
131
- "\n",
132
- "We need to convert the train dataset to a pandas datafrome exploration."
133
- ],
134
- "metadata": {
135
- "id": "KkoS3g2KxDfk"
136
- }
137
- },
138
- {
139
- "cell_type": "code",
140
- "source": [
141
- "df_train = dataset['train'].to_pandas()\n",
142
- "df_train.head()"
143
- ],
144
- "metadata": {
145
- "colab": {
146
- "base_uri": "https://localhost:8080/",
147
- "height": 206
148
- },
149
- "id": "Fd4_eL-PwUNw",
150
- "outputId": "1b6f9fdc-d9fa-47bf-ef42-09a9952b7a09"
151
- },
152
- "execution_count": 4,
153
- "outputs": [
154
- {
155
- "output_type": "execute_result",
156
- "data": {
157
- "text/plain": [
158
- " text label_text label\n",
159
- "0 The Samsung Mobile Applications Store was laun... neutral 1\n",
160
- "1 F-Secure , a developer of security solutions a... neutral 1\n",
161
- "2 The company serves customers in various indust... neutral 1\n",
162
- "3 The company reported net sales of 302 mln euro... neutral 1\n",
163
- "4 Microsoft last week also issued the first patc... neutral 1"
164
- ],
165
- "text/html": [
166
- "\n",
167
- " <div id=\"df-499d12bd-abf1-4494-9c02-9cc3895cae4e\" class=\"colab-df-container\">\n",
168
- " <div>\n",
169
- "<style scoped>\n",
170
- " .dataframe tbody tr th:only-of-type {\n",
171
- " vertical-align: middle;\n",
172
- " }\n",
173
- "\n",
174
- " .dataframe tbody tr th {\n",
175
- " vertical-align: top;\n",
176
- " }\n",
177
- "\n",
178
- " .dataframe thead th {\n",
179
- " text-align: right;\n",
180
- " }\n",
181
- "</style>\n",
182
- "<table border=\"1\" class=\"dataframe\">\n",
183
- " <thead>\n",
184
- " <tr style=\"text-align: right;\">\n",
185
- " <th></th>\n",
186
- " <th>text</th>\n",
187
- " <th>label_text</th>\n",
188
- " <th>label</th>\n",
189
- " </tr>\n",
190
- " </thead>\n",
191
- " <tbody>\n",
192
- " <tr>\n",
193
- " <th>0</th>\n",
194
- " <td>The Samsung Mobile Applications Store was laun...</td>\n",
195
- " <td>neutral</td>\n",
196
- " <td>1</td>\n",
197
- " </tr>\n",
198
- " <tr>\n",
199
- " <th>1</th>\n",
200
- " <td>F-Secure , a developer of security solutions a...</td>\n",
201
- " <td>neutral</td>\n",
202
- " <td>1</td>\n",
203
- " </tr>\n",
204
- " <tr>\n",
205
- " <th>2</th>\n",
206
- " <td>The company serves customers in various indust...</td>\n",
207
- " <td>neutral</td>\n",
208
- " <td>1</td>\n",
209
- " </tr>\n",
210
- " <tr>\n",
211
- " <th>3</th>\n",
212
- " <td>The company reported net sales of 302 mln euro...</td>\n",
213
- " <td>neutral</td>\n",
214
- " <td>1</td>\n",
215
- " </tr>\n",
216
- " <tr>\n",
217
- " <th>4</th>\n",
218
- " <td>Microsoft last week also issued the first patc...</td>\n",
219
- " <td>neutral</td>\n",
220
- " <td>1</td>\n",
221
- " </tr>\n",
222
- " </tbody>\n",
223
- "</table>\n",
224
- "</div>\n",
225
- " <div class=\"colab-df-buttons\">\n",
226
- "\n",
227
- " <div class=\"colab-df-container\">\n",
228
- " <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-499d12bd-abf1-4494-9c02-9cc3895cae4e')\"\n",
229
- " title=\"Convert this dataframe to an interactive table.\"\n",
230
- " style=\"display:none;\">\n",
231
- "\n",
232
- " <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\">\n",
233
- " <path d=\"M120-120v-720h720v720H120Zm60-500h600v-160H180v160Zm220 220h160v-160H400v160Zm0 220h160v-160H400v160ZM180-400h160v-160H180v160Zm440 0h160v-160H620v160ZM180-180h160v-160H180v160Zm440 0h160v-160H620v160Z\"/>\n",
234
- " </svg>\n",
235
- " </button>\n",
236
- "\n",
237
- " <style>\n",
238
- " .colab-df-container {\n",
239
- " display:flex;\n",
240
- " gap: 12px;\n",
241
- " }\n",
242
- "\n",
243
- " .colab-df-convert {\n",
244
- " background-color: #E8F0FE;\n",
245
- " border: none;\n",
246
- " border-radius: 50%;\n",
247
- " cursor: pointer;\n",
248
- " display: none;\n",
249
- " fill: #1967D2;\n",
250
- " height: 32px;\n",
251
- " padding: 0 0 0 0;\n",
252
- " width: 32px;\n",
253
- " }\n",
254
- "\n",
255
- " .colab-df-convert:hover {\n",
256
- " background-color: #E2EBFA;\n",
257
- " box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
258
- " fill: #174EA6;\n",
259
- " }\n",
260
- "\n",
261
- " .colab-df-buttons div {\n",
262
- " margin-bottom: 4px;\n",
263
- " }\n",
264
- "\n",
265
- " [theme=dark] .colab-df-convert {\n",
266
- " background-color: #3B4455;\n",
267
- " fill: #D2E3FC;\n",
268
- " }\n",
269
- "\n",
270
- " [theme=dark] .colab-df-convert:hover {\n",
271
- " background-color: #434B5C;\n",
272
- " box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
273
- " filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
274
- " fill: #FFFFFF;\n",
275
- " }\n",
276
- " </style>\n",
277
- "\n",
278
- " <script>\n",
279
- " const buttonEl =\n",
280
- " document.querySelector('#df-499d12bd-abf1-4494-9c02-9cc3895cae4e button.colab-df-convert');\n",
281
- " buttonEl.style.display =\n",
282
- " google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
283
- "\n",
284
- " async function convertToInteractive(key) {\n",
285
- " const element = document.querySelector('#df-499d12bd-abf1-4494-9c02-9cc3895cae4e');\n",
286
- " const dataTable =\n",
287
- " await google.colab.kernel.invokeFunction('convertToInteractive',\n",
288
- " [key], {});\n",
289
- " if (!dataTable) return;\n",
290
- "\n",
291
- " const docLinkHtml = 'Like what you see? Visit the ' +\n",
292
- " '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n",
293
- " + ' to learn more about interactive tables.';\n",
294
- " element.innerHTML = '';\n",
295
- " dataTable['output_type'] = 'display_data';\n",
296
- " await google.colab.output.renderOutput(dataTable, element);\n",
297
- " const docLink = document.createElement('div');\n",
298
- " docLink.innerHTML = docLinkHtml;\n",
299
- " element.appendChild(docLink);\n",
300
- " }\n",
301
- " </script>\n",
302
- " </div>\n",
303
- "\n",
304
- "\n",
305
- " </div>\n",
306
- " </div>\n"
307
- ],
308
- "application/vnd.google.colaboratory.intrinsic+json": {
309
- "type": "dataframe",
310
- "variable_name": "df_train",
311
- "summary": "{\n \"name\": \"df_train\",\n \"rows\": 1264,\n \"fields\": [\n {\n \"column\": \"text\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 1263,\n \"samples\": [\n \"R&D Loan ) .\",\n \"Mr. Mikko Saavalainen , head of Comptel 's Global Sales concludes : `` Gibtelecom provides a perfect illustration of the variety of business , technical and regulatory challenges operators are facing in their OSS today .\",\n \"The decision reflects the underutilisation of the line , which produces nonwovens used in medical and wipes applications as well as for the automotive industry .\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"label_text\",\n \"properties\": {\n \"dtype\": \"category\",\n \"num_unique_values\": 3,\n \"samples\": [\n \"neutral\",\n \"positive\",\n \"negative\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"label\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": 0,\n \"max\": 2,\n \"num_unique_values\": 3,\n \"samples\": [\n 1,\n 2,\n 0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}"
312
- }
313
- },
314
- "metadata": {},
315
- "execution_count": 4
316
- }
317
- ]
318
- },
319
- {
320
- "cell_type": "markdown",
321
- "source": [
322
- "### **Data Check and Cleaning**"
323
- ],
324
- "metadata": {
325
- "id": "8G472RswiiTH"
326
- }
327
- },
328
- {
329
- "cell_type": "code",
330
- "source": [
331
- "# Check for `null` values\n",
332
- "nulls_per_column = df_train.isna().sum()\n",
333
- "\n",
334
- "# Check for duplicated values\n",
335
- "duplicated_instances = df_train.duplicated().sum()\n",
336
- "\n",
337
- "print(\"Null Values Per Column:\")\n",
338
- "print(nulls_per_column)\n",
339
- "print(\"-\" * 30)\n",
340
- "print(f\"Number of Duplicated Instances: {duplicated_instances}\")"
341
- ],
342
- "metadata": {
343
- "colab": {
344
- "base_uri": "https://localhost:8080/"
345
- },
346
- "id": "rotrrtnxishA",
347
- "outputId": "9a73f6eb-897e-4da7-ac1d-c6e02eec3678"
348
- },
349
- "execution_count": 5,
350
- "outputs": [
351
- {
352
- "output_type": "stream",
353
- "name": "stdout",
354
- "text": [
355
- "Null Values Per Column:\n",
356
- "text 0\n",
357
- "label_text 0\n",
358
- "label 0\n",
359
- "dtype: int64\n",
360
- "------------------------------\n",
361
- "Number of Duplicated Instances: 1\n"
362
- ]
363
- }
364
- ]
365
- },
366
- {
367
- "cell_type": "markdown",
368
- "source": [
369
- "We see that our dataset (in tabular form) contains three columns: **text**, **label_text** and **label**.\n",
370
- "\n",
371
- "The **`label_text`** has three unique represents the sentiments of each text in human redable form, which are **positive**, **negative** or **neutral**.\n",
372
- "\n",
373
- "Each of this is encoded in the `label` as follows:\n",
374
- "label_text | code\n",
375
- "-----------|-----\n",
376
- "negative | `0`\n",
377
- "neutral | `1`\n",
378
- "positive | `1`\n",
379
- "\n",
380
- "\n",
381
- "We see from our result that one instance in the dataset is exactly repeated. We drop the duplicated values in the following cell."
382
- ],
383
- "metadata": {
384
- "id": "1T4BUAkbyjp0"
385
- }
386
- },
387
- {
388
- "cell_type": "code",
389
- "source": [
390
- "df_train.drop_duplicates(inplace=True)\n",
391
- "assert df_train.duplicated().sum() == 0"
392
- ],
393
- "metadata": {
394
- "id": "HWZSAfqTkgtU"
395
- },
396
- "execution_count": 7,
397
- "outputs": []
398
- },
399
- {
400
- "cell_type": "markdown",
401
- "source": [
402
- "Now that the duplicated entries are removed, we need to visualize our class distribution."
403
- ],
404
- "metadata": {
405
- "id": "NzLiGGnnl2D2"
406
- }
407
- },
408
- {
409
- "cell_type": "code",
410
- "source": [
411
- "plt.figure(figsize=(8, 5))\n",
412
- "ax = sns.countplot(data=df_train,\n",
413
- " x='label_text',\n",
414
- " order=['negative', 'neutral', 'positive'])\n",
415
- "plt.title('Distribution of Sentiments in Financial PhraseBank', fontsize=14)\n",
416
- "plt.ylabel('Number of Sentences', fontsize=12)\n",
417
- "plt.xlabel('Sentiment', fontsize=12)\n",
418
- "plt.grid(axis='y', linestyle='--', alpha=0.7)\n",
419
- "\n",
420
- "# Add percentages on top of each bar\n",
421
- "total = len(df_train)\n",
422
- "for p in ax.patches:\n",
423
- " percentage = '{:.1f}%'.format(100 * p.get_height()/total)\n",
424
- " x = p.get_x() + p.get_width() / 2\n",
425
- " y = p.get_height()\n",
426
- " ax.annotate(percentage, (x, y), ha='center', va='bottom')\n",
427
- "\n",
428
- "plt.show()"
429
- ],
430
- "metadata": {
431
- "colab": {
432
- "base_uri": "https://localhost:8080/",
433
- "height": 492
434
- },
435
- "id": "FQs0xwBqyPP8",
436
- "outputId": "13afcab9-fbd1-4dbc-e632-3fecc2fae869"
437
- },
438
- "execution_count": 11,
439
- "outputs": [
440
- {
441
- "output_type": "display_data",
442
- "data": {
443
- "text/plain": [
444
- "<Figure size 800x500 with 1 Axes>"
445
- ],
446
- "image/png": "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1atXR8+ePfHbb79hx44dGD16dIlt4+Pj0bhxY2RmZqJTp07o1asXMjMzcfv2baxYsQLff/89LCwsMG3aNKxduxb379/HtGnTxOcHBwdr9RcbG4umTZuibt26GDRoEJ4+fVqqI44LFy5EVFQUevXqhU6dOuHAgQNYtGgRTp06haNHj0IqlZZ5O8jlckybNg2LFi0CAHz22WfispedXBATE4OWLVsiKSkJXbp0Qe3atXHt2jWsWbMGf/75J44fP47AwMAiz+vTpw/OnDmDDh06wNzcHJs3b8bIkSMhlUoxbNiwUuX96aefYunSpfD29saHH34IANi2bRsGDx6MixcvYvHixVpjeH58crn8hf0X/PQZExNTqnyAZ1Nl3nnnHRw+fBjBwcH48MMPoVKpsHv3bnTt2hVLly4t9uftL774AkeOHEHnzp3Rvn177NixA9OnT0deXh7mzJkDAHjvvfeQmpqKP/74A127di3yN/Uyp0+fxvz589G+fXt8/PHHOHToEH788UekpaWhS5cuGDRoELp27YpmzZph9+7d+O6772BnZ4epU6dq9TNx4kR888038Pb2xvvvvw9HR0ccO3YMX3zxBU6fPo0tW7YUWffOnTuxe/dudOnSBc2bN8fRo0cRERGBO3fu4Pjx4wCe7SNjxozB4sWLERQUhPfee098fsEXk/DwcGzevBn16tXD4MGDIZPJ8PDhQxw6dAhnz55FUFBQmbbJ80rzOrwKpd0/jh49igULFuCtt95CkyZNIJVKcfHiRfz444/4+++/ceHChWKnSpRlnJ9//jkWLlwIZ2dnvPfee3B3d8fDhw9x4MABvPnmm6hTp84LxzJy5EgEBQWhbdu2cHNzw+PHj7Fjxw60bdsWkZGR6Nq1q342WgmeP39CpVKhXbt2UCgU6N69O7KysrBx40b07NkTf/31F9q1a1ekj9GjR+PUqVPo1KkTunTpAnd3dwBl2/6CIKB9+/Y4ffo0WrRogXfeeQdmZma4f/8+du7ciQEDBsDX11ds269fP2zYsAHVqlVD3759YWlpif379+PDDz9EdHQ0vv/++1KN//79+7h16xZ8fHzEvAvo8tqcPXsW3377Ldq0aYOPP/4YFy9exI4dO3D16lVcu3YNVlZWJeaiUqkwaNAgrF+/Hp999hkWLlz4Wp7fYhACUTHu3bsnABDat2//wnarV68W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6NFDbNO1a1fk5uZi5cqVyMrKQo0aNTBp0iStN+hPP/0Uq1evxsyZMyGRPLupxJAhQwwxJCIinTRq1Ah37tzRit29exfe3t7l6rdhw4bYsWMHNBqN+Eva3bt34eHhUaTQBYDFixcjNDQUdevWxbVr15Cfny8uU6lU0Gg05cqHiKiiGdUJasYmKSlJ68Q1IqJX5dKlS+jatSs+//xzdOnSBZcuXcIXX3yBb7/9Fu+//z6AZ2ckP378GP/++y8GDhyIFStWoGrVqnB3d4e7uzuAZ1/+PT09xekQjx8/RlhYGD744AMMHjwY9+7dw+eff44hQ4ZgzJgxWjnExMRgyJAh2LdvH2xsbJCdnY1GjRph8uTJcHNzw0cffYQTJ05o3cGSiOhVKe0Jaix2X4DFLhEZ0v79+/HNN9/g3r17eOONN/DRRx+hX79+4vJNmzaJ82wLGzduHD7//HMAQI8ePeDj44NFixaJy8+dO4fp06cjOjoalSpVQu/evcWrMRQQBAHdunXDyJEj8fbbb2vlNHnyZOTl5eHLL79E3759K2DkREQvx2JXD1jsEhERERmn0ha7RnW7YCIiIiIifTKqE9SIiJ7XokWeoVMg0nLiRNET+YjIePHILhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJsvC0AkUNnLkSCQlJRWJt2vXDkOHDkVeXh4iIiJw8uRJqFQqBAUFYejQoZDL5WLb5ORk/PLLL7h+/TqsrKwQEhKCvn37wtzc/BWOhIiIiIiMgVEVu/PmzYNGoxEfP3jwALNnz0azZs0AAOvWrcOFCxcwbtw42NjYYPXq1ViwYAFmzZoFANBoNJg3bx7kcjlmz54NhUKBZcuWwdzcHH379jXImIiIiIjIcIxq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uxbznTt3cPDgQcTHx8PMzAxVq1atyE1AREREBsJilyrc5cuX8cEHH4iPZ8yYAQD44IMP8M033+DOnTv46KOPkJKSAicnJwQFBSEyMhLVq1cXn3P//n2kpKSUqs9FixaJ8ezsbEyePBk//vgjzMye/ZDh5eWFWbNmYdy4cbC0tMSiRYtgbW1dIWMnIiIiw5IIgiAYOgljlZSUpPVzNxG9ei1a6G86C5E+nDhhaegUSoX7Dhkbfe87UqkUbm5uL23HObtEREREZLI4jeEV4TdsMkavyxEqIiIiXfHILhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyLAydQGHR0dHYuXMn7t27B4VCgfHjx6Nx48bickEQsHnzZkRFRSEzMxM1atTA0KFD4enpKbbJyMjAmjVrcP78eUgkEjRp0gSDBw+GlZWVIYZERERERAZkVEd2c3Nz4efnhw8//LDY5X/88Qf27t2LYcOGYe7cuZDJZJgzZw7y8vLENkuWLMHDhw8xZcoUfPXVV7hx4wZWrlz5qoZAREREREbEqIrd+vXro3fv3lpHcwsIgoA9e/bg/fffR6NGjeDr64tRo0ZBoVDg7NmzAIBHjx7h0qVLGD58OKpVq4YaNWpgyJAhOHnyJFJSUl71cIiIiIjIwIyq2H2RxMREpKamol69emLMxsYGAQEBiImJAQDExMTA1tYWVatWFdvUrVsXEokEsbGxJfatUqmQlZUl/svOzhaXSSQSSCQSrfYFsbLEiYxR4b/Nwn+/ZY0/36c+40TGRl/7zavcn4iMjT72m9Iyqjm7L5KamgoAcHR01Io7OjqKy1JTU+Hg4KC13NzcHHZ2dmKb4mzfvh1bt24VH1epUgXz58+Hg4MDBEEA8GyKRWZmJmxtbSGTycS22dnZyM7Ohr29PaRSqRjPzMxEbm4uHB0dYW5uDiBBh1ETVSwnJyco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\n"
447
- },
448
- "metadata": {}
449
- }
450
- ]
451
- },
452
- {
453
- "cell_type": "code",
454
- "source": [],
455
- "metadata": {
456
- "id": "YbIbJHKfjX-c"
457
- },
458
- "execution_count": 8,
459
- "outputs": []
460
- }
461
- ]
462
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
requirements.txt CHANGED
@@ -1,9 +1,15 @@
1
- fastapi==0.110.0
2
- uvicorn==0.27.1
3
- pydantic==2.6.3
4
- transformers==4.38.1
5
- torch==2.2.1
6
- numpy==1.26.4
7
- pandas==2.2.1
8
- sqlalchemy==2.0.28
9
- psycopg2-binary==2.9.9
 
 
 
 
 
 
 
1
+ fastapi
2
+ uvicorn
3
+ pydantic
4
+ transformers
5
+ torch
6
+ numpy
7
+ pandas
8
+ sqlalchemy
9
+ psycopg2-binary
10
+ python-dotenv
11
+ huggingface-hub
12
+ evaluate
13
+ scikit-learn
14
+ ipykernel
15
+