QuantumLearner commited on
Commit
4154fcf
·
verified ·
1 Parent(s): 38a97c9

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +74 -82
app.py CHANGED
@@ -1,7 +1,6 @@
1
  import os
2
  import nltk
3
  import requests
4
- import datetime
5
 
6
  # Use a directory within the user's home directory
7
  nltk_data_dir = os.path.expanduser("~/.nltk_data")
@@ -10,7 +9,6 @@ nltk.data.path.append(nltk_data_dir)
10
 
11
  # Download NLTK data
12
  nltk.download('punkt', download_dir=nltk_data_dir, quiet=True)
13
-
14
  import chainlit as cl
15
  from llama_index.core import VectorStoreIndex, Document
16
  from llama_index.embeddings.huggingface import HuggingFaceEmbedding
@@ -23,40 +21,45 @@ import pandas as pd
23
 
24
  load_dotenv()
25
 
26
- # We won't print your keys to avoid exposing them
27
  GROQ_API_KEY = os.getenv("GROQ_API_KEY")
28
  FMP_API_KEY = os.getenv("FMP_API_KEY")
29
 
 
30
  embed_model = HuggingFaceEmbedding(model_name="sentence-transformers/all-MiniLM-L6-v2")
31
  llm = Groq(model="llama3-70b-8192", api_key=GROQ_API_KEY)
32
 
 
33
  service_context = ServiceContext.from_defaults(
34
  llm=llm,
35
  embed_model=embed_model,
36
  node_parser=SentenceSplitter(chunk_size=1000, chunk_overlap=200)
37
  )
38
 
39
- def fetch_annual_report_10k(symbol: str) -> str:
40
  """
41
- Fetches the latest available 10-K filing from FMP's SEC Filings endpoint.
42
- Mirrors the approach in the working 'earnings transcript' code.
 
 
 
43
  """
44
- sec_url = (
45
- f"https://financialmodelingprep.com/api/v4/sec_filings"
46
- f"?symbol={symbol}&type=10-K&apikey={FMP_API_KEY}"
47
- )
48
  try:
49
- response = requests.get(sec_url, timeout=10)
50
  response.raise_for_status()
51
- filings_data = response.json()
52
-
53
- if not filings_data:
54
- return f"No 10-K data available for {symbol}."
55
-
56
- # Like your earnings code, pick the first record
57
- # Return it as a string for indexing
58
- first_filing = filings_data[0]
59
- return str(first_filing)
 
 
60
 
61
  except requests.exceptions.HTTPError as http_err:
62
  return f"HTTP error occurred: {http_err}"
@@ -65,84 +68,78 @@ def fetch_annual_report_10k(symbol: str) -> str:
65
  except Exception as err:
66
  return f"An unexpected error occurred: {err}"
67
 
68
- # Prompts remain unchanged
69
  summary_prompt = (
70
- "You are a world-class financial analyst with extensive experience analyzing annual reports. "
71
- "Provide a comprehensive summary of the 10-K report. Focus on Strategic Insights, Key Financial Figures, and Risk Factors. "
72
- "Answer in extensive bullet points, summarizing the company's performance, strengths, and weaknesses."
73
  )
74
 
75
  question_prompt = (
76
- "You are a financial analyst with extensive experience analyzing annual reports. "
77
- "Read the 10-K report and generate 10 strategic questions focusing on the company's performance, risks, and financial figures. "
78
- "Ask questions that provide strategic insights into the company's long-term goals, revenue trends, competitive position, and more. "
79
- "Format the questions as a numbered list (e.g., '1. Question')."
 
 
80
  )
81
 
82
  @cl.on_chat_start
83
  async def on_chat_start():
84
- # Ask the user for a ticker symbol
85
  ticker_response = await cl.AskUserMessage(
86
  content=(
87
- "This tool is designed to analyze 10-K annual reports for publicly traded companies. "
88
- "Provide the company's ticker symbol, and the tool will fetch the latest available 10-K report. "
89
- "It generates summaries and strategic due diligence. Ask your own questions afterwards.\n\n"
90
  "Please enter the ticker symbol for the company you want to analyze (e.g. MSFT):"
91
  )
92
  ).send()
93
 
94
- if not ticker_response or 'content' not in ticker_response:
95
- await cl.Message(content="No ticker symbol provided. Please enter a valid ticker symbol to proceed.").send()
96
- return
97
-
98
  ticker_symbol = ticker_response['content'].upper()
99
- msg = cl.Message(content=f"Retrieving the latest 10-K report for {ticker_symbol}...")
 
100
  await msg.send()
101
 
102
  try:
103
- # Fetch the 10-K, just like your working approach for earnings
104
- annual_report_text = fetch_annual_report_10k(ticker_symbol)
105
-
106
- # Check if there's an immediate error
107
- if annual_report_text.startswith("No 10-K data") or \
108
- annual_report_text.startswith("HTTP error") or \
109
- annual_report_text.startswith("Request error") or \
110
- annual_report_text.startswith("An unexpected error occurred"):
111
- await cl.Message(content=annual_report_text).send()
112
  return
113
 
114
- # Create a Document from the raw JSON/string
115
- document = Document(text=annual_report_text, metadata={"company": ticker_symbol})
116
 
117
- # Build the index
118
- index = VectorStoreIndex.from_documents([document], service_context=service_context)
 
 
119
 
120
- # Save index to user session
121
  cl.user_session.set("index", index)
122
 
123
- # Summaries
124
  query_engine = index.as_query_engine()
125
  summary_response = await cl.make_async(query_engine.query)(summary_prompt)
126
- summary_text = str(summary_response)
127
- await cl.Message(content=f"**Summary:**\n{summary_text}").send()
128
 
129
- # Generated questions
130
  questions_response = await cl.make_async(query_engine.query)(question_prompt)
131
- questions_text = str(questions_response)
132
- questions_format = questions_text.split('\n')
133
- relevant_questions = [
134
- question.strip() for question in questions_format
135
- if question.strip() and question.strip()[0].isdigit()
136
- ]
137
-
138
- await cl.Message(content="Generated strategic questions and answers:").send()
139
  for question in relevant_questions:
140
- await cl.Message(content=f"**{question}**").send()
141
- answer_obj = await cl.make_async(query_engine.query)(question)
142
- answer_text = str(answer_obj)
143
- await cl.Message(content=f"**Answer:**\n{answer_text}").send()
144
 
145
- msg.content = "Processing done. You can now ask more questions about the 10-K report!"
146
  await msg.update()
147
 
148
  except Exception as e:
@@ -151,22 +148,17 @@ async def on_chat_start():
151
  @cl.on_message
152
  async def main(message: cl.Message):
153
  index = cl.user_session.get("index")
 
154
  if index is None:
155
  await cl.Message(content="Please provide a ticker symbol first before asking questions.").send()
156
  return
157
 
158
  query_engine = index.as_query_engine()
159
- user_query = message.content
160
- try:
161
- raw_response = await cl.make_async(query_engine.query)(user_query)
162
- response_str = str(raw_response)
163
-
164
- # Stream the response token-by-token
165
- response_message = cl.Message(content="")
166
- for token in response_str:
167
- await response_message.stream_token(token=token)
168
-
169
- await response_message.send()
170
-
171
- except Exception as e:
172
- await cl.Message(content=f"Error while processing your question: {str(e)}").send()
 
1
  import os
2
  import nltk
3
  import requests
 
4
 
5
  # Use a directory within the user's home directory
6
  nltk_data_dir = os.path.expanduser("~/.nltk_data")
 
9
 
10
  # Download NLTK data
11
  nltk.download('punkt', download_dir=nltk_data_dir, quiet=True)
 
12
  import chainlit as cl
13
  from llama_index.core import VectorStoreIndex, Document
14
  from llama_index.embeddings.huggingface import HuggingFaceEmbedding
 
21
 
22
  load_dotenv()
23
 
24
+ # Fetch the API keys from environment variables
25
  GROQ_API_KEY = os.getenv("GROQ_API_KEY")
26
  FMP_API_KEY = os.getenv("FMP_API_KEY")
27
 
28
+ # Initialize models
29
  embed_model = HuggingFaceEmbedding(model_name="sentence-transformers/all-MiniLM-L6-v2")
30
  llm = Groq(model="llama3-70b-8192", api_key=GROQ_API_KEY)
31
 
32
+ # Create service context
33
  service_context = ServiceContext.from_defaults(
34
  llm=llm,
35
  embed_model=embed_model,
36
  node_parser=SentenceSplitter(chunk_size=1000, chunk_overlap=200)
37
  )
38
 
39
+ def fetch_earnings_transcript(symbol: str) -> str:
40
  """
41
+ Fetch the latest transcript for a company's earnings call.
42
+ Args:
43
+ - symbol (str): The stock ticker symbol (e.g., 'AAPL').
44
+ Returns:
45
+ - str: The earnings call transcript or an error message.
46
  """
47
+ transcript_url = f"https://financialmodelingprep.com/api/v3/earning_call_transcript/{symbol}?apikey={FMP_API_KEY}"
48
+
 
 
49
  try:
50
+ response = requests.get(transcript_url, timeout=10)
51
  response.raise_for_status()
52
+ transcript_data = response.json()
53
+
54
+ if not transcript_data:
55
+ return f"No transcript available for {symbol}."
56
+
57
+ # Extract the first available transcript
58
+ latest_transcript = transcript_data[0].get("content", "")
59
+ if not latest_transcript:
60
+ return f"No transcript content found for {symbol}."
61
+
62
+ return latest_transcript
63
 
64
  except requests.exceptions.HTTPError as http_err:
65
  return f"HTTP error occurred: {http_err}"
 
68
  except Exception as err:
69
  return f"An unexpected error occurred: {err}"
70
 
71
+ # Prompts
72
  summary_prompt = (
73
+ "You are a world-class financial analyst with extensive experience analyzing quarterly reports. "
74
+ "Give me a comprehensive summary of the earnings report. Focus on the Strategic Insights and Key Financial Figures. "
75
+ "Answer in extensive bullet points please."
76
  )
77
 
78
  question_prompt = (
79
+ "You are a financial analyst with extensive experience analyzing quarterly reports. "
80
+ "Read the earnings call transcript and earnings presentation report and generate 10 questions focusing on the strategic insights and financial figures. "
81
+ "Ask questions that require precise answers and provide strategic insight into the company's financial and strategic performance, such as revenue growth, market trends, profit margins, and more. "
82
+ "Only ask questions that can be answered using the provided document, without making any assumptions or inferences beyond the text. "
83
+ "Please format the questions as a list with a simple '1. Question 1', '2. Question 2', etc. structure. "
84
+ "Unless retrievable from the documents, don't ask questions which cannot be compared to previous periods."
85
  )
86
 
87
  @cl.on_chat_start
88
  async def on_chat_start():
 
89
  ticker_response = await cl.AskUserMessage(
90
  content=(
91
+ "This tool is designed to analyze earnings call transcripts for publicly traded companies. "
92
+ "Provide the company's ticker symbol, and the tool will fetch the latest earnings call transcript. "
93
+ "It generates summaries and strategic due diligence. Ask your own questions afterwards. \n\n"
94
  "Please enter the ticker symbol for the company you want to analyze (e.g. MSFT):"
95
  )
96
  ).send()
97
 
 
 
 
 
98
  ticker_symbol = ticker_response['content'].upper()
99
+
100
+ msg = cl.Message(content=f"Retrieving earnings call transcript for {ticker_symbol}...")
101
  await msg.send()
102
 
103
  try:
104
+ # Fetch the transcript using FMP API
105
+ transcript_text = fetch_earnings_transcript(ticker_symbol)
106
+
107
+ # Check if an error message was returned
108
+ if transcript_text.startswith("No transcript") or \
109
+ transcript_text.startswith("HTTP error") or \
110
+ transcript_text.startswith("Request error") or \
111
+ transcript_text.startswith("An unexpected error occurred"):
112
+ await cl.Message(content=transcript_text).send()
113
  return
114
 
115
+ # Create a Document object with the transcript text
116
+ document = Document(text=transcript_text, metadata={"company": ticker_symbol})
117
 
118
+ # Create index
119
+ index = VectorStoreIndex.from_documents(
120
+ [document], service_context=service_context
121
+ )
122
 
123
+ # Store the index in the user session
124
  cl.user_session.set("index", index)
125
 
126
+ # Generate summary
127
  query_engine = index.as_query_engine()
128
  summary_response = await cl.make_async(query_engine.query)(summary_prompt)
129
+ await cl.Message(content=f"**Summary:**\n{summary_response}").send()
 
130
 
131
+ # Generate questions
132
  questions_response = await cl.make_async(query_engine.query)(question_prompt)
133
+ questions_format = str(questions_response).split('\n')
134
+ relevant_questions = [question.strip() for question in questions_format if question.strip() and question.strip()[0].isdigit()]
135
+
136
+ # Answer generated questions
137
+ await cl.Message(content="Generated questions and answers:").send()
 
 
 
138
  for question in relevant_questions:
139
+ response = await cl.make_async(query_engine.query)(question)
140
+ await cl.Message(content=f"**{question}**\n{response}").send()
 
 
141
 
142
+ msg.content = "Processing done. You can now ask more questions about the earnings call transcript!"
143
  await msg.update()
144
 
145
  except Exception as e:
 
148
  @cl.on_message
149
  async def main(message: cl.Message):
150
  index = cl.user_session.get("index")
151
+
152
  if index is None:
153
  await cl.Message(content="Please provide a ticker symbol first before asking questions.").send()
154
  return
155
 
156
  query_engine = index.as_query_engine()
157
+
158
+ response = await cl.make_async(query_engine.query)(message.content)
159
+
160
+ response_message = cl.Message(content="")
161
+ for token in str(response):
162
+ await response_message.stream_token(token=token)
163
+
164
+ await response_message.send()