pheww again
Browse files- app.py +30 -22
- routes/api/__init__.py +0 -0
- routes/api/descriptive.py +12 -13
app.py
CHANGED
@@ -2,42 +2,50 @@
|
|
2 |
import os
|
3 |
import sys
|
4 |
from fastapi import FastAPI
|
|
|
|
|
5 |
|
6 |
-
# ---
|
7 |
-
# Assuming app.py is at the project root level.
|
8 |
# This ensures Python can find 'components' and 'routes' as packages.
|
9 |
sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
|
10 |
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "components")))
|
11 |
-
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "routes")))
|
12 |
-
# Add routes/api
|
13 |
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "routes", "api")))
|
14 |
|
15 |
# Import your routers
|
16 |
-
# These imports expect routes/api/ingest.py, routes/api/
|
17 |
from routes.api import ingest as ingest_router_module
|
18 |
-
from routes.api import
|
19 |
-
from routes.api import headlines as headlines_router_module
|
|
|
20 |
|
|
|
|
|
21 |
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
# daily_feed.py and detailed_explainer.py, so setting Settings.llm here is not strictly needed
|
28 |
-
# but also not harmful if it's just meant as a placeholder for a different use case.
|
29 |
-
# I will leave it commented out as per your original request, but be aware of its implications.
|
30 |
-
# Settings.llm = None
|
31 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
|
33 |
-
app = FastAPI()
|
34 |
|
35 |
@app.get("/")
|
36 |
def greet():
|
|
|
37 |
return {"welcome": "nuse ai"}
|
38 |
|
39 |
-
# Include your routers
|
40 |
-
|
41 |
-
app.include_router(
|
42 |
-
app.include_router(
|
43 |
-
app.include_router(headlines_router_module.router, prefix="/api/headlines")
|
|
|
2 |
import os
|
3 |
import sys
|
4 |
from fastapi import FastAPI
|
5 |
+
import logging
|
6 |
+
import redis # For optional top-level Redis connectivity check
|
7 |
|
8 |
+
# --- CRITICAL: Adjust sys.path to find your modules correctly ---
|
9 |
+
# Assuming 'app.py' is at the project root level.
|
10 |
# This ensures Python can find 'components' and 'routes' as packages.
|
11 |
sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
|
12 |
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "components")))
|
13 |
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "routes")))
|
14 |
+
# Add routes/api specifically, as you're importing directly from it
|
15 |
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "routes", "api")))
|
16 |
|
17 |
# Import your routers
|
18 |
+
# These imports expect routes/api/ingest.py, routes/api/descriptive.py, routes/api/headlines.py to exist
|
19 |
from routes.api import ingest as ingest_router_module
|
20 |
+
from routes.api import descriptive as descriptive_router_module
|
21 |
+
from routes.api import headlines as headlines_router_module
|
22 |
+
# query.py is ignored as per your instruction
|
23 |
|
24 |
+
# Configure basic logging for the application
|
25 |
+
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
26 |
|
27 |
+
app = FastAPI(
|
28 |
+
title="Nuse AI News Aggregator",
|
29 |
+
description="API for fetching, summarizing, and providing detailed explanations of news articles.",
|
30 |
+
version="1.0.0",
|
31 |
+
)
|
|
|
|
|
|
|
|
|
32 |
|
33 |
+
# Optional: App-level Redis client check
|
34 |
+
REDIS_URL = os.environ.get("UPSTASH_REDIS_URL", "redis://localhost:6379")
|
35 |
+
try:
|
36 |
+
_app_redis_client_test = redis.Redis.from_url(REDIS_URL, decode_responses=True)
|
37 |
+
_app_redis_client_test.ping()
|
38 |
+
logging.info("App-level Redis connection test successful.")
|
39 |
+
except Exception as e:
|
40 |
+
logging.critical(f"❌ FATAL ERROR: App-level Redis connection failed: {e}. Some functionalities may be impaired.")
|
41 |
|
|
|
42 |
|
43 |
@app.get("/")
|
44 |
def greet():
|
45 |
+
"""Root endpoint for the API."""
|
46 |
return {"welcome": "nuse ai"}
|
47 |
|
48 |
+
# Include your routers with specific prefixes and tags
|
49 |
+
app.include_router(ingest_router_module.router, prefix="/api/ingest", tags=["Data Ingestion & Summaries"])
|
50 |
+
app.include_router(descriptive_router_module.router, prefix="/api/descriptive", tags=["Detailed Explanations"])
|
51 |
+
app.include_router(headlines_router_module.router, prefix="/api/headlines", tags=["Headlines (Placeholder)"])
|
|
routes/api/__init__.py
ADDED
File without changes
|
routes/api/descriptive.py
CHANGED
@@ -1,14 +1,13 @@
|
|
1 |
-
# routes/api/
|
2 |
from fastapi import APIRouter, HTTPException, status
|
3 |
import logging
|
4 |
from typing import Dict, Any
|
5 |
|
6 |
# Import functions directly from the now standalone detailed_explainer
|
7 |
-
# Ensure sys.path in app.py allows these imports to components/generators
|
8 |
from components.generators.detailed_explainer import (
|
9 |
generate_detailed_feed,
|
10 |
-
cache_detailed_feed,
|
11 |
-
get_cached_detailed_feed
|
12 |
)
|
13 |
# We also need to get the initial summaries, which are managed by daily_feed.py
|
14 |
from components.generators.daily_feed import get_cached_daily_feed
|
@@ -24,10 +23,10 @@ async def generate_detailed_headlines_endpoint() -> Dict[str, Any]:
|
|
24 |
This step requires initial summaries to be present in Redis cache (from daily_feed.py).
|
25 |
The final detailed feed is then cached by this endpoint using its dedicated key.
|
26 |
"""
|
27 |
-
logging.info("API Call: POST /api/
|
28 |
try:
|
29 |
# Step 1: Retrieve the cached initial summaries
|
30 |
-
initial_summaries = get_cached_daily_feed() #
|
31 |
|
32 |
if not initial_summaries:
|
33 |
logging.warning("No initial summaries found in cache to generate detailed explanations from.")
|
@@ -49,16 +48,16 @@ async def generate_detailed_headlines_endpoint() -> Dict[str, Any]:
|
|
49 |
# This function (cache_detailed_feed) internally uses its own Redis client and DETAILED_FEED_CACHE_KEY
|
50 |
cache_detailed_feed(detailed_feed)
|
51 |
|
52 |
-
logging.info("API Call: POST /api/
|
53 |
|
54 |
total_items = sum(len(topic_summaries) for topic_summaries in detailed_feed.values())
|
55 |
|
56 |
return {"status": "success", "message": "Detailed headlines generated and cached.", "items": total_items}
|
57 |
|
58 |
except HTTPException as he:
|
59 |
-
raise he
|
60 |
except Exception as e:
|
61 |
-
logging.error(f"Error in /api/
|
62 |
raise HTTPException(
|
63 |
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
64 |
detail=f"An unexpected error occurred during detailed feed generation: {e}"
|
@@ -70,7 +69,7 @@ async def get_detailed_headlines_endpoint() -> Dict[str, Dict[int, Dict[str, Any
|
|
70 |
Retrieves the most recently cached *fully detailed* news feed.
|
71 |
Returns 404 if no detailed feed is found in cache.
|
72 |
"""
|
73 |
-
logging.info("API Call: GET /api/
|
74 |
try:
|
75 |
# Retrieve the cached detailed feed using the function from detailed_explainer
|
76 |
cached_detailed_feed = get_cached_detailed_feed()
|
@@ -79,16 +78,16 @@ async def get_detailed_headlines_endpoint() -> Dict[str, Dict[int, Dict[str, Any
|
|
79 |
logging.info("No full detailed news feed found in cache.")
|
80 |
raise HTTPException(
|
81 |
status_code=status.HTTP_404_NOT_FOUND,
|
82 |
-
detail="No detailed news feed found in cache. Please run /api/
|
83 |
)
|
84 |
|
85 |
-
logging.info("API Call: GET /api/
|
86 |
return cached_detailed_feed
|
87 |
|
88 |
except HTTPException as he:
|
89 |
raise he
|
90 |
except Exception as e:
|
91 |
-
logging.error(f"Error in /api/
|
92 |
raise HTTPException(
|
93 |
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
94 |
detail=f"An unexpected error occurred while retrieving cached detailed feed: {e}"
|
|
|
1 |
+
# routes/api/descriptive.py
|
2 |
from fastapi import APIRouter, HTTPException, status
|
3 |
import logging
|
4 |
from typing import Dict, Any
|
5 |
|
6 |
# Import functions directly from the now standalone detailed_explainer
|
|
|
7 |
from components.generators.detailed_explainer import (
|
8 |
generate_detailed_feed,
|
9 |
+
cache_detailed_feed, # Function to cache the detailed feed
|
10 |
+
get_cached_detailed_feed # Function to retrieve the detailed feed
|
11 |
)
|
12 |
# We also need to get the initial summaries, which are managed by daily_feed.py
|
13 |
from components.generators.daily_feed import get_cached_daily_feed
|
|
|
23 |
This step requires initial summaries to be present in Redis cache (from daily_feed.py).
|
24 |
The final detailed feed is then cached by this endpoint using its dedicated key.
|
25 |
"""
|
26 |
+
logging.info("API Call: POST /api/descriptive/generate-detailed initiated.")
|
27 |
try:
|
28 |
# Step 1: Retrieve the cached initial summaries
|
29 |
+
initial_summaries = get_cached_daily_feed() # From daily_feed.py
|
30 |
|
31 |
if not initial_summaries:
|
32 |
logging.warning("No initial summaries found in cache to generate detailed explanations from.")
|
|
|
48 |
# This function (cache_detailed_feed) internally uses its own Redis client and DETAILED_FEED_CACHE_KEY
|
49 |
cache_detailed_feed(detailed_feed)
|
50 |
|
51 |
+
logging.info("API Call: POST /api/descriptive/generate-detailed completed successfully.")
|
52 |
|
53 |
total_items = sum(len(topic_summaries) for topic_summaries in detailed_feed.values())
|
54 |
|
55 |
return {"status": "success", "message": "Detailed headlines generated and cached.", "items": total_items}
|
56 |
|
57 |
except HTTPException as he:
|
58 |
+
raise he
|
59 |
except Exception as e:
|
60 |
+
logging.error(f"Error in /api/descriptive/generate-detailed: {e}", exc_info=True)
|
61 |
raise HTTPException(
|
62 |
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
63 |
detail=f"An unexpected error occurred during detailed feed generation: {e}"
|
|
|
69 |
Retrieves the most recently cached *fully detailed* news feed.
|
70 |
Returns 404 if no detailed feed is found in cache.
|
71 |
"""
|
72 |
+
logging.info("API Call: GET /api/descriptive/get-detailed initiated.")
|
73 |
try:
|
74 |
# Retrieve the cached detailed feed using the function from detailed_explainer
|
75 |
cached_detailed_feed = get_cached_detailed_feed()
|
|
|
78 |
logging.info("No full detailed news feed found in cache.")
|
79 |
raise HTTPException(
|
80 |
status_code=status.HTTP_404_NOT_FOUND,
|
81 |
+
detail="No detailed news feed found in cache. Please run /api/descriptive/generate-detailed first."
|
82 |
)
|
83 |
|
84 |
+
logging.info("API Call: GET /api/descriptive/get-detailed completed successfully.")
|
85 |
return cached_detailed_feed
|
86 |
|
87 |
except HTTPException as he:
|
88 |
raise he
|
89 |
except Exception as e:
|
90 |
+
logging.error(f"Error in /api/descriptive/get-detailed: {e}", exc_info=True)
|
91 |
raise HTTPException(
|
92 |
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
93 |
detail=f"An unexpected error occurred while retrieving cached detailed feed: {e}"
|