From 5d0558f5577af3d8f67f5413c701b4d7cd6d65b9 Mon Sep 17 00:00:00 2001 From: Silviu Druma Date: Thu, 22 Jan 2026 07:18:05 -0500 Subject: [PATCH] feat: add opik setup --- apps/api/src/planproof_api/agent/planner.py | 2 ++ apps/api/src/planproof_api/config.py | 14 ++++++++++++++ apps/api/src/planproof_api/main.py | 15 +++++++++++++++ apps/api/src/planproof_api/observability/opik.py | 10 +++++++++- apps/api/src/planproof_api/routes.py | 16 ++++++++++++++++ 5 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 apps/api/src/planproof_api/config.py diff --git a/apps/api/src/planproof_api/agent/planner.py b/apps/api/src/planproof_api/agent/planner.py index 6cbc93d..9b726af 100644 --- a/apps/api/src/planproof_api/agent/planner.py +++ b/apps/api/src/planproof_api/agent/planner.py @@ -5,6 +5,7 @@ from openai import OpenAI from planproof_api.agent.schemas import ExtractedMetadata, PlanItem +from planproof_api.observability.opik import opik _SYSTEM_PROMPT = ( "You are a planning assistant. Return ONLY valid JSON with keys: " @@ -18,6 +19,7 @@ class PlanGenerationError(RuntimeError): pass +@opik.track(name="generate_plan") def generate_plan( context: str, metadata: ExtractedMetadata, diff --git a/apps/api/src/planproof_api/config.py b/apps/api/src/planproof_api/config.py new file mode 100644 index 0000000..df5ca9f --- /dev/null +++ b/apps/api/src/planproof_api/config.py @@ -0,0 +1,14 @@ +from __future__ import annotations + +from pydantic_settings import BaseSettings, SettingsConfigDict + + +class Settings(BaseSettings): + OPIK_API_KEY: str | None = None + OPIK_PROJECT_NAME: str = "Hackaton" + OPIK_WORKSPACE: str = "silviu-druma" + + model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8") + + +settings = Settings() diff --git a/apps/api/src/planproof_api/main.py b/apps/api/src/planproof_api/main.py index 333d45b..138414c 100644 --- a/apps/api/src/planproof_api/main.py +++ b/apps/api/src/planproof_api/main.py @@ -1,12 +1,27 @@ from __future__ import annotations from pathlib import Path +import sys from fastapi import FastAPI from fastapi.staticfiles import StaticFiles +from planproof_api.config import settings +from planproof_api.observability.opik import opik from planproof_api.routes import router +try: + opik.configure( + api_key=settings.OPIK_API_KEY, + workspace=settings.OPIK_WORKSPACE, + project_name=settings.OPIK_PROJECT_NAME, + ) + print( + f"OPIK INITIALIZED: {settings.OPIK_WORKSPACE}/{settings.OPIK_PROJECT_NAME}" + ) +except Exception as exc: + print(f"OPIK WARNING: Failed to initialize. ({exc})", file=sys.stderr) + app = FastAPI() app.include_router(router) diff --git a/apps/api/src/planproof_api/observability/opik.py b/apps/api/src/planproof_api/observability/opik.py index 5b93f04..1f73ab0 100644 --- a/apps/api/src/planproof_api/observability/opik.py +++ b/apps/api/src/planproof_api/observability/opik.py @@ -3,7 +3,7 @@ import sys if "OPIK_PROJECT_NAME" not in os.environ: - os.environ["OPIK_PROJECT_NAME"] = "PlanProof" + os.environ["OPIK_PROJECT_NAME"] = "Hackaton" def _warn(message: str) -> None: @@ -35,6 +35,14 @@ def decorator(func): return decorator + @staticmethod + def configure(*_args, **_kwargs) -> None: + return None + + @staticmethod + def get_current_trace_id() -> None: + return None + class _NoOpOpikContext: @staticmethod diff --git a/apps/api/src/planproof_api/routes.py b/apps/api/src/planproof_api/routes.py index be1530f..abf44f9 100644 --- a/apps/api/src/planproof_api/routes.py +++ b/apps/api/src/planproof_api/routes.py @@ -161,6 +161,9 @@ def create_plan(request: PlanRequest) -> PlanResponse: pass metadata = extract_metadata(request.context) + print( + f"DEBUG: Extractor produced {len(metadata.task_keywords)} keywords" + ) try: plan, assumptions, questions = _initial_planning_step(request, metadata) except PlanGenerationError as exc: @@ -190,6 +193,12 @@ def create_plan(request: PlanRequest) -> PlanResponse: ) validation = _validate_plan(plan, metadata, request.current_time) + print( + "DEBUG: Validation - Overlaps: " + f"{validation.metrics.overlap_minutes}, " + "Recall: " + f"{validation.metrics.keyword_recall_score}" + ) repair_attempted = False repair_success = False @@ -201,6 +210,12 @@ def create_plan(request: PlanRequest) -> PlanResponse: ) validation = _validate_plan(plan, metadata, request.current_time) repair_success = validation.status == "pass" + print( + "DEBUG: Validation (repair) - Overlaps: " + f"{validation.metrics.overlap_minutes}, " + "Recall: " + f"{validation.metrics.keyword_recall_score}" + ) except PlanGenerationError as exc: validation = PlanValidation( status="fail", @@ -213,6 +228,7 @@ def create_plan(request: PlanRequest) -> PlanResponse: ), errors=[str(exc)], ) + print(f"DEBUG: Trace ID: {opik.get_current_trace_id() or 'No Trace'}") return PlanResponse( plan=plan,