1- # API imports
21from fastapi import FastAPI , Request , Depends
3- import groq
4- import os
5- import dotenv
6- import datetime
7- import requests
8-
92from fastapi .middleware .cors import CORSMiddleware
10- from fastapi .responses import HTMLResponse
11- from fastapi .templating import Jinja2Templates
12- from fastapi_cache import FastAPICache
13- from fastapi_cache .backends .redis import RedisBackend
14- from contextlib import asynccontextmanager
15- import json
16- from redis import asyncio as aioredis
17- # Custom imports
18- from topStocks import get_top_stocks , get_stock
19- from ask import groq_chat
20- from stockNews import fetch_news
21- from agents import multi_ai
22- from agno .agent import RunResponse
23-
24- dotenv .load_dotenv ()
25- templates = Jinja2Templates (directory = "templates" )
26-
27- GROQ_API_KEY = os .getenv ("GROQ_API_KEY" )
28- groq_client = groq .Client (api_key = GROQ_API_KEY )
29-
30- if not GROQ_API_KEY :
31- raise ValueError ("Please provide a GROQ API key" )
32- REDIS_URL = os .getenv ("REDIS_URL" )
33-
34- @asynccontextmanager
35- async def lifespan (_ : FastAPI ):
36- redis_client = None
37-
38- try :
39- redis_client = aioredis .from_url (REDIS_URL , encoding = "utf-8" , decode_responses = True )
40- FastAPICache .init (RedisBackend (redis_client ), prefix = "fastapi-cache" )
41- print ("✅ Redis cache initialized successfully!" )
42- yield
43- except Exception as e :
44- print (f"❌ Redis Connection Error: { e } " )
45- yield
46- finally :
47- try :
48- await FastAPICache .clear ()
49- if redis_client :
50- await redis_client .close ()
51- print ("🔴 Redis connection closed!" )
52- except Exception as e :
53- print (f"❌ Error while closing Redis: { e } " )
54-
3+ from utils .redisCache import lifespan , get_cache
4+ from routes .stockRoutes import router as stock_router
5+ from routes .agentRoutes import router as agent_router
556
567app = FastAPI (lifespan = lifespan )
578app .add_middleware (
@@ -62,110 +13,8 @@ async def lifespan(_: FastAPI):
6213 allow_headers = ["*" ],
6314)
6415
65- @app .get ("/" )
66- @app .head ("/" )
67- async def read_root (request : Request ):
68- text = "Investo-glow Backend API Server"
69- return templates .TemplateResponse ("base.html" ,{"request" :request , "text" : text })
70-
71- def get_cache ():
72- return FastAPICache .get_backend ()
73-
74- @app .get ("/top-stocks" )
75- async def read_top_stocks (cache : RedisBackend = Depends (get_cache )):
76- cache_key = "top_stocks"
77- cached_result = await cache .get (cache_key )
78- if cached_result :
79- return json .loads (cached_result )
80-
81- top_stocks = ['AAPL' , 'MSFT' , 'AMZN' , 'GOOGL' ]
82- stocks = " " .join (top_stocks )
83- stocks_info = get_top_stocks (stocks )
84-
85- await cache .set (cache_key , json .dumps (stocks_info ), 10 )
86- return stocks_info
87-
88- @app .get ("/stock-news" )
89- async def stock_news (cache : RedisBackend = Depends (get_cache )):
90- cache_key = "stock_news"
91- cached_result = await cache .get (cache_key )
92- if cached_result :
93- return json .loads (cached_result )
94- news_stack = fetch_news ()
95- await cache .set (cache_key , json .dumps (news_stack ), 300 )
96- return news_stack
97-
98- @app .get ("/stocks/{name}" )
99- async def read_stock (name : str , cache : RedisBackend = Depends (get_cache )):
100- cache_key = "stock_{name}"
101- cached_result = await cache .get (cache_key )
102- if cached_result :
103- return json .loads (cached_result )
104- stock_info = get_stock (name )
105- await cache .set (cache_key , json .dumps (stock_info ), 10 )
106- return stock_info
107-
108-
109- @app .get ("health/" ) # Changed to GET since it's retrieving status
110- async def health_check ():
111- try :
112- return {
113- "status" : "healthy" ,
114- "timestamp" : datetime .datetime .now ().isoformat (),
115- "uptime" : "OK" ,
116- "api" : {
117- "groq_api" : "connected" if GROQ_API_KEY else "not configured" ,
118- },
119- "ip" : requests .get ('https://api.ipify.org' ).text ,
120- "services" : {
121- "top_stocks" : app .url_path_for ("read_top_stocks" ),
122- "chat" : app .url_path_for ("chat" ),
123- "agent" : app .url_path_for ("ask" ),
124- },
125- }
126-
127- except Exception as e :
128- return {
129- "status" : "unhealthy" ,
130- "timestamp" : datetime .datetime .now ().isoformat (),
131- "error" : str (e )
132- }
133-
134- @app .get ("/chat" )
135- def chat (query : str ):
136- """
137- API endpoint to handle user investment-related questions and return AI-generated insights.
138- """
139- if not query :
140- return {"error" : "Query parameter is required" }
141-
142- try :
143- response = groq_client .chat .completions .create (
144- model = "llama-3.3-70b-versatile" ,
145- messages = [{"role" : "system" , "content" : "You are an AI investment assistant." },
146- {"role" : "user" , "content" : query }]
147- )
148-
149- answer = response .choices [0 ].message .content
150- return {"question" : query , "answer" : answer }
151-
152- except Exception as e :
153- return {"error" : str (e )}
16+ app .include_router (stock_router )
17+ app .include_router (agent_router )
15418
15519
156- @app .get ("/agent" )
157- def ask (query : str ):
158- """
159- API endpoint to handle user investment-related questions and return AI-generated insights.
160- """
161- if not query :
162- return {"error" : "Query parameter is required" }
163-
164- try :
165- response : RunResponse = multi_ai .run (query )
166- answer = response .content
16720
168- return {"question" : query , "answer" : answer }
169-
170- except Exception as e :
171- return {"error" : str (e )}
0 commit comments