Ani-404 commited on
Commit
9f53bc3
·
1 Parent(s): 025d0f3

a lot of changes

Browse files
App/app.py CHANGED
@@ -12,19 +12,22 @@ import os
12
  import plotly.express as px
13
  import sys
14
 
 
 
15
  PROJECT_ROOT = r"C:\Users\anime\OneDrive\Desktop\Sentiment-Analysis-App"
 
16
  if PROJECT_ROOT not in sys.path:
17
  sys.path.insert(0, PROJECT_ROOT)
18
 
19
- # This brings in the logic from your new 'finance' directory
 
20
  from finance.processor import (
21
- ingest_transcripts,
22
- preprocess_and_split,
23
- get_sentiment_vectors,
24
- aggregate_vectors_to_features,
25
- get_stock_returns
26
  )
27
- from finance.analysis import run_prediction_model
 
28
 
29
  # Configuration and Model Loading
30
 
@@ -38,35 +41,28 @@ st.set_page_config(
38
 
39
  @st.cache_resource
40
  def load_models():
41
- """
42
- Loads both the general emotion model and the fine-tuned financial model.
43
- This function will be run only once.
44
- """
45
  models = {}
46
  try:
47
- # --- Determine Project Root Correctly ---
48
- # This handles running the script from 'App/' or the project's root directory
49
- app_dir = os.path.dirname(os.path.abspath(__file__))
50
- if os.path.basename(app_dir) == 'App':
51
- project_root = os.path.dirname(app_dir)
52
- else:
53
- project_root = app_dir
54
-
55
- # --- Load General Emotion Model (for the first tab) ---
56
- general_model_path = os.path.join(project_root, "Models", "sentiment_model_distilbert")
57
  st.info(f"Loading general model from: {general_model_path}")
58
  models['general_tokenizer'] = AutoTokenizer.from_pretrained(general_model_path)
59
  models['general_model'] = AutoModelForSequenceClassification.from_pretrained(general_model_path)
60
 
61
- # --- Load Fine-Tuned Financial Model (for the second tab) ---
62
- finbert_path = os.path.join(project_root, "finance", "finbert_emotion_model")
 
 
63
  st.info(f"Loading financial model from: {finbert_path}")
64
  if os.path.exists(finbert_path):
65
  models['finbert_tokenizer'] = AutoTokenizer.from_pretrained(finbert_path)
66
  models['finbert_model'] = AutoModelForSequenceClassification.from_pretrained(finbert_path)
67
  else:
68
- # Display a warning if the financial model hasn't been trained yet
69
- st.sidebar.warning("Fine-tuned FinBERT model not found. Please run `python finance/train_finbert.py` from your project root.")
70
  models['finbert_tokenizer'] = None
71
  models['finbert_model'] = None
72
 
@@ -74,7 +70,6 @@ def load_models():
74
  st.error(f"Error loading models: {e}")
75
  return None
76
  return models
77
-
78
  # Load all models at startup
79
  models = load_models()
80
 
@@ -156,7 +151,7 @@ def run_full_finance_pipeline():
156
  finbert_model = models['finbert_model']
157
  finbert_tokenizer = models['finbert_tokenizer']
158
 
159
- df_transcripts = ingest_transcripts()
160
  all_features = []
161
 
162
  for _, row in df_transcripts.iterrows():
@@ -238,4 +233,6 @@ def render_about_page():
238
  """)
239
 
240
  if __name__ == '__main__':
241
- main()
 
 
 
12
  import plotly.express as px
13
  import sys
14
 
15
+ print('Starting App...')
16
+
17
  PROJECT_ROOT = r"C:\Users\anime\OneDrive\Desktop\Sentiment-Analysis-App"
18
+ # This block adds your project folder to Python's search path so it can find 'finance'.
19
  if PROJECT_ROOT not in sys.path:
20
  sys.path.insert(0, PROJECT_ROOT)
21
 
22
+ # --- Import New Finance Modules ---
23
+ # This will now work correctly because of the path correction above.
24
  from finance.processor import (
25
+ get_huggingface_sentiment,
26
+ get_twitter_credentials,
27
+ get_twitter_data,
 
 
28
  )
29
+ from finance.modeling_analysis import run_prediction_model
30
+
31
 
32
  # Configuration and Model Loading
33
 
 
41
 
42
  @st.cache_resource
43
  def load_models():
44
+ """Loads both models using the hardcoded project root path."""
 
 
 
45
  models = {}
46
  try:
47
+ # --- Load General Emotion Model ---
48
+ # This path is for the "Emotion Analyzer" tab.
49
+ # It should point to your trained DistilBERT model.
50
+ general_model_path = os.path.join(PROJECT_ROOT, "Models", "sentiment_model_distilbert")
 
 
 
 
 
 
51
  st.info(f"Loading general model from: {general_model_path}")
52
  models['general_tokenizer'] = AutoTokenizer.from_pretrained(general_model_path)
53
  models['general_model'] = AutoModelForSequenceClassification.from_pretrained(general_model_path)
54
 
55
+ # --- Load Fine-Tuned Financial Model ---
56
+ # This path is for the "Financial Analysis" tab.
57
+ # It should point to your final, high-accuracy model (e.g., finbert_large_emotion_model).
58
+ finbert_path = os.path.join(PROJECT_ROOT, "finance", "finbert_large_emotion_model")
59
  st.info(f"Loading financial model from: {finbert_path}")
60
  if os.path.exists(finbert_path):
61
  models['finbert_tokenizer'] = AutoTokenizer.from_pretrained(finbert_path)
62
  models['finbert_model'] = AutoModelForSequenceClassification.from_pretrained(finbert_path)
63
  else:
64
+ # This warning will appear if the folder is not found
65
+ st.sidebar.warning("Fine-tuned FinBERT model not found. Please run the training script.")
66
  models['finbert_tokenizer'] = None
67
  models['finbert_model'] = None
68
 
 
70
  st.error(f"Error loading models: {e}")
71
  return None
72
  return models
 
73
  # Load all models at startup
74
  models = load_models()
75
 
 
151
  finbert_model = models['finbert_model']
152
  finbert_tokenizer = models['finbert_tokenizer']
153
 
154
+ df_transcripts = ingest_transcripts(PROJECT_ROOT)
155
  all_features = []
156
 
157
  for _, row in df_transcripts.iterrows():
 
233
  """)
234
 
235
  if __name__ == '__main__':
236
+ main()
237
+
238
+ print("App loaded successfully.")
finance/advanced_earnings.csv DELETED
@@ -1,4 +0,0 @@
1
- ticker,company_name,quarter,year,earnings_date,prepared_remarks,analyst_qa
2
- AAPL,Apple Inc.,4,2023,2023-10-26,"Good afternoon everyone. We are thrilled to report a September quarter revenue record. Our services division achieved an all-time revenue peak, and iPhone sales were the strongest we've ever seen for this quarter. Our active installed base continues to grow to new heights, which is a testament to our customer loyalty. We are confident in our product pipeline and see strong momentum heading into the holiday season. Our margins remain healthy despite some supply chain headwinds. Overall, we executed extremely well.","Analyst: Can you comment on the regulatory scrutiny in Europe? Tim Cook: We are actively engaged with regulators and are confident we comply with all laws. It's a complex issue, but we are focused on innovation. Analyst: What is the outlook for your China market given the recent slowdown? Tim Cook: We saw some softness, which we attribute to macroeconomic factors. However, we remain very optimistic about the long-term opportunity in China. We believe our products offer tremendous value."
3
- MSFT,Microsoft Corp.,1,2024,2023-10-24,"Thank you for joining. We are off to a tremendous start to the fiscal year. The Microsoft Cloud surpassed $31.8 billion in quarterly revenue, a fantastic achievement. Our AI initiatives, especially Copilot, are driving significant productivity gains for our customers and creating new revenue streams. We are rapidly infusing AI across every layer of the tech stack to lead this new era. Bookings were strong, and we feel we are well-positioned to continue our growth trajectory. Our commercial business is performing exceptionally well.","Analyst: How should we think about the margin impact from your AI investments? Amy Hood: There is an upfront investment cost, but we expect the efficiencies and new revenue will lead to margin expansion over time. It's a strategic investment in our future. Analyst: Is the PC market showing signs of recovery? Satya Nadella: The market is stabilizing. We see challenges, but also pockets of strength. We are focused on innovating in the PC space with AI-powered experiences."
4
- GOOGL,Alphabet Inc.,3,2023,2023-10-24,"Good afternoon. I am very pleased with our financial results this quarter. Revenues were strong, up 11% year over year, driven by excellent performance in Search and YouTube, along with continued momentum in our Cloud division. Our investments in AI are bearing fruit, and our new Gemini models are performing at the state-of-the-art. We are laser-focused on delivering value for our users and advertisers. The future is bright, and we are innovating at a rapid pace.","Analyst: Cloud growth seems to have decelerated slightly. Can you provide color? Ruth Porat: We are still seeing very strong customer adoption. The growth rate can fluctuate quarter to quarter based on deal timing, but we are confident in the underlying business momentum. There is some concern, but we are managing it. Analyst: What is the timeline for monetizing your generative AI products in Search? Sundar Pichai: We are taking a measured approach. We are testing various models and user experiences. It is a long-term journey, and we are being very deliberate to ensure we get it right for our users and partners."
 
 
 
 
 
finance/{modeling_analysis → modeling_analysis.py} RENAMED
File without changes
finance/processor.py CHANGED
@@ -7,74 +7,100 @@ import yfinance as yf
7
  from datetime import timedelta
8
  import numpy as np
9
  import torch
 
 
10
 
 
 
 
 
11
 
12
- def ingest_transcripts(file_path='finance/sample_transcripts_advanced.csv'):
13
- """Ingests earnings call transcripts from the advanced CSV file."""
14
- return pd.read_csv(file_path)
15
-
 
 
 
 
 
16
 
17
- def preprocess_and_split(transcript_text):
18
- """Splits raw text into clean, individual sentences."""
19
- if not isinstance(transcript_text, str):
20
  return []
21
- sentences = re.split(r'(?<=[.!?]) +', transcript_text)
22
- cleaned_sentences = [s.strip() for s in sentences if s.strip()]
23
- return cleaned_sentences
24
 
25
-
26
- def get_sentiment_vectors(sentences, model, tokenizer):
27
- """Runs FinBERT on sentences to get full emotion probability vectors."""
 
 
28
  if not sentences:
29
  return []
 
 
 
 
30
 
31
- vectors = []
32
- with torch.no_grad():
33
- for sentence in sentences:
34
- inputs = tokenizer(sentence, return_tensors="pt", padding=True, truncation=True, max_length=256)
35
- logits = model(**inputs).logits
36
- probabilities = torch.nn.functional.softmax(logits, dim=1).numpy()[0]
37
- vectors.append(probabilities)
38
- return vectors
39
-
40
-
41
- def aggregate_vectors_to_features(vectors, model, prefix=''):
42
- """Aggregates sentence vectors into call-level features."""
43
- if not vectors:
44
- # Returning a dictionary with zero values for all emotions if no vectors
45
- return {f"{prefix}{model.config.id2label[i]}_mean": 0 for i in range(model.config.num_labels)}
46
-
47
- vectors_np = np.array(vectors)
48
- # Calculating the mean probability for each emotion across all sentences
49
- mean_sentiments = np.mean(vectors_np, axis=0)
50
 
51
- # Creating a feature dictionary
52
- features = {f"{prefix}{model.config.id2label[i]}_mean": mean_sentiments[i] for i in range(len(mean_sentiments))}
53
- return features
54
 
55
-
56
- def get_stock_returns(ticker, earnings_date):
57
- """Fetches stock prices and calculates 1-day and 5-day returns."""
58
- earnings_date = pd.to_datetime(earnings_date)
59
- start_date = earnings_date - timedelta(days=1)
60
- end_date = earnings_date + timedelta(days=7)
61
 
62
- stock_data = yf.download(ticker, start=start_date, end=end_date, progress=False)
 
 
63
 
64
- if stock_data.empty: return None
 
 
 
 
65
 
 
 
 
 
66
  try:
67
- price_on_earnings_date = stock_data.loc[stock_data.index.date == earnings_date.date()]['Adj Close'].iloc[0]
68
- except IndexError:
69
- try:
70
- price_on_earnings_date = stock_data[stock_data.index > earnings_date]['Adj Close'].iloc[0]
71
- except IndexError: return None
 
 
 
72
 
73
- try:
74
- price_1_day_after = stock_data[stock_data.index > earnings_date]['Adj Close'].iloc[0]
75
- price_5_days_after = stock_data[stock_data.index > earnings_date]['Adj Close'].iloc[4]
 
76
 
77
- return_1d = (price_1_day_after - price_on_earnings_date) / price_on_earnings_date
78
- return_5d = (price_5_days_after - price_on_earnings_date) / price_on_earnings_date
79
- return {'return_1d': return_1d, 'return_5d': return_5d}
80
- except IndexError: return None
 
 
 
 
 
 
 
 
 
 
 
 
7
  from datetime import timedelta
8
  import numpy as np
9
  import torch
10
+ import os
11
+ from sklearn.feature_extraction.text import TfidfVectorizer
12
 
13
+ def get_sentiment_vectors(texts: list[str]) -> list[list[float]]:
14
+ """Return TF-IDF vectors for a list of texts."""
15
+ vectorizer = TfidfVectorizer(stop_words="english")
16
+ return vectorizer.fit_transform(texts).toarray()
17
 
18
+ def ingest_transcripts(project_root: str):
19
+ """
20
+ Ingests the NEW, simplified sample earnings call transcripts.
21
+ """
22
+ file_path = os.path.join(project_root, "finance", "sample_transcripts.csv")
23
+ try:
24
+ return pd.read_csv(file_path)
25
+ except FileNotFoundError:
26
+ raise FileNotFoundError(f"Could not find transcript data at '{file_path}'.")
27
 
28
+ def preprocess_and_split(text):
29
+ """Cleans and splits text into sentences."""
30
+ if not isinstance(text, str):
31
  return []
32
+ text = re.sub(r'\s+', ' ', text).strip()
33
+ sentences = re.split(r'(?<=[.!?])\s+', text)
34
+ return [s.strip() for s in sentences if s.strip()]
35
 
36
+ @torch.no_grad()
37
+ def get_sentiment_scores(sentences, model, tokenizer):
38
+ """
39
+ Runs the model on sentences and returns a simplified -1, 0, +1 score per sentence.
40
+ """
41
  if not sentences:
42
  return []
43
+
44
+ inputs = tokenizer(sentences, return_tensors="pt", padding=True, truncation=True, max_length=128)
45
+ outputs = model(**inputs)
46
+ predictions = torch.argmax(outputs.logits, dim=-1)
47
 
48
+ score_map = {
49
+ 'joy': 1, 'surprise': 1,
50
+ 'anger': -1, 'fear': -1, 'sadness': -1,
51
+ 'neutral': 0, 'shame': 0, 'disgust': 0
52
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
 
54
+ labels = [model.config.id2label[p.item()] for p in predictions]
55
+ scores = [score_map.get(label, 0) for label in labels]
56
+ return scores
57
 
58
+ def aggregate_sentiment_features(scores):
59
+ """Aggregates a list of scores into features like mean score and positive ratio."""
60
+ if not scores:
61
+ return {'mean_score': 0, 'positive_ratio': 0, 'negative_ratio': 0}
 
 
62
 
63
+ total_sentences = len(scores)
64
+ positive_sentences = sum(1 for s in scores if s > 0)
65
+ negative_sentences = sum(1 for s in scores if s < 0)
66
 
67
+ return {
68
+ 'mean_score': np.mean(scores),
69
+ 'positive_ratio': positive_sentences / total_sentences,
70
+ 'negative_ratio': negative_sentences / total_sentences
71
+ }
72
 
73
+ def get_stock_returns(ticker, earnings_date_str):
74
+ """
75
+ More robustly fetches stock prices and calculates 1-day and 5-day returns.
76
+ """
77
  try:
78
+ earnings_date = datetime.strptime(earnings_date_str, '%Y-%m-%d')
79
+ start_date = earnings_date - timedelta(days=1)
80
+ end_date = earnings_date + timedelta(days=10)
81
+
82
+ stock_data = yf.download(ticker, start=start_date, end=end_date, auto_adjust=True, progress=False)
83
+
84
+ if stock_data.empty:
85
+ return None
86
 
87
+ price_on_date_series = stock_data.loc[stock_data.index >= earnings_date]
88
+ if price_on_date_series.empty: return None
89
+ # --- KEY CHANGE: Use 'Close' instead of 'Adj Close' ---
90
+ price_on_date = price_on_date_series.iloc[0]['Close']
91
 
92
+ post_earnings_prices = stock_data.loc[stock_data.index > earnings_date]
93
+ if len(post_earnings_prices) < 5: return None
94
+
95
+ # --- KEY CHANGE: Use 'Close' instead of 'Adj Close' ---
96
+ price_1d_after = post_earnings_prices.iloc[0]['Close']
97
+ price_5d_after = post_earnings_prices.iloc[4]['Close']
98
+ # --- END OF CHANGE ---
99
+
100
+ return {
101
+ 'return_1d': (price_1d_after - price_on_date) / price_on_date,
102
+ 'return_5d': (price_5d_after - price_on_date) / price_on_date
103
+ }
104
+ except Exception:
105
+ return None
106
+
finance/sample_transcripts_advanced.csv ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ company_name,ticker,earnings_date,transcript
2
+ "Apple Inc.","AAPL","2024-05-02","Good afternoon, everyone. We are thrilled to report another record-breaking quarter. Our iPhone sales continue to show incredible strength, and we are seeing fantastic momentum in our services division. The macro-economic environment presents some headwinds, but we are confident in our product pipeline. We are managing our supply chain effectively despite some challenges. The future looks very bright, and we are excited about the innovations we have in store. We believe we are well-positioned for strong growth ahead."
3
+ "Microsoft Corp.","MSFT","2024-04-25","Thank you for joining us. This quarter's results demonstrate the strength of our cloud offerings. Azure's growth has accelerated, and we are seeing strong demand for our AI-powered services. We are navigating a complex global market, which has created some areas of softness, particularly in the PC market. However, our commercial bookings remain very strong. We are investing heavily in the future, and we see a long runway for growth. We are concerned about the regulatory landscape, but we are prepared to adapt."
4
+ "NVIDIA Corp.","NVDA","2024-05-22","We have had a phenomenal quarter, driven by the unprecedented demand for our AI and data center platforms. The computational needs of the world are growing exponentially, and we are at the center of this transformation. We are facing some supply constraints, which is our biggest challenge. We are working tirelessly to increase our capacity. The gaming market has shown some weakness, but the data center segment is more than compensating for it. We are extremely optimistic about our future."