Skip to content

Commit 05dbc09

Browse files
authored
Merge branch 'main' into 68-genai-enhance-course-generation-api-confirmation-chat-and-crawling
2 parents 869f1cb + 9c67a51 commit 05dbc09

File tree

8 files changed

+622
-145
lines changed

8 files changed

+622
-145
lines changed

genai/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,7 @@ genai-devops25-env/
2020

2121
# Misc
2222
*.log
23+
24+
# Scheduler cache
25+
scheduler_cache.json
26+
src/services/scheduler/scheduler_cache.json

genai/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ langchain
99
langchain-openai
1010
langchain_community
1111
tiktoken
12+
pydantic

genai/src/main.py

Lines changed: 75 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@
2525
from .utils.error_schema import ErrorResponse
2626
from .utils.handle_httpx_exception import handle_httpx_exception
2727

28+
from .services.scheduler.schemas import SchedulerStatus, SchedulerControl
29+
from .services.scheduler import start_scheduler, stop_scheduler, get_scheduler_status
30+
31+
2832

2933
# --- Configuration ---
3034
load_dotenv()
@@ -44,27 +48,37 @@
4448
{"name": "Crawler", "description": "Crawl and clean website content."},
4549
{"name": "Embedder", "description": "Chunk and embed text to vector DB."},
4650
{"name": "LLM", "description": "Language Model completions and chat."},
51+
{"name": "Scheduler", "description": "Scheduled background jobs and automation."},
4752
]
4853

4954
# -------------------------------
5055
# --- Lifespan Manager (for startup) ---
5156
# -------------------------------
5257
@asynccontextmanager
5358
async def lifespan(app: FastAPI):
54-
logger.info("Service starting up...")
55-
try:
56-
# Example: Create client connections here
57-
client = get_weaviate_client()
58-
logger.info("Testing Weaviate connection...")
59-
test_weaviate_connection()
60-
logger.info("Ensuring Weaviate schema exists...")
61-
ensure_schema_exists(client)
62-
logger.info("Everything is set up successfully and ready to go!")
63-
except Exception as e:
64-
logger.error(f"Error during startup: {e}", exc_info=True)
65-
raise RuntimeError("Failed during application startup.") from e
66-
yield
67-
logger.info("Service shutting down...")
59+
logger.info("Service starting up...")
60+
try:
61+
# Example: Create client connections here
62+
client = get_weaviate_client()
63+
logger.info("Testing Weaviate connection...")
64+
test_weaviate_connection()
65+
logger.info("Ensuring Weaviate schema exists...")
66+
ensure_schema_exists(client)
67+
logger.info("Everything is set up successfully and ready to go!")
68+
69+
# Start the blog embedder scheduler
70+
logger.info("Starting blog embedder scheduler...")
71+
start_scheduler()
72+
73+
except Exception as e:
74+
logger.error(f"Error during startup: {e}", exc_info=True)
75+
raise RuntimeError("Failed during application startup.") from e
76+
yield
77+
logger.info("Service shutting down...")
78+
79+
# Stop the scheduler on shutdown
80+
logger.info("Stopping blog embedder scheduler...")
81+
stop_scheduler()
6882

6983
# --- App Initialization ---
7084
app = FastAPI(
@@ -263,6 +277,53 @@ async def generate_course(req: CourseGenerationRequest):
263277
except Exception as e:
264278
raise HTTPException(500, str(e)) from e
265279

280+
# -------------------------------
281+
# --- Scheduler Endpoints -------
282+
# -------------------------------
283+
@app.get(f"{API_PREFIX}/scheduler/status", response_model=SchedulerStatus, tags=["Scheduler"])
284+
async def get_scheduler_status_endpoint():
285+
"""Get the current status of the blog embedder scheduler"""
286+
return SchedulerStatus(**get_scheduler_status())
287+
288+
289+
@app.post(f"{API_PREFIX}/scheduler/control", tags=["Scheduler"])
290+
async def control_scheduler(request: SchedulerControl):
291+
"""Control the blog embedder scheduler (start/stop)"""
292+
if request.action == "start":
293+
start_scheduler()
294+
return {"message": "Scheduler started successfully"}
295+
elif request.action == "stop":
296+
stop_scheduler()
297+
return {"message": "Scheduler stopped successfully"}
298+
else:
299+
raise HTTPException(status_code=400, detail="Invalid action. Use 'start' or 'stop'")
300+
301+
302+
@app.post(f"{API_PREFIX}/scheduler/run-now", tags=["Scheduler"])
303+
async def run_scheduler_now():
304+
"""Manually trigger the blog embedder job immediately"""
305+
try:
306+
# Import here to avoid circular imports
307+
from .services.scheduler.scheduler_service import _scheduler
308+
309+
# Run the job in a separate thread to avoid blocking
310+
import threading
311+
def run_job():
312+
import asyncio
313+
async def async_job():
314+
urls = await _scheduler.fetch_freecodecamp_articles()
315+
await _scheduler.embed_articles(urls)
316+
asyncio.run(async_job())
317+
318+
thread = threading.Thread(target=run_job, daemon=True)
319+
thread.start()
320+
321+
return {"message": "Blog embedder job triggered successfully"}
322+
except Exception as e:
323+
logger.error(f"Error triggering scheduler job: {e}")
324+
raise HTTPException(status_code=500, detail=f"Failed to trigger job: {str(e)}")
325+
326+
266327

267328
# -------------------------------
268329
# --------- MAIN ----------------

0 commit comments

Comments
 (0)