diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..3fadbbc --- /dev/null +++ b/.dockerignore @@ -0,0 +1,9 @@ +.venv +node_modules +frontend/node_modules +data/ +logs/ +.git +__pycache__ +*.pyc +.env \ No newline at end of file diff --git a/docker/Dockerfile.backend b/docker/Dockerfile.backend new file mode 100644 index 0000000..74d0f59 --- /dev/null +++ b/docker/Dockerfile.backend @@ -0,0 +1,6 @@ +FROM python:3.11-slim +WORKDIR /app +COPY requirements.txt . +RUN pip install -r requirements.txt +COPY . . +CMD ["uvicorn", "src.api.main:app", "--host", "0.0.0.0", "--port", "8000"] \ No newline at end of file diff --git a/docker/Dockerfile.frontend b/docker/Dockerfile.frontend new file mode 100644 index 0000000..5a5807b --- /dev/null +++ b/docker/Dockerfile.frontend @@ -0,0 +1,10 @@ +FROM node:20-alpine AS build +WORKDIR /app +COPY frontend/package*.json ./ +RUN npm install +COPY frontend/ . +RUN npm run build + +FROM nginx:alpine +COPY --from=build /app/build /usr/share/nginx/html +EXPOSE 80 \ No newline at end of file diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index e69de29..14175ed 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -0,0 +1,30 @@ +services: + backend: + build: + context: .. + dockerfile: docker/Dockerfile.backend + ports: + - "8000:8000" + env_file: + - ../.env + environment: + - MLFLOW_TRACKING_URI=http://mlflow:5000 + depends_on: + - mlflow + + mlflow: + image: ghcr.io/mlflow/mlflow + ports: + - "5001:5000" + volumes: + - ../logs/mlflow:/mlflow + command: mlflow server --host 0.0.0.0 --port 5000 --allowed-hosts "mlflow,mlflow:5000,localhost:5001,127.0.0.1" --cors-allowed-origins "http://localhost:3000,http://localhost:8000,http://frontend:80" + + frontend: + build: + context: .. + dockerfile: docker/Dockerfile.frontend + ports: + - "3000:80" + depends_on: + - backend \ No newline at end of file diff --git a/src/agent/nodes.py b/src/agent/nodes.py index dd718d6..58bc25d 100644 --- a/src/agent/nodes.py +++ b/src/agent/nodes.py @@ -1,7 +1,6 @@ import numpy as np import torch from src.agent.state import AgentState -from src.retrieval.cache import get_cache, set_cache from src.retrieval.vector_store import add_abstracts, query_abstracts from src.retrieval.pubmed import search_pubmed from src.monitoring.mlflow_logger import log_query_run @@ -19,19 +18,6 @@ def extract_clean_text(response) -> str: return next((block["text"] for block in response.content if block.get("type") == "text"), "") return str(response.content) -def check_cache(state: AgentState): - cached_result = get_cache(state["query"]) - if cached_result: - return {"cache_hit": True, "abstracts": cached_result} - else: - return {"cache_hit": False} - -def route_after_cache(state: AgentState) -> str: - if state["cache_hit"]: - return "llm_generation" - return "pubmed_retrieval" - - def preprocess_query(state: AgentState): prompt = f"""You are an expert medical librarian. Convert the clinical question into a professional PubMed search string. @@ -48,17 +34,14 @@ def preprocess_query(state: AgentState): Search string:""" response = _search_llm.invoke(prompt) - print(response.content) search_query = response.content.strip().replace('"', '') # Clean quotes for API return {"search_query": search_query} def pubmed_retrieval(state: AgentState): - if not state["cache_hit"]: - results = search_pubmed(state["search_query"]) - add_abstracts(results) - abstracts = query_abstracts(state["query"]) - set_cache(state["query"], abstracts) - return {"abstracts": abstracts} + results = search_pubmed(state["search_query"]) + add_abstracts(results) + abstracts = query_abstracts(state["query"]) + return {"abstracts": abstracts} def llm_generation(state: AgentState): context = "\n\n".join([f"Title: {a['title']}\nAbstract: {a['abstract']}" diff --git a/src/agent/state.py b/src/agent/state.py index fbaa25b..df12b5c 100644 --- a/src/agent/state.py +++ b/src/agent/state.py @@ -2,7 +2,6 @@ class AgentState(TypedDict): query: str - cache_hit: bool search_query: Optional[str] abstracts: list[dict] llm_response: Optional[str] diff --git a/src/api/main.py b/src/api/main.py index 083c8ac..a459527 100644 --- a/src/api/main.py +++ b/src/api/main.py @@ -26,7 +26,6 @@ async def query(request: QueryRequest): result = agent.invoke({ "query": request.query, "search_query": None, - "cache_hit": False, "abstracts": [], "llm_response": None, "claims": None, diff --git a/src/retrieval/vector_store.py b/src/retrieval/vector_store.py index 67ca07c..1b07c7d 100644 --- a/src/retrieval/vector_store.py +++ b/src/retrieval/vector_store.py @@ -37,7 +37,7 @@ def add_abstracts(abstracts: list[dict]): if data_list: get_collection().upsert(vectors=data_list) -def query_abstracts(query: str, n_results: int = 5) -> list[dict]: +def query_abstracts(query: str, n_results: int = 3) -> list[dict]: embedding = _embed_text(query) results = get_collection().query( vector=embedding,