QuantumLearner commited on
Commit
d081699
·
verified ·
1 Parent(s): 63ecac2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +49 -60
app.py CHANGED
@@ -23,7 +23,6 @@ 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
 
@@ -38,34 +37,39 @@ service_context = ServiceContext.from_defaults(
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}"
63
- except requests.exceptions.RequestException as req_err:
64
- return f"Request error occurred: {req_err}"
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. "
@@ -81,12 +85,12 @@ question_prompt = (
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()
@@ -100,47 +104,38 @@ async def on_chat_start():
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()
@@ -151,22 +146,16 @@ 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()
 
23
 
24
  load_dotenv()
25
 
 
26
  GROQ_API_KEY = os.getenv("GROQ_API_KEY")
27
  FMP_API_KEY = os.getenv("FMP_API_KEY")
28
 
 
37
 
38
  def fetch_annual_report_10k(symbol: str) -> str:
39
  """
40
+ Tries up to 5 years (current year backward) to find a 10-K.
41
+ Returns the raw text of the first successful result.
42
  """
43
+ current_year = datetime.datetime.now().year
44
+
45
+ # We'll attempt up to 5 years back
46
+ for year_try in range(current_year, current_year - 5, -1):
47
+ url = (
48
+ "https://financialmodelingprep.com/api/v4/financial-reports-json"
49
+ f"?symbol={symbol}&year={year_try}&period=FY&apikey={FMP_API_KEY}"
50
+ )
51
+ try:
52
+ response = requests.get(url, timeout=10)
53
+ response.raise_for_status()
54
+ text_data = response.text
55
+
56
+ # If FMP returns an error message inside the JSON, skip and try the next year
57
+ if "Error Message" in text_data or len(text_data.strip()) < 10:
58
+ continue
59
+
60
+ # If we got meaningful data, return it immediately
61
+ return text_data
62
+
63
+ except requests.exceptions.RequestException:
64
+ # On request error or no data, try older year
65
+ pass
66
+
67
+ # If we exit the loop, no data was found for any year in that range
68
+ return (
69
+ f"No 10-K data found for {symbol} in the last 5 years "
70
+ "(or API returned an error)."
71
  )
72
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  summary_prompt = (
74
  "You are a world-class financial analyst with extensive experience analyzing annual reports. "
75
  "Provide a comprehensive summary of the 10-K report. Focus on Strategic Insights, Key Financial Figures, and Risk Factors. "
 
85
 
86
  @cl.on_chat_start
87
  async def on_chat_start():
 
88
  ticker_response = await cl.AskUserMessage(
89
  content=(
90
  "This tool is designed to analyze 10-K annual reports for publicly traded companies. "
91
+ "Provide the company's ticker symbol, and the tool will fetch the latest available 10-K report "
92
+ "from the last few years. It generates summaries and strategic due diligence. "
93
+ "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()
 
104
  await msg.send()
105
 
106
  try:
 
107
  annual_report_text = fetch_annual_report_10k(ticker_symbol)
108
 
109
+ # Check if we failed for all years
110
+ if annual_report_text.startswith("No 10-K data found") or \
111
  annual_report_text.startswith("HTTP error") or \
112
  annual_report_text.startswith("Request error") or \
113
  annual_report_text.startswith("An unexpected error occurred"):
114
  await cl.Message(content=annual_report_text).send()
115
  return
116
 
 
117
  document = Document(text=annual_report_text, metadata={"company": ticker_symbol})
 
 
118
  index = VectorStoreIndex.from_documents([document], service_context=service_context)
119
 
 
120
  cl.user_session.set("index", index)
 
 
121
  query_engine = index.as_query_engine()
122
+
123
  summary_response = await cl.make_async(query_engine.query)(summary_prompt)
124
+ await cl.Message(content=f"**Summary:**\n{summary_response}").send()
 
125
 
 
126
  questions_response = await cl.make_async(query_engine.query)(question_prompt)
127
+ questions_format = str(questions_response).split('\n')
 
128
  relevant_questions = [
129
+ question.strip()
130
+ for question in questions_format
131
  if question.strip() and question.strip()[0].isdigit()
132
  ]
133
 
134
  await cl.Message(content="Generated strategic questions and answers:").send()
135
  for question in relevant_questions:
136
  await cl.Message(content=f"**{question}**").send()
137
+ answer = await cl.make_async(query_engine.query)(question)
138
+ await cl.Message(content=f"**Answer:**\n{answer}").send()
 
139
 
140
  msg.content = "Processing done. You can now ask more questions about the 10-K report!"
141
  await msg.update()
 
146
  @cl.on_message
147
  async def main(message: cl.Message):
148
  index = cl.user_session.get("index")
149
+
150
  if index is None:
151
  await cl.Message(content="Please provide a ticker symbol first before asking questions.").send()
152
  return
153
 
154
  query_engine = index.as_query_engine()
155
+ response = await cl.make_async(query_engine.query)(message.content)
 
 
 
156
 
157
+ response_message = cl.Message(content="")
158
+ for token in str(response):
159
+ await response_message.stream_token(token=token)
 
160
 
161
+ await response_message.send()