Walukagga Patrick commited on
Commit
5848a2e
·
2 Parent(s): 7b9cfed 87b05cb

Merge pull request #1 from SunbirdAI/api

Browse files
.dockerignore ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ **/.git
2
+ **/.gitignore
3
+ **/.vscode
4
+ **/coverage
5
+ **/.aws
6
+ **/.ssh
7
+ **/.terraform
8
+ Dockerfile
9
+ README.md
10
+ docker-compose.yml
11
+ **/.DS_Store
12
+ **/venv
13
+ **/env
.env.example ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxx
2
+ HF_TOKEN_PATRICK=hf_xxxxxxxxxxxxxxxxx
3
+ ZOTERO_LIBRARY_ID=1120xxxx
4
+ ZOTERO_API_ACCESS_KEY=Ky5RGxxxxxxxxxxxxxxxxxx
5
+ GRADIO_URL_=http://gradio:7860/
6
+
.flake8 ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ [flake8]
2
+ ignore = D203, E402, F403, F405, W503, W605
3
+ exclude = .git,env,__pycache__,docs/source/conf.py,old,build,dist, *migrations*,env,venv,alembic
4
+ max-complexity = 10
5
+ max-line-length = 119
.gitignore CHANGED
@@ -173,5 +173,9 @@ poetry.toml
173
  pyrightconfig.json
174
 
175
  # data
176
- # data/
177
  study_export_*
 
 
 
 
 
173
  pyrightconfig.json
174
 
175
  # data
176
+ data/
177
  study_export_*
178
+ study_files.db
179
+ study_files.json
180
+
181
+ infra/ecs_config.toml
.isort.cfg ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ [settings]
2
+ multi_line_output=3
3
+ include_trailing_comma=True
4
+ force_grid_wrap=0
5
+ use_parentheses=True
6
+ line_length=88
7
+ skip=env,migrations,alembic,venv
Dockerfile.api ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # FastAPI Dockerfile
2
+ FROM python:3.11.10-slim
3
+
4
+ ENV PYTHONUNBUFFERED=1
5
+ ENV OMP_NUM_THREADS=1
6
+
7
+ # Set working directory
8
+ WORKDIR /app
9
+
10
+ # Copy app files
11
+ COPY requirements.txt ./
12
+ RUN pip install --no-cache-dir -r requirements.txt
13
+ COPY . .
14
+
15
+ # Expose port
16
+ EXPOSE 8000
17
+
18
+ # Command to run the FastAPI app
19
+ CMD ["uvicorn", "api:app", "--host", "0.0.0.0", "--port", "8000"]
Dockerfile.api.prod ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ###########
2
+ # BUILDER #
3
+ ###########
4
+
5
+ ARG AWS_ACCOUNT_ID
6
+
7
+ # pull official base image
8
+ FROM ${AWS_ACCOUNT_ID}.dkr.ecr.us-east-1.amazonaws.com/gradio-python:3.11.10-slim as builder
9
+
10
+ # set work directory
11
+ WORKDIR /app
12
+
13
+ # set environment variables
14
+ ENV PYTHONDONTWRITEBYTECODE 1
15
+ ENV PYTHONUNBUFFERED 1
16
+ ENV OMP_NUM_THREADS=1
17
+
18
+
19
+ # install dependencies
20
+ RUN apt-get update \
21
+ && apt-get -y install libpq-dev gcc \
22
+ && pip install psycopg
23
+
24
+ RUN pip install --upgrade pip
25
+ COPY ./requirements.txt /app/requirements.txt
26
+ RUN pip wheel --no-cache-dir --no-deps --wheel-dir /app/wheels -r requirements.txt
27
+
28
+ #########
29
+ # FINAL #
30
+ #########
31
+
32
+ ARG AWS_ACCOUNT_ID
33
+
34
+ # pull official base image
35
+ FROM ${AWS_ACCOUNT_ID}.dkr.ecr.us-east-1.amazonaws.com/gradio-python:3.11.10-slim
36
+
37
+ # create directory for the app user
38
+ RUN mkdir -p /home/backend-app
39
+
40
+ # create the app user
41
+ RUN addgroup --system app && adduser --system --group app
42
+
43
+ # create the appropriate directories
44
+ ENV HOME=/home/app
45
+ ENV BACKEND_APP_HOME=/home/app
46
+ # RUN mkdir $BACKEND_APP_HOME
47
+ WORKDIR $BACKEND_APP_HOME
48
+
49
+ # install dependencies
50
+ RUN apt-get update \
51
+ && apt-get -y install libpq-dev gcc \
52
+ && pip install psycopg
53
+
54
+ COPY --from=builder /app/wheels /wheels
55
+ COPY --from=builder /app/requirements.txt .
56
+ RUN pip install --upgrade pip
57
+ RUN pip install --no-cache /wheels/*
58
+
59
+ # copy project
60
+ COPY . $BACKEND_APP_HOME
61
+
62
+ # chown all the files to the app user
63
+ RUN chown -R app:app $BACKEND_APP_HOME
64
+
65
+ # change to the app user
66
+ USER app
67
+
68
+ ## Expose port
69
+ EXPOSE 8000
70
+
71
+ # Command to run the FastAPI app
72
+ CMD ["uvicorn", "api:app", "--host", "0.0.0.0", "--port", "8000"]
Dockerfile.gradio ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Gradio Dockerfile
2
+ FROM python:3.11.10-slim
3
+
4
+ ENV PYTHONUNBUFFERED=1
5
+ ENV OMP_NUM_THREADS=1
6
+
7
+ # Set working directory
8
+ WORKDIR /app
9
+
10
+ # Copy app files
11
+ COPY requirements.txt ./
12
+ RUN pip install --no-cache-dir -r requirements.txt
13
+ COPY . .
14
+
15
+ # Expose port
16
+ EXPOSE 7860
17
+ ENV GRADIO_SERVER_NAME="0.0.0.0"
18
+
19
+ # Command to run the Gradio app
20
+ CMD ["gradio", "app.py"]
21
+ # CMD ["python", "app.py"]
Dockerfile.gradio.prod ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ###########
2
+ # BUILDER #
3
+ ###########
4
+
5
+ # pull official base image
6
+ FROM 224427659724.dkr.ecr.us-east-1.amazonaws.com/gradio-python:3.11.10-slim as builder
7
+
8
+ # set work directory
9
+ WORKDIR /app
10
+
11
+ # set environment variables
12
+ ENV PYTHONDONTWRITEBYTECODE 1
13
+ ENV PYTHONUNBUFFERED 1
14
+ ENV OMP_NUM_THREADS=1
15
+
16
+
17
+ # install dependencies
18
+ RUN apt-get update \
19
+ && apt-get -y install libpq-dev gcc \
20
+ && pip install psycopg
21
+
22
+ RUN pip install --upgrade pip
23
+ COPY ./requirements.txt /app/requirements.txt
24
+ RUN pip wheel --no-cache-dir --no-deps --wheel-dir /app/wheels -r requirements.txt
25
+
26
+ #########
27
+ # FINAL #
28
+ #########
29
+
30
+ # pull official base image
31
+ FROM 224427659724.dkr.ecr.us-east-1.amazonaws.com/gradio-python:3.11.10-slim
32
+
33
+ # create directory for the app user
34
+ RUN mkdir -p /home/backend-app
35
+
36
+ # create the app user
37
+ RUN addgroup --system app && adduser --system --group app
38
+
39
+ # create the appropriate directories
40
+ ENV HOME=/home/app
41
+ ENV BACKEND_APP_HOME=/home/app
42
+ # RUN mkdir $BACKEND_APP_HOME
43
+ WORKDIR $BACKEND_APP_HOME
44
+
45
+ # install dependencies
46
+ RUN apt-get update \
47
+ && apt-get -y install libpq-dev gcc \
48
+ && pip install psycopg
49
+
50
+ COPY --from=builder /app/wheels /wheels
51
+ COPY --from=builder /app/requirements.txt .
52
+ RUN pip install --upgrade pip
53
+ RUN pip install --no-cache /wheels/*
54
+
55
+ # copy project
56
+ COPY . $BACKEND_APP_HOME
57
+
58
+ # chown all the files to the app user
59
+ RUN chown -R app:app $BACKEND_APP_HOME
60
+
61
+ # change to the app user
62
+ USER app
63
+
64
+ # Expose port
65
+ EXPOSE 7860
66
+ ENV GRADIO_SERVER_NAME="0.0.0.0"
67
+
68
+ CMD ["gradio", "app.py"]
Makefile ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .PHONY: lint-apply lint-check
2
+
3
+ lint-check:
4
+ @echo "Checking for lint errors..."
5
+ flake8 .
6
+ black --check .
7
+ isort --check-only .
8
+
9
+ lint-apply:
10
+ @echo "apply linting ..."
11
+ black .
12
+ isort .
README.md CHANGED
@@ -10,4 +10,177 @@ pinned: false
10
  license: apache-2.0
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  license: apache-2.0
11
  ---
12
 
13
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
14
+
15
+
16
+ # ACRES RAG Project
17
+
18
+ ## Project Setup
19
+
20
+ To test and run the project locally. Clone the project from github and change directoory to `acres`.
21
+
22
+ ```sh
23
+ git clone https://github.com/SunbirdAI/acres.git
24
+ cd acres
25
+ ```
26
+
27
+ Create python virtual environment and activate it.
28
+
29
+ ```sh
30
+ python -m venv env
31
+ source env/bin/activate
32
+ ```
33
+
34
+ Install project dependencies
35
+
36
+ ```sh
37
+ pip install -r requirements.txt
38
+ ```
39
+
40
+ ## Run project locally
41
+ To test the project locally follow the steps below.
42
+
43
+ Copy `.env.example` to `.env` and provide the correct enviroment variable values.
44
+
45
+ ```sh
46
+ cp .env.example .env
47
+ ```
48
+
49
+ Run the application
50
+
51
+ ```sh
52
+ python app.py
53
+ ```
54
+
55
+ OR
56
+
57
+ ```sh
58
+ gradio app.py
59
+ ```
60
+
61
+ Browse the application with the link `http://localhost:7860/`
62
+
63
+
64
+ ## Run with docker
65
+ To run the application with docker locally, first make sure you have docker installed. See [link](https://docs.docker.com/)
66
+
67
+ Build the project docker image
68
+
69
+ ```sh
70
+ docker build -f Dockerfile.gradio -t gradio-app .
71
+ ```
72
+
73
+ Create docker network
74
+
75
+ ```sh
76
+ docker network create gradio-fastapi-network
77
+ ```
78
+
79
+ Run the docker container
80
+
81
+ ```sh
82
+ docker run -it -p 7860:7860 --rm --name gradio --network=gradio-fastapi-network gradio-app
83
+ ```
84
+
85
+ Browse the application with the link `http://localhost:7860/`
86
+
87
+
88
+ ## Deploy to AWS ECS (Elastic Container Service) with Fargate
89
+
90
+ Install and configure the AWS CLI and aws credentials. See [link](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html)
91
+
92
+ OR: See the pdf document [here](./aws-cli.pdf)
93
+
94
+ Now follow the steps below to deploy to AWS ECS
95
+
96
+ Setup the default region and your aws account id
97
+
98
+ ```sh
99
+ export AWS_DEFAULT_REGION=region # i.e us-east-1, eu-west-1
100
+ export AWS_ACCOUNT_ID=aws_account_id # ie. 2243838xxxxxx
101
+ ```
102
+
103
+ Login into the AWS ECR (Elastic Container Registry) via the commandline
104
+
105
+ ```sh
106
+ aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin "$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com
107
+ ```
108
+
109
+ Create a python image and push to ECR. This image will be used as the base image for the application image deployed on AWS ECS.
110
+
111
+ - Create python repository
112
+
113
+ ```sh
114
+ aws ecr create-repository \
115
+ --repository-name gradio-python \
116
+ --image-tag-mutability MUTABLE
117
+ ```
118
+
119
+ ```sh
120
+ export ECR_PYTHON_URL="$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/gradio-python"
121
+ echo $ECR_PYTHON_URL
122
+ ```
123
+
124
+ - Pull python image and tag it to the ECR url
125
+
126
+ ```sh
127
+ docker pull python:3.11.10-slim
128
+ docker tag python:3.11.10-slim $ECR_PYTHON_URL:3.11.10-slim
129
+
130
+ docker push $ECR_PYTHON_URL:3.11.10-slim
131
+ ```
132
+
133
+ - Now create application repostory
134
+
135
+ ```sh
136
+ aws ecr create-repository \
137
+ --repository-name gradio-app-prod \
138
+ --image-tag-mutability MUTABLE
139
+
140
+ export ECR_BACKEND_GRADIO_URL="$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/gradio-app-prod"
141
+ echo $ECR_BACKEND_GRADIO_URL
142
+ ```
143
+
144
+ - Build the docker image for the production and push to ECR
145
+
146
+ ```sh
147
+ docker build --build-arg AWS_ACCOUNT_ID=$AWS_ACCOUNT_ID -f Dockerfile.gradio.prod -t gradio-app-prod .
148
+ docker tag gradio-app-prod:latest "${ECR_BACKEND_GRADIO_URL}:latest"
149
+ docker push "${ECR_BACKEND_GRADIO_URL}:latest"
150
+ ```
151
+
152
+ ### Setup and Provision AWS ECS infra using AWS Cloudformation (IaC)
153
+
154
+ #### Install
155
+ To install the CFN-CLI run the command below
156
+
157
+ ```sh
158
+ pip install cloudformation-cli cloudformation-cli-java-plugin cloudformation-cli-go-plugin cloudformation-cli-python-plugin cloudformation-cli-typescript-plugin
159
+ ```
160
+
161
+ #### CFN-Toml
162
+
163
+ ```sh
164
+ gem install cfn-toml
165
+ ```
166
+
167
+
168
+ Copy `infra/ecs_config.template` to `infra/ecs_config.toml` and provide the correct `AWS Account ID` for the `ContainerImageGradio`
169
+
170
+ ```sh
171
+ cp infra/ecs_config.template infra/ecs_config.toml
172
+ ```
173
+
174
+
175
+ #### Deploy
176
+
177
+ To deploy the ECS infra run the commands below. It provisions the cloudformation stack changeset for review.
178
+
179
+ Log into your aws console and search for `cloudformation`. See and review the changeset. If everything is good execute the changeset to finish with the infra deployment.
180
+
181
+ Then look for the outputs to the link for the deployed application.
182
+
183
+ ```sh
184
+ chmod u+x bin/cfn/*
185
+ ./bin/cfn/ecs-deploy
186
+ ```
api.py ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ import os
3
+ from enum import Enum
4
+ from typing import List, Optional
5
+
6
+ from dotenv import load_dotenv
7
+ from fastapi import FastAPI, HTTPException
8
+ from fastapi.responses import FileResponse
9
+ from gradio_client import Client
10
+ from pydantic import BaseModel, ConfigDict, Field, constr
11
+
12
+ from docs import description, tags_metadata
13
+
14
+ load_dotenv()
15
+ logging.basicConfig(level=logging.INFO)
16
+ logger = logging.getLogger(__name__)
17
+
18
+ app = FastAPI(
19
+ title="ACRES RAG API",
20
+ description=description,
21
+ openapi_tags=tags_metadata,
22
+ )
23
+ GRADIO_URL = os.getenv("GRADIO_URL", "http://localhost:7860/")
24
+ logger.info(f"GRADIO_URL: {GRADIO_URL}")
25
+ client = Client(GRADIO_URL)
26
+
27
+
28
+ class StudyVariables(str, Enum):
29
+ ebola_virus = "Ebola Virus"
30
+ vaccine_coverage = "Vaccine coverage"
31
+ genexpert = "GeneXpert"
32
+
33
+
34
+ class PromptType(str, Enum):
35
+ default = "Default"
36
+ highlight = "Highlight"
37
+ evidence_based = "Evidence-based"
38
+
39
+
40
+ class StudyVariableRequest(BaseModel):
41
+ study_variable: StudyVariables
42
+ prompt_type: PromptType
43
+ text: constr(min_length=1, strip_whitespace=True) # type: ignore
44
+
45
+ model_config = ConfigDict(from_attributes=True)
46
+
47
+
48
+ class DownloadCSV(BaseModel):
49
+ text: constr(min_length=1, strip_whitespace=True) # type: ignore
50
+
51
+ model_config = ConfigDict(from_attributes=True)
52
+
53
+
54
+ class Study(BaseModel):
55
+ study_name: constr(min_length=1, strip_whitespace=True) # type: ignore
56
+
57
+ model_config = ConfigDict(from_attributes=True)
58
+
59
+
60
+ class ZoteroCredentials(BaseModel):
61
+ library_id: constr(min_length=1, strip_whitespace=True) # type: ignore
62
+ api_access_key: constr(min_length=1, strip_whitespace=True) # type: ignore
63
+
64
+ model_config = ConfigDict(from_attributes=True)
65
+
66
+
67
+ @app.post("/process_zotero_library_items", tags=["zotero"])
68
+ def process_zotero_library_items(zotero_credentials: ZoteroCredentials):
69
+ result = client.predict(
70
+ zotero_library_id=zotero_credentials.library_id,
71
+ zotero_api_access_key=zotero_credentials.api_access_key,
72
+ api_name="/process_zotero_library_items",
73
+ )
74
+ return {"result": result}
75
+
76
+
77
+ @app.post("/get_study_info", tags=["zotero"])
78
+ def get_study_info(study: Study):
79
+ result = client.predict(study_name=study.study_name, api_name="/get_study_info")
80
+ # print(result)
81
+ return {"result": result}
82
+
83
+
84
+ @app.post("/study_variables", tags=["zotero"])
85
+ def process_study_variables(
86
+ study_request: StudyVariableRequest,
87
+ ):
88
+ result = client.predict(
89
+ text=study_request.text, # "study id, study title, study design, study summary",
90
+ study_name=study_request.study_variable, # "Ebola Virus",
91
+ prompt_type=study_request.prompt_type, # "Default",
92
+ api_name="/process_multi_input",
93
+ )
94
+ print(type(result))
95
+ return {"result": result[0]}
96
+
97
+
98
+ @app.post("/download_csv", tags=["zotero"])
99
+ def download_csv(download_request: DownloadCSV):
100
+ result = client.predict(
101
+ markdown_content=download_request.text, api_name="/download_as_csv"
102
+ )
103
+ print(result)
104
+
105
+ file_path = result
106
+ if not file_path or not os.path.exists(file_path):
107
+ raise HTTPException(status_code=404, detail="File not found")
108
+
109
+ # Use FileResponse to send the file to the client
110
+ return FileResponse(
111
+ file_path,
112
+ media_type="text/csv", # Specify the correct MIME type for CSV
113
+ filename=os.path.basename(
114
+ file_path
115
+ ), # Provide a default filename for the download
116
+ )
app.py CHANGED
@@ -1,33 +1,38 @@
1
  # app.py
2
 
3
  import csv
4
-
5
  import datetime
6
-
7
  # from datetime import datetime
8
  import io
9
  import json
10
  import logging
11
  import os
12
- from typing import Tuple, List, Any
13
 
14
  import gradio as gr
15
  import openai
 
16
  from dotenv import load_dotenv
17
  from slugify import slugify
18
 
19
- from config import STUDY_FILES, OPENAI_API_KEY
 
20
  from rag.rag_pipeline import RAGPipeline
 
 
 
 
 
 
 
21
  from utils.helpers import (
22
- append_to_study_files,
23
  add_study_files_to_chromadb,
 
24
  chromadb_client,
25
  )
26
- from utils.prompts import highlight_prompt, evidence_based_prompt
27
- from utils.zotero_manager import ZoteroManager
28
-
29
- from interface import create_chat_interface
30
  from utils.pdf_processor import PDFProcessor
 
 
31
 
32
  # Configure logging
33
  logging.basicConfig(level=logging.INFO)
@@ -39,9 +44,27 @@ openai.api_key = OPENAI_API_KEY
39
  # Initialize ChromaDB with study files
40
  add_study_files_to_chromadb("study_files.json", "study_files_collection")
41
 
 
 
 
 
42
  # Cache for RAG pipelines
43
  rag_cache = {}
44
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
 
46
  def get_rag_pipeline(study_name: str) -> RAGPipeline:
47
  """Get or create a RAGPipeline instance for the given study by querying ChromaDB."""
@@ -61,18 +84,26 @@ def get_rag_pipeline(study_name: str) -> RAGPipeline:
61
  return rag_cache[study_name]
62
 
63
 
64
- def get_study_info(study_name: str) -> str:
65
  """Retrieve information about the specified study."""
 
 
 
 
 
 
 
 
66
 
67
  collection = chromadb_client.get_or_create_collection("study_files_collection")
68
  result = collection.get(ids=[study_name]) # Query by study name (as a list)
69
- logging.info(f"Result: ======> {result}")
70
 
71
  if not result or len(result["metadatas"]) == 0:
72
  raise ValueError(f"Invalid study name: {study_name}")
73
 
74
  study_file = result["metadatas"][0].get("file_path")
75
- logging.info(f"study_file: =======> {study_file}")
76
  if not study_file:
77
  raise ValueError(f"File path not found for study name: {study_name}")
78
 
@@ -116,9 +147,9 @@ def cleanup_temp_files():
116
  try:
117
  os.remove(file)
118
  except Exception as e:
119
- logging.warning(f"Failed to remove temp file {file}: {e}")
120
  except Exception as e:
121
- logging.warning(f"Error during cleanup: {e}")
122
 
123
 
124
  def chat_function(message: str, study_name: str, prompt_type: str) -> str:
@@ -128,7 +159,7 @@ def chat_function(message: str, study_name: str, prompt_type: str) -> str:
128
  return "Please enter a valid query."
129
 
130
  rag = get_rag_pipeline(study_name)
131
- logging.info(f"rag: ==> {rag}")
132
  prompt = {
133
  "Highlight": highlight_prompt,
134
  "Evidence-based": evidence_based_prompt,
@@ -139,12 +170,14 @@ def chat_function(message: str, study_name: str, prompt_type: str) -> str:
139
 
140
 
141
  def process_zotero_library_items(
142
- zotero_library_id: str, zotero_api_access_key: str
143
  ) -> str:
144
- if not zotero_library_id or not zotero_api_access_key:
 
145
  return "Please enter your zotero library Id and API Access Key"
146
 
147
- zotero_library_id = zotero_library_id
 
148
  zotero_library_type = "user" # or "group"
149
  zotero_api_access_key = zotero_api_access_key
150
 
@@ -192,10 +225,18 @@ def process_zotero_library_items(
192
 
193
  # Update in-memory STUDY_FILES for reference in current session
194
  STUDY_FILES.update({collection_name: f"data/{export_file}"})
195
- logging.info(f"STUDY_FILES: {STUDY_FILES}")
196
 
197
  # After loop, add all collected data to ChromaDB
198
  add_study_files_to_chromadb("study_files.json", "study_files_collection")
 
 
 
 
 
 
 
 
199
  message = "Successfully processed items in your zotero library"
200
  except Exception as e:
201
  message = f"Error process your zotero library: {str(e)}"
@@ -203,11 +244,27 @@ def process_zotero_library_items(
203
  return message
204
 
205
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
206
  def process_multi_input(text, study_name, prompt_type):
207
  # Split input based on commas and strip any extra spaces
208
  variable_list = [word.strip().upper() for word in text.split(",")]
209
  user_message = f"Extract and present in a tabular format the following variables for each {study_name} study: {', '.join(variable_list)}"
210
- logging.info(f"User message: ==> {user_message}")
211
  response = chat_function(user_message, study_name, prompt_type)
212
  return [response, gr.update(visible=True)]
213
 
@@ -311,7 +368,8 @@ def chat_response(
311
 
312
  def create_gr_interface() -> gr.Blocks:
313
  """Create and configure the Gradio interface for the RAG platform."""
314
- with gr.Blocks() as demo:
 
315
  gr.Markdown("# ACRES RAG Platform")
316
 
317
  with gr.Tabs() as tabs:
@@ -320,7 +378,7 @@ def create_gr_interface() -> gr.Blocks:
320
  with gr.Row():
321
  with gr.Column(scale=1):
322
  gr.Markdown("### Zotero Credentials")
323
- zotero_library_id = gr.Textbox(
324
  label="Zotero Library ID",
325
  type="password",
326
  placeholder="Enter Your Zotero Library ID here...",
@@ -346,11 +404,26 @@ def create_gr_interface() -> gr.Blocks:
346
  if all_documents
347
  ]
348
 
 
 
 
 
 
 
 
 
 
 
 
 
349
  study_dropdown = gr.Dropdown(
350
  choices=study_choices,
351
  label="Select Study",
352
  value=(study_choices[0] if study_choices else None),
353
  )
 
 
 
354
  study_info = gr.Markdown(label="Study Details")
355
  prompt_type = gr.Radio(
356
  ["Default", "Highlight", "Evidence-based"],
@@ -420,7 +493,7 @@ def create_gr_interface() -> gr.Blocks:
420
  # Event handlers for Study Analysis tab
421
  process_zotero_btn.click(
422
  process_zotero_library_items,
423
- inputs=[zotero_library_id, zotero_api_access_key],
424
  outputs=[zotero_output],
425
  )
426
 
@@ -438,6 +511,11 @@ def create_gr_interface() -> gr.Blocks:
438
  fn=download_as_csv, inputs=[answer_output], outputs=[download_btn]
439
  ).then(fn=cleanup_temp_files, inputs=None, outputs=None)
440
 
 
 
 
 
 
441
  # Event handlers for PDF Chat tab
442
 
443
  def handle_pdf_upload(files, name):
 
1
  # app.py
2
 
3
  import csv
 
4
  import datetime
 
5
  # from datetime import datetime
6
  import io
7
  import json
8
  import logging
9
  import os
10
+ from typing import Any, List, Tuple
11
 
12
  import gradio as gr
13
  import openai
14
+ from cachetools import LRUCache
15
  from dotenv import load_dotenv
16
  from slugify import slugify
17
 
18
+ from config import OPENAI_API_KEY, STUDY_FILES
19
+ from interface import create_chat_interface
20
  from rag.rag_pipeline import RAGPipeline
21
+ from utils.db import (
22
+ add_study_files_to_db,
23
+ create_db_and_tables,
24
+ get_all_study_files,
25
+ get_study_file_by_name,
26
+ get_study_files_by_library_id,
27
+ )
28
  from utils.helpers import (
 
29
  add_study_files_to_chromadb,
30
+ append_to_study_files,
31
  chromadb_client,
32
  )
 
 
 
 
33
  from utils.pdf_processor import PDFProcessor
34
+ from utils.prompts import evidence_based_prompt, highlight_prompt
35
+ from utils.zotero_manager import ZoteroManager
36
 
37
  # Configure logging
38
  logging.basicConfig(level=logging.INFO)
 
44
  # Initialize ChromaDB with study files
45
  add_study_files_to_chromadb("study_files.json", "study_files_collection")
46
 
47
+ # Create sqlite study file data table
48
+ create_db_and_tables()
49
+
50
+
51
  # Cache for RAG pipelines
52
  rag_cache = {}
53
 
54
+ cache = LRUCache(maxsize=100)
55
+
56
+ # with open("study_files.json", "w") as file:
57
+ # data_ = {}
58
+ # json.dump(data_, file, indent=4)
59
+
60
+
61
+ def get_cache_value(key):
62
+ return cache.get(key)
63
+
64
+
65
+ zotero_library_id = get_cache_value("zotero_library_id")
66
+ logger.info(f"zotero_library_id: {zotero_library_id}")
67
+
68
 
69
  def get_rag_pipeline(study_name: str) -> RAGPipeline:
70
  """Get or create a RAGPipeline instance for the given study by querying ChromaDB."""
 
84
  return rag_cache[study_name]
85
 
86
 
87
+ def get_study_info(study_name: str | list) -> str:
88
  """Retrieve information about the specified study."""
89
+ if isinstance(study_name, list):
90
+ study_name = study_name[0] if study_name else None
91
+
92
+ if not study_name:
93
+ return "No study selected"
94
+
95
+ study = get_study_file_by_name(study_name)
96
+ logger.info(f"Study: {study}")
97
 
98
  collection = chromadb_client.get_or_create_collection("study_files_collection")
99
  result = collection.get(ids=[study_name]) # Query by study name (as a list)
100
+ logger.info(f"Result: {result}")
101
 
102
  if not result or len(result["metadatas"]) == 0:
103
  raise ValueError(f"Invalid study name: {study_name}")
104
 
105
  study_file = result["metadatas"][0].get("file_path")
106
+ logger.info(f"study_file: {study_file}")
107
  if not study_file:
108
  raise ValueError(f"File path not found for study name: {study_name}")
109
 
 
147
  try:
148
  os.remove(file)
149
  except Exception as e:
150
+ logger.warning(f"Failed to remove temp file {file}: {e}")
151
  except Exception as e:
152
+ logger.warning(f"Error during cleanup: {e}")
153
 
154
 
155
  def chat_function(message: str, study_name: str, prompt_type: str) -> str:
 
159
  return "Please enter a valid query."
160
 
161
  rag = get_rag_pipeline(study_name)
162
+ logger.info(f"rag: {rag}")
163
  prompt = {
164
  "Highlight": highlight_prompt,
165
  "Evidence-based": evidence_based_prompt,
 
170
 
171
 
172
  def process_zotero_library_items(
173
+ zotero_library_id_param: str, zotero_api_access_key: str
174
  ) -> str:
175
+ global zotero_library_id
176
+ if not zotero_library_id_param or not zotero_api_access_key:
177
  return "Please enter your zotero library Id and API Access Key"
178
 
179
+ zotero_library_id = zotero_library_id_param
180
+ cache["zotero_library_id"] = zotero_library_id
181
  zotero_library_type = "user" # or "group"
182
  zotero_api_access_key = zotero_api_access_key
183
 
 
225
 
226
  # Update in-memory STUDY_FILES for reference in current session
227
  STUDY_FILES.update({collection_name: f"data/{export_file}"})
228
+ logger.info(f"STUDY_FILES: {STUDY_FILES}")
229
 
230
  # After loop, add all collected data to ChromaDB
231
  add_study_files_to_chromadb("study_files.json", "study_files_collection")
232
+ # Add collected data to sqlite
233
+ add_study_files_to_db("study_files.json", zotero_library_id)
234
+
235
+ # Dynamically update study choices
236
+ global study_choices
237
+ study_choices = [
238
+ file.name for file in get_study_files_by_library_id([zotero_library_id])
239
+ ]
240
  message = "Successfully processed items in your zotero library"
241
  except Exception as e:
242
  message = f"Error process your zotero library: {str(e)}"
 
244
  return message
245
 
246
 
247
+ def refresh_study_choices():
248
+ """
249
+ Refresh study choices for a specific dropdown instance.
250
+
251
+ :return: Updated Dropdown with current study choices
252
+ """
253
+ global study_choices
254
+ zotero_library_id = get_cache_value("zotero_library_id")
255
+ logger.info(f"zotero_library_id: {zotero_library_id}")
256
+ study_choices = [
257
+ file.name for file in get_study_files_by_library_id([zotero_library_id])
258
+ ]
259
+ logger.info(f"Study choices: {study_choices}")
260
+ return study_choices
261
+
262
+
263
  def process_multi_input(text, study_name, prompt_type):
264
  # Split input based on commas and strip any extra spaces
265
  variable_list = [word.strip().upper() for word in text.split(",")]
266
  user_message = f"Extract and present in a tabular format the following variables for each {study_name} study: {', '.join(variable_list)}"
267
+ logger.info(f"User message: {user_message}")
268
  response = chat_function(user_message, study_name, prompt_type)
269
  return [response, gr.update(visible=True)]
270
 
 
368
 
369
  def create_gr_interface() -> gr.Blocks:
370
  """Create and configure the Gradio interface for the RAG platform."""
371
+ global zotero_library_id
372
+ with gr.Blocks(theme=gr.themes.Base()) as demo:
373
  gr.Markdown("# ACRES RAG Platform")
374
 
375
  with gr.Tabs() as tabs:
 
378
  with gr.Row():
379
  with gr.Column(scale=1):
380
  gr.Markdown("### Zotero Credentials")
381
+ zotero_library_id_param = gr.Textbox(
382
  label="Zotero Library ID",
383
  type="password",
384
  placeholder="Enter Your Zotero Library ID here...",
 
404
  if all_documents
405
  ]
406
 
407
+ print(f"zotero_library_id: {zotero_library_id_param.value}")
408
+ zotero_library_id = zotero_library_id_param.value
409
+ if zotero_library_id is None:
410
+ zotero_library_id = get_cache_value("zotero_library_id")
411
+ logger.info(f"zotero_library_id: =====> {zotero_library_id}")
412
+ study_choices_db = get_study_files_by_library_id(
413
+ [zotero_library_id]
414
+ )
415
+ logger.info(f"study_choices_db: =====> {study_choices_db}")
416
+ study_files = get_all_study_files()
417
+ logger.info(f"study_files: =====> {study_files}")
418
+
419
  study_dropdown = gr.Dropdown(
420
  choices=study_choices,
421
  label="Select Study",
422
  value=(study_choices[0] if study_choices else None),
423
  )
424
+ # In Gradio interface setup
425
+ refresh_button = gr.Button("Refresh Studies")
426
+
427
  study_info = gr.Markdown(label="Study Details")
428
  prompt_type = gr.Radio(
429
  ["Default", "Highlight", "Evidence-based"],
 
493
  # Event handlers for Study Analysis tab
494
  process_zotero_btn.click(
495
  process_zotero_library_items,
496
+ inputs=[zotero_library_id_param, zotero_api_access_key],
497
  outputs=[zotero_output],
498
  )
499
 
 
511
  fn=download_as_csv, inputs=[answer_output], outputs=[download_btn]
512
  ).then(fn=cleanup_temp_files, inputs=None, outputs=None)
513
 
514
+ refresh_button.click(
515
+ fn=refresh_study_choices,
516
+ outputs=[study_dropdown], # Update the same dropdown
517
+ )
518
+
519
  # Event handlers for PDF Chat tab
520
 
521
  def handle_pdf_upload(files, name):
bin/cfn/ecs-delete ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #! /usr/bin/env bash
2
+ set -e # stop the execution of the script if it fails
3
+
4
+ CONFIG_PATH="/Users/patrickcmd/Projects/sunbirdai/Acres/infra/ecs_config.toml"
5
+
6
+
7
+ REGION=$(cfn-toml key deploy.region -t $CONFIG_PATH)
8
+ STACK_NAME=$(cfn-toml key deploy.stack_name -t $CONFIG_PATH)
9
+
10
+
11
+ aws cloudformation delete-stack \
12
+ --stack-name $STACK_NAME \
13
+ --region $REGION \
14
+ --profile sunbirdai
bin/cfn/ecs-deploy ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #! /usr/bin/env bash
2
+ set -e # stop the execution of the script if it fails
3
+
4
+ CFN_PATH="/Users/patrickcmd/Projects/sunbirdai/Acres/infra/ecs_fargate.yml"
5
+ CONFIG_PATH="/Users/patrickcmd/Projects/sunbirdai/Acres/infra/ecs_config.toml"
6
+ echo $CFN_PATH
7
+
8
+ cfn-lint $CFN_PATH
9
+
10
+ BUCKET=$(cfn-toml key deploy.bucket -t $CONFIG_PATH)
11
+ REGION=$(cfn-toml key deploy.region -t $CONFIG_PATH)
12
+ STACK_NAME=$(cfn-toml key deploy.stack_name -t $CONFIG_PATH)
13
+ PARAMETERS=$(cfn-toml params v2 -t $CONFIG_PATH)
14
+
15
+ aws cloudformation deploy \
16
+ --stack-name $STACK_NAME \
17
+ --s3-bucket $BUCKET \
18
+ --s3-prefix acres-rag \
19
+ --region $REGION \
20
+ --template-file "$CFN_PATH" \
21
+ --no-execute-changeset \
22
+ --tags group=acres-rag \
23
+ --parameter-overrides $PARAMETERS \
24
+ --capabilities CAPABILITY_NAMED_IAM \
25
+ --profile sunbirdai
commands.md ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ docker network create gradio-fastapi-network
2
+
3
+ docker run -it -p 7860:7860 --rm --name gradio --network=gradio-fastapi-network gradio-app
4
+
5
+ docker run -it -p 7860:7860 --rm --name gradio --network=gradio-fastapi-network gradio-app-prod
6
+
7
+
8
+ export AWS_DEFAULT_REGION=us-east-1
9
+ export AWS_ACCOUNT_ID=2244276xxxxx
10
+ aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin "$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com"
11
+
12
+ aws ecr create-repository \
13
+ --repository-name gradio-python \
14
+ --image-tag-mutability MUTABLE
15
+
16
+ export ECR_PYTHON_URL="$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/gradio-python"
17
+ echo $ECR_PYTHON_URL
18
+
19
+ docker pull python:3.11.10-slim
20
+ docker tag python:3.11.10-slim $ECR_PYTHON_URL:3.11.10-slim
21
+
22
+ docker push $ECR_PYTHON_URL:3.11.10-slim
23
+
24
+
25
+ aws ecr create-repository \
26
+ --repository-name gradio-app-prod \
27
+ --image-tag-mutability MUTABLE
28
+
29
+ export ECR_BACKEND_GRADIO_URL="$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/gradio-app-prod"
30
+ echo $ECR_BACKEND_GRADIO_URL
31
+
32
+ docker build --build-arg AWS_ACCOUNT_ID=2244276xxxxx -t your-image-name .
33
+ docker build -f Dockerfile.gradio.prod -t gradio-app-prod .
34
+
35
+ docker build --build-arg AWS_ACCOUNT_ID=$AWS_ACCOUNT_ID -f Dockerfile.gradio.prod -t gradio-app-prod .
36
+ docker tag gradio-app-prod:latest "${ECR_BACKEND_GRADIO_URL}:latest"
37
+ docker push "${ECR_BACKEND_GRADIO_URL}:latest"
38
+
39
+
40
+ docker build -f Dockerfile.api -t fastapi-app .
41
+ docker run -it -p 8000:8000 --rm --name fastapi --network=gradio-fastapi-network fastapi-app
42
+
43
+ aws ecr create-repository \
44
+ --repository-name fastapi-api-prod \
45
+ --image-tag-mutability MUTABLE
46
+
47
+ export ECR_BACKEND_FASTAPI_URL="$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/fastapi-api-prod"
48
+ echo $ECR_BACKEND_FASTAPI_URL
49
+
50
+ docker build -f Dockerfile.api.prod -t fastapi-api-prod .
51
+ docker tag fastapi-api-prod:latest "${ECR_BACKEND_FASTAPI_URL}:latest"
52
+ docker push "${ECR_BACKEND_FASTAPI_URL}:latest"
53
+
docs.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ description = """
2
+ Welcome to the Acres AI RAG API documentation.
3
+
4
+ ### RAG Tasks
5
+ - Use the `/process_zotero_library_items`: Process zotero library items with your zotero credentials.
6
+ - Use the `/get_study_info`: Get number of documents in a zotero study.
7
+ - Use the `/study_variables`: Get research summary from the study provided the study variables.
8
+ - Use the `/download_csv`: Export the markdown text to a csv file.
9
+ """
10
+
11
+ tags_metadata = [
12
+ {"name": "ACRES RAG", "description": "AI RAG Application"},
13
+ ]
infra/ecs_config.template ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ [deploy]
2
+ bucket = 'dev-acres-gradio-bucket'
3
+ region = 'us-east-1'
4
+ stack_name = 'AcresRag'
5
+
6
+ [parameters]
7
+ ContainerImageGradio = '224427659xxxx.dkr.ecr.us-east-1.amazonaws.com/gradio-app-prod:latest'
infra/ecs_fargate.yml ADDED
@@ -0,0 +1,581 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ AWSTemplateFormatVersion: '2010-09-09'
2
+ Description: Deploy Gradio and FastAPI services on AWS ECS Fargate
3
+
4
+ Parameters:
5
+ Environment:
6
+ Type: String
7
+ Default: dev
8
+ AllowedValues: [dev, prod]
9
+
10
+ # VPC Configuration
11
+ VpcCIDR:
12
+ Type: String
13
+ Default: 10.0.0.0/16
14
+ PublicSubnet1CIDR:
15
+ Type: String
16
+ Default: 10.0.1.0/24
17
+ PublicSubnet2CIDR:
18
+ Type: String
19
+ Default: 10.0.2.0/24
20
+
21
+ # ECS Configuration
22
+ ECSClusterName:
23
+ Type: String
24
+ Default: rag-ecs-cluster
25
+ GradioTaskDefinitionCPU:
26
+ Type: Number
27
+ Default: 512
28
+ GradioTaskDefinitionMemory:
29
+ Type: Number
30
+ Default: 1024
31
+ FastAPITaskDefinitionCPU:
32
+ Type: Number
33
+ Default: 256
34
+ FastAPITaskDefinitionMemory:
35
+ Type: Number
36
+ Default: 512
37
+
38
+ # Container Images
39
+ ContainerImageGradio:
40
+ Type: String
41
+ Description: URI of the Gradio container image in ECR
42
+ ContainerImageFastAPI:
43
+ Type: String
44
+ Description: URI of the FastAPI container image in ECR
45
+ # CertificateArn:
46
+ # Type: String
47
+
48
+ Resources:
49
+ # VPC and Networking
50
+ VPC:
51
+ Type: AWS::EC2::VPC
52
+ Properties:
53
+ CidrBlock: !Ref VpcCIDR
54
+ EnableDnsHostnames: true
55
+ EnableDnsSupport: true
56
+ Tags:
57
+ - Key: Name
58
+ Value: !Sub ${Environment}-acres-vpc
59
+
60
+ InternetGateway:
61
+ Type: AWS::EC2::InternetGateway
62
+ Properties:
63
+ Tags:
64
+ - Key: Name
65
+ Value: !Sub ${Environment}-acres-igw
66
+
67
+ AttachGateway:
68
+ Type: AWS::EC2::VPCGatewayAttachment
69
+ Properties:
70
+ VpcId: !Ref VPC
71
+ InternetGatewayId: !Ref InternetGateway
72
+
73
+ PublicSubnet1:
74
+ Type: AWS::EC2::Subnet
75
+ Properties:
76
+ VpcId: !Ref VPC
77
+ AvailabilityZone: !Select [0, !GetAZs '']
78
+ CidrBlock: !Ref PublicSubnet1CIDR
79
+ MapPublicIpOnLaunch: true
80
+ Tags:
81
+ - Key: Name
82
+ Value: !Sub ${Environment}-acres-public-subnet-1
83
+
84
+ PublicSubnet2:
85
+ Type: AWS::EC2::Subnet
86
+ Properties:
87
+ VpcId: !Ref VPC
88
+ AvailabilityZone: !Select [1, !GetAZs '']
89
+ CidrBlock: !Ref PublicSubnet2CIDR
90
+ MapPublicIpOnLaunch: true
91
+ Tags:
92
+ - Key: Name
93
+ Value: !Sub ${Environment}-acres-public-subnet-2
94
+
95
+ PublicRouteTable:
96
+ Type: AWS::EC2::RouteTable
97
+ Properties:
98
+ VpcId: !Ref VPC
99
+ Tags:
100
+ - Key: Name
101
+ Value: !Sub ${Environment}-acres-public-rt
102
+
103
+ PublicRoute:
104
+ Type: AWS::EC2::Route
105
+ DependsOn: AttachGateway
106
+ Properties:
107
+ RouteTableId: !Ref PublicRouteTable
108
+ DestinationCidrBlock: 0.0.0.0/0
109
+ GatewayId: !Ref InternetGateway
110
+
111
+ PublicSubnet1RouteTableAssociation:
112
+ Type: AWS::EC2::SubnetRouteTableAssociation
113
+ Properties:
114
+ SubnetId: !Ref PublicSubnet1
115
+ RouteTableId: !Ref PublicRouteTable
116
+
117
+ PublicSubnet2RouteTableAssociation:
118
+ Type: AWS::EC2::SubnetRouteTableAssociation
119
+ Properties:
120
+ SubnetId: !Ref PublicSubnet2
121
+ RouteTableId: !Ref PublicRouteTable
122
+
123
+ # Security Groups
124
+ GradioSecurityGroup:
125
+ Type: AWS::EC2::SecurityGroup
126
+ Properties:
127
+ GroupDescription: Security group for Gradio service
128
+ VpcId: !Ref VPC
129
+ SecurityGroupIngress:
130
+ - IpProtocol: tcp
131
+ FromPort: 7860
132
+ ToPort: 7860
133
+ CidrIp: 0.0.0.0/0
134
+ Description: INTERNET HTTPS
135
+ - IpProtocol: tcp
136
+ FromPort: 80
137
+ ToPort: 80
138
+ CidrIp: 0.0.0.0/0
139
+ Description: INTERNET HTTP
140
+ SecurityGroupEgress:
141
+ - IpProtocol: -1
142
+ CidrIp: 0.0.0.0/0
143
+
144
+ FastAPISecurityGroup:
145
+ Type: AWS::EC2::SecurityGroup
146
+ Properties:
147
+ GroupDescription: Security group for FastAPI service
148
+ VpcId: !Ref VPC
149
+ SecurityGroupIngress:
150
+ - IpProtocol: tcp
151
+ FromPort: 8000
152
+ ToPort: 8000
153
+ CidrIp: 0.0.0.0/0
154
+ Description: INTERNET HTTPS
155
+ - IpProtocol: tcp
156
+ FromPort: 80
157
+ ToPort: 80
158
+ CidrIp: 0.0.0.0/0
159
+ Description: INTERNET HTTP
160
+ SecurityGroupEgress:
161
+ - IpProtocol: -1
162
+ CidrIp: 0.0.0.0/0
163
+
164
+
165
+ # IAM Roles and Policies
166
+ # Gradio Execution Role - for pulling images and logging
167
+ GradioTaskExecutionRole:
168
+ Type: AWS::IAM::Role
169
+ Properties:
170
+ AssumeRolePolicyDocument:
171
+ Version: '2012-10-17'
172
+ Statement:
173
+ - Effect: Allow
174
+ Principal:
175
+ Service: ecs-tasks.amazonaws.com
176
+ Action: sts:AssumeRole
177
+ ManagedPolicyArns:
178
+ - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
179
+ Policies:
180
+ - PolicyName: GradioExecutionPolicy
181
+ PolicyDocument:
182
+ Version: '2012-10-17'
183
+ Statement:
184
+ - Effect: Allow
185
+ Action:
186
+ - ecr:GetAuthorizationToken
187
+ - ecr:BatchCheckLayerAvailability
188
+ - ecr:GetDownloadUrlForLayer
189
+ - ecr:BatchGetImage
190
+ Resource: '*'
191
+ - Effect: Allow
192
+ Action:
193
+ - logs:CreateLogStream
194
+ - logs:PutLogEvents
195
+ Resource:
196
+ - !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/ecs/${Environment}-acres-gradio:*
197
+ - !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/ecs/${Environment}-acres-gradio:log-stream:*
198
+
199
+ # Gradio Task Role - for runtime permissions
200
+ GradioTaskRole:
201
+ Type: AWS::IAM::Role
202
+ Properties:
203
+ AssumeRolePolicyDocument:
204
+ Version: '2012-10-17'
205
+ Statement:
206
+ - Effect: Allow
207
+ Principal:
208
+ Service: ecs-tasks.amazonaws.com
209
+ Action: sts:AssumeRole
210
+ Policies:
211
+ - PolicyName: GradioTaskPolicy
212
+ PolicyDocument:
213
+ Version: '2012-10-17'
214
+ Statement:
215
+ # Add specific permissions needed by your Gradio application at runtime
216
+ - Effect: Allow
217
+ Action:
218
+ - s3:GetObject
219
+ - s3:PutObject
220
+ Resource: !Sub arn:aws:s3:::${Environment}-acres-gradio-bucket/*
221
+
222
+ # FastAPI Execution Role - for pulling images and logging
223
+ FastAPITaskExecutionRole:
224
+ Type: AWS::IAM::Role
225
+ Properties:
226
+ AssumeRolePolicyDocument:
227
+ Version: '2012-10-17'
228
+ Statement:
229
+ - Effect: Allow
230
+ Principal:
231
+ Service: ecs-tasks.amazonaws.com
232
+ Action: sts:AssumeRole
233
+ ManagedPolicyArns:
234
+ - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
235
+ Policies:
236
+ - PolicyName: FastAPIExecutionPolicy
237
+ PolicyDocument:
238
+ Version: '2012-10-17'
239
+ Statement:
240
+ - Effect: Allow
241
+ Action:
242
+ - ecr:GetAuthorizationToken
243
+ - ecr:BatchCheckLayerAvailability
244
+ - ecr:GetDownloadUrlForLayer
245
+ - ecr:BatchGetImage
246
+ Resource: '*'
247
+ - Effect: Allow
248
+ Action:
249
+ - logs:CreateLogStream
250
+ - logs:PutLogEvents
251
+ Resource:
252
+ - !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/ecs/${Environment}-acres-fastapi:*
253
+ - !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/ecs/${Environment}-acres-fastapi:log-stream:*
254
+
255
+ # FastAPI Task Role - for runtime permissions
256
+ FastAPITaskRole:
257
+ Type: AWS::IAM::Role
258
+ Properties:
259
+ AssumeRolePolicyDocument:
260
+ Version: '2012-10-17'
261
+ Statement:
262
+ - Effect: Allow
263
+ Principal:
264
+ Service: ecs-tasks.amazonaws.com
265
+ Action: sts:AssumeRole
266
+ Policies:
267
+ - PolicyName: FastAPITaskPolicy
268
+ PolicyDocument:
269
+ Version: '2012-10-17'
270
+ Statement:
271
+ # Add specific permissions needed by your FastAPI application at runtime
272
+ - Effect: Allow
273
+ Action:
274
+ - dynamodb:GetItem
275
+ - dynamodb:PutItem
276
+ - dynamodb:Query
277
+ Resource: !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${Environment}-acres-fastapi-table
278
+ # Allow FastAPI to make HTTP calls to Gradio service
279
+ - Effect: Allow
280
+ Action:
281
+ - execute-api:Invoke
282
+ Resource: !Sub arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:*
283
+
284
+ # ECS Cluster
285
+ ECSCluster:
286
+ Type: AWS::ECS::Cluster
287
+ Properties:
288
+ ClusterName: !Ref ECSClusterName
289
+ Tags:
290
+ - Key: Environment
291
+ Value: !Ref Environment
292
+
293
+ # Load Balancer for Gradio
294
+ GradioALB:
295
+ Type: AWS::ElasticLoadBalancingV2::LoadBalancer
296
+ Properties:
297
+ Name: !Sub ${Environment}-acres-gradio-alb
298
+ Scheme: internet-facing
299
+ LoadBalancerAttributes:
300
+ - Key: idle_timeout.timeout_seconds
301
+ Value: '60'
302
+ Subnets:
303
+ - !Ref PublicSubnet1
304
+ - !Ref PublicSubnet2
305
+ SecurityGroups:
306
+ - !Ref GradioSecurityGroup
307
+
308
+ GradioTargetGroup:
309
+ Type: AWS::ElasticLoadBalancingV2::TargetGroup
310
+ Properties:
311
+ HealthCheckEnabled: true
312
+ HealthCheckIntervalSeconds: 30
313
+ HealthCheckPath: /
314
+ HealthCheckPort: 7860
315
+ HealthCheckTimeoutSeconds: 20
316
+ HealthyThresholdCount: 2
317
+ Name: !Sub ${Environment}-acres-gradio-tg
318
+ Port: 7860
319
+ Protocol: HTTP
320
+ TargetType: ip
321
+ UnhealthyThresholdCount: 5
322
+ VpcId: !Ref VPC
323
+ TargetGroupAttributes:
324
+ - Key: deregistration_delay.timeout_seconds
325
+ Value: '30'
326
+
327
+ GradioHTTPSListener:
328
+ # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticloadbalancingv2-listener.html
329
+ Type: AWS::ElasticLoadBalancingV2::Listener
330
+ Properties:
331
+ DefaultActions:
332
+ - Type: forward
333
+ TargetGroupArn: !Ref GradioTargetGroup
334
+ LoadBalancerArn: !Ref GradioALB
335
+ # Certificates:
336
+ # - CertificateArn: !Ref CertificateArn
337
+ Port: 7860
338
+ Protocol: HTTP
339
+ # GradioHTTPListener:
340
+ # # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticloadbalancingv2-listener.html
341
+ # Type: AWS::ElasticLoadBalancingV2::Listener
342
+ # Properties:
343
+ # Protocol: HTTP
344
+ # Port: 80
345
+ # LoadBalancerArn: !Ref GradioALB
346
+ # DefaultActions:
347
+ # - Type: redirect
348
+ # RedirectConfig:
349
+ # Protocol: "HTTPS"
350
+ # Port: 7860
351
+ # Host: "#{host}"
352
+ # Path: "/#{path}"
353
+ # Query: "#{query}"
354
+ # StatusCode: "HTTP_301"
355
+
356
+ # Load Balancer for FastAPI
357
+ FastAPIALB:
358
+ Type: AWS::ElasticLoadBalancingV2::LoadBalancer
359
+ Properties:
360
+ Name: !Sub ${Environment}-acres-fastapi-alb
361
+ Scheme: internet-facing
362
+ LoadBalancerAttributes:
363
+ - Key: idle_timeout.timeout_seconds
364
+ Value: '60'
365
+ Subnets:
366
+ - !Ref PublicSubnet1
367
+ - !Ref PublicSubnet2
368
+ SecurityGroups:
369
+ - !Ref FastAPISecurityGroup
370
+
371
+ FastAPITargetGroup:
372
+ Type: AWS::ElasticLoadBalancingV2::TargetGroup
373
+ Properties:
374
+ HealthCheckEnabled: true
375
+ HealthCheckIntervalSeconds: 30
376
+ HealthCheckPath: /docs # FastAPI's Swagger UI path
377
+ HealthCheckPort: 8000
378
+ HealthCheckTimeoutSeconds: 20
379
+ HealthyThresholdCount: 2
380
+ Name: !Sub ${Environment}-acres-fastapi-tg
381
+ Port: 8000
382
+ Protocol: HTTP
383
+ TargetType: ip
384
+ UnhealthyThresholdCount: 5
385
+ VpcId: !Ref VPC
386
+ TargetGroupAttributes:
387
+ - Key: deregistration_delay.timeout_seconds
388
+ Value: '30'
389
+
390
+ FastAPIHTTPSListener:
391
+ # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticloadbalancingv2-listener.html
392
+ Type: AWS::ElasticLoadBalancingV2::Listener
393
+ Properties:
394
+ DefaultActions:
395
+ - Type: forward
396
+ TargetGroupArn: !Ref FastAPITargetGroup
397
+ LoadBalancerArn: !Ref FastAPIALB
398
+ # Certificates:
399
+ # - CertificateArn: !Ref CertificateArn
400
+ Port: 8000
401
+ Protocol: HTTP
402
+ # FastAPIHTTPListener:
403
+ # # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticloadbalancingv2-listener.html
404
+ # Type: AWS::ElasticLoadBalancingV2::Listener
405
+ # Properties:
406
+ # Protocol: HTTP
407
+ # Port: 80
408
+ # LoadBalancerArn: !Ref FastAPIALB
409
+ # DefaultActions:
410
+ # - Type: redirect
411
+ # RedirectConfig:
412
+ # Protocol: "HTTPS"
413
+ # Port: 8000
414
+ # Host: "#{host}"
415
+ # Path: "/#{path}"
416
+ # Query: "#{query}"
417
+ # StatusCode: "HTTP_301"
418
+
419
+ # ECS Task Definitions
420
+ GradioTaskDefinition:
421
+ Type: AWS::ECS::TaskDefinition
422
+ Properties:
423
+ Family: !Sub ${Environment}-acres-gradio
424
+ RequiresCompatibilities:
425
+ - FARGATE
426
+ Cpu: !Ref GradioTaskDefinitionCPU
427
+ Memory: !Ref GradioTaskDefinitionMemory
428
+ NetworkMode: awsvpc
429
+ ExecutionRoleArn: !GetAtt GradioTaskExecutionRole.Arn
430
+ TaskRoleArn: !GetAtt GradioTaskRole.Arn
431
+ ContainerDefinitions:
432
+ - Name: gradio
433
+ Image: !Ref ContainerImageGradio
434
+ PortMappings:
435
+ - ContainerPort: 7860
436
+ LogConfiguration:
437
+ LogDriver: awslogs
438
+ Options:
439
+ awslogs-group: !Ref GradioLogGroup
440
+ awslogs-region: !Ref AWS::Region
441
+ awslogs-stream-prefix: gradio
442
+
443
+ FastAPITaskDefinition:
444
+ Type: AWS::ECS::TaskDefinition
445
+ Properties:
446
+ Family: !Sub ${Environment}-acres-fastapi
447
+ RequiresCompatibilities:
448
+ - FARGATE
449
+ Cpu: !Ref FastAPITaskDefinitionCPU
450
+ Memory: !Ref FastAPITaskDefinitionMemory
451
+ NetworkMode: awsvpc
452
+ ExecutionRoleArn: !GetAtt FastAPITaskExecutionRole.Arn
453
+ TaskRoleArn: !GetAtt FastAPITaskRole.Arn
454
+ ContainerDefinitions:
455
+ - Name: fastapi
456
+ Image: !Ref ContainerImageFastAPI
457
+ PortMappings:
458
+ - ContainerPort: 8000
459
+ Environment:
460
+ - Name: GRADIO_URL
461
+ Value: !Sub http://${GradioALB.DNSName}:7860/
462
+ LogConfiguration:
463
+ LogDriver: awslogs
464
+ Options:
465
+ awslogs-group: !Ref FastAPILogGroup
466
+ awslogs-region: !Ref AWS::Region
467
+ awslogs-stream-prefix: fastapi
468
+
469
+ # CloudWatch Log Groups
470
+ GradioLogGroup:
471
+ Type: AWS::Logs::LogGroup
472
+ Properties:
473
+ LogGroupName: !Sub /ecs/${Environment}-acres-gradio
474
+ RetentionInDays: 30
475
+
476
+ FastAPILogGroup:
477
+ Type: AWS::Logs::LogGroup
478
+ Properties:
479
+ LogGroupName: !Sub /ecs/${Environment}-acres-fastapi
480
+ RetentionInDays: 30
481
+
482
+
483
+ # ECS Services
484
+ GradioService:
485
+ Type: AWS::ECS::Service
486
+ DependsOn:
487
+ - GradioHTTPSListener
488
+ # - GradioHTTPListener
489
+ Properties:
490
+ ServiceName: !Sub ${Environment}-acres-gradio
491
+ Cluster: !Ref ECSCluster
492
+ TaskDefinition: !Ref GradioTaskDefinition
493
+ DesiredCount: 1
494
+ LaunchType: FARGATE
495
+ HealthCheckGracePeriodSeconds: 180
496
+ LoadBalancers:
497
+ - ContainerName: gradio
498
+ ContainerPort: 7860
499
+ TargetGroupArn: !Ref GradioTargetGroup
500
+ NetworkConfiguration:
501
+ AwsvpcConfiguration:
502
+ AssignPublicIp: ENABLED
503
+ SecurityGroups:
504
+ - !Ref GradioSecurityGroup
505
+ Subnets:
506
+ - !Ref PublicSubnet1
507
+ - !Ref PublicSubnet2
508
+ DeploymentConfiguration:
509
+ DeploymentCircuitBreaker:
510
+ Enable: true
511
+ Rollback: true
512
+ MaximumPercent: 200
513
+ MinimumHealthyPercent: 100
514
+
515
+ FastAPIService:
516
+ Type: AWS::ECS::Service
517
+ DependsOn:
518
+ - GradioService
519
+ - FastAPIHTTPSListener
520
+ # - FastAPIHTTPListener
521
+ Properties:
522
+ ServiceName: !Sub ${Environment}-acres-fastapi
523
+ Cluster: !Ref ECSCluster
524
+ TaskDefinition: !Ref FastAPITaskDefinition
525
+ DesiredCount: 1
526
+ LaunchType: FARGATE
527
+ HealthCheckGracePeriodSeconds: 180
528
+ LoadBalancers:
529
+ - ContainerName: fastapi
530
+ ContainerPort: 8000
531
+ TargetGroupArn: !Ref FastAPITargetGroup
532
+ NetworkConfiguration:
533
+ AwsvpcConfiguration:
534
+ AssignPublicIp: ENABLED
535
+ SecurityGroups:
536
+ - !Ref FastAPISecurityGroup
537
+ Subnets:
538
+ - !Ref PublicSubnet1
539
+ - !Ref PublicSubnet2
540
+ DeploymentConfiguration:
541
+ DeploymentCircuitBreaker:
542
+ Enable: true
543
+ Rollback: true
544
+ MaximumPercent: 200
545
+ MinimumHealthyPercent: 100
546
+ # Add deployment controller for better rollout control
547
+ DeploymentController:
548
+ Type: ECS
549
+
550
+ Outputs:
551
+ VpcId:
552
+ Description: VPC ID
553
+ Value: !Ref VPC
554
+
555
+ PublicSubnet1:
556
+ Description: Public Subnet 1
557
+ Value: !Ref PublicSubnet1
558
+
559
+ PublicSubnet2:
560
+ Description: Public Subnet 2
561
+ Value: !Ref PublicSubnet2
562
+
563
+ GradioServiceUrl:
564
+ Description: URL for the Gradio service
565
+ Value: !Sub http://${GradioALB.DNSName}:7860/
566
+
567
+ ECSClusterName:
568
+ Description: Name of the ECS cluster
569
+ Value: !Ref ECSCluster
570
+
571
+ GradioServiceName:
572
+ Description: Name of the Gradio service
573
+ Value: !GetAtt GradioService.Name
574
+
575
+ FastAPIServiceName:
576
+ Description: Name of the FastAPI service
577
+ Value: !GetAtt FastAPIService.Name
578
+
579
+ FastAPIServiceUrl:
580
+ Description: URL for the FastAPI service
581
+ Value: !Sub http://${FastAPIALB.DNSName}:8000/
pyproject.toml ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [tool.black]
2
+ include = '\.pyi?$'
3
+ exclude = '''
4
+ /(
5
+ \.git
6
+ | \.hg
7
+ | \.mypy_cache
8
+ | \.tox
9
+ | \.venv
10
+ | env
11
+ |venv
12
+ | _build
13
+ | buck-out
14
+ | build
15
+ | dist
16
+ | migrations
17
+ |alembic
18
+ )/
19
+ '''
rag/rag_pipeline.py CHANGED
@@ -1,19 +1,15 @@
1
  # rag/rag_pipeline.py
2
  import json
3
  import logging
4
- from typing import Dict, Any, List
 
5
 
6
- from llama_index.core import Document, VectorStoreIndex
7
- from llama_index.core.node_parser import SentenceWindowNodeParser, SentenceSplitter
8
- from llama_index.core import PromptTemplate
9
  from llama_index.embeddings.openai import OpenAIEmbedding
10
  from llama_index.llms.openai import OpenAI
11
  from llama_index.vector_stores.chroma import ChromaVectorStore
12
- import chromadb
13
- from typing import Dict, Any, List, Tuple, Optional
14
- import re
15
- import logging
16
-
17
 
18
  logging.basicConfig(level=logging.INFO)
19
  logger = logging.getLogger(__name__)
@@ -172,7 +168,6 @@ class RAGPipeline:
172
  self.extract_page_number_from_query(context) if self.is_pdf else None
173
  )
174
 
175
-
176
  # This is a hack to index all the documents in the store :)
177
  n_documents = len(self.index.docstore.docs)
178
  print(f"n_documents: {n_documents}")
 
1
  # rag/rag_pipeline.py
2
  import json
3
  import logging
4
+ import re
5
+ from typing import Any, Dict, List, Optional, Tuple
6
 
7
+ import chromadb
8
+ from llama_index.core import Document, PromptTemplate, VectorStoreIndex
9
+ from llama_index.core.node_parser import SentenceSplitter, SentenceWindowNodeParser
10
  from llama_index.embeddings.openai import OpenAIEmbedding
11
  from llama_index.llms.openai import OpenAI
12
  from llama_index.vector_stores.chroma import ChromaVectorStore
 
 
 
 
 
13
 
14
  logging.basicConfig(level=logging.INFO)
15
  logger = logging.getLogger(__name__)
 
168
  self.extract_page_number_from_query(context) if self.is_pdf else None
169
  )
170
 
 
171
  # This is a hack to index all the documents in the store :)
172
  n_documents = len(self.index.docstore.docs)
173
  print(f"n_documents: {n_documents}")
rag/rag_pipeline_backup.py CHANGED
@@ -1,9 +1,8 @@
1
  import json
2
- from typing import Dict, Any
3
- from llama_index.core import Document, VectorStoreIndex
4
- from llama_index.core.node_parser import SentenceWindowNodeParser, SentenceSplitter
5
- from llama_index.core import PromptTemplate
6
- from typing import List
7
  from llama_index.embeddings.openai import OpenAIEmbedding
8
  from llama_index.llms.openai import OpenAI
9
 
 
1
  import json
2
+ from typing import Any, Dict, List
3
+
4
+ from llama_index.core import Document, PromptTemplate, VectorStoreIndex
5
+ from llama_index.core.node_parser import SentenceSplitter, SentenceWindowNodeParser
 
6
  from llama_index.embeddings.openai import OpenAIEmbedding
7
  from llama_index.llms.openai import OpenAI
8
 
requirements-dev.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ black==24.10.0
2
+ isort==5.13.2
3
+ flake8==7.1.1
requirements.txt CHANGED
@@ -1,6 +1,7 @@
1
- chromadb==0.5.5
2
- fastapi==0.112.2
3
  gradio
 
4
  llama-index
5
  llama-index-vector-stores-chroma
6
  nest-asyncio==1.6.0
@@ -11,4 +12,6 @@ python-dotenv
11
  pyzotero
12
  python-slugify
13
  PyMuPDF==1.23.8
14
- Pillow==10.2.0
 
 
 
1
+ chromadb
2
+ fastapi
3
  gradio
4
+ gradio_client
5
  llama-index
6
  llama-index-vector-stores-chroma
7
  nest-asyncio==1.6.0
 
12
  pyzotero
13
  python-slugify
14
  PyMuPDF==1.23.8
15
+ Pillow==10.2.0
16
+ sqlmodel
17
+ cachetools
study_files.json CHANGED
@@ -1,8 +1,5 @@
1
  {
2
  "Vaccine coverage": "data/vaccine_coverage_zotero_items.json",
3
  "Ebola Virus": "data/ebola_virus_zotero_items.json",
4
- "GeneXpert": "data/gene_xpert_zotero_items.json",
5
- "Zotero Collection Pastan": "data/zotero-collection-pastan_zotero_items.json",
6
- "EBSCOhost": "data/ebscohost_zotero_items.json",
7
- "ExportedRis_file_1_of_1 (1)": "data/exportedris-file-1-of-1-1_zotero_items.json"
8
  }
 
1
  {
2
  "Vaccine coverage": "data/vaccine_coverage_zotero_items.json",
3
  "Ebola Virus": "data/ebola_virus_zotero_items.json",
4
+ "GeneXpert": "data/gene_xpert_zotero_items.json"
 
 
 
5
  }
utils/db.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:84acae8e51383d6990cd9edb7c1684292e523e7d0af87a71531bd5f9cf2909b5
3
+ size 4907
utils/helpers.py CHANGED
@@ -1,18 +1,18 @@
1
  # utils/helpers.py
2
 
3
- from typing import Dict, Any
 
 
 
 
4
  from llama_index.core import Response
5
- from typing import List
6
  from rag.rag_pipeline import RAGPipeline
7
  from utils.prompts import (
8
- structured_follow_up_prompt,
9
- VaccineCoverageVariables,
10
  StudyCharacteristics,
 
 
11
  )
12
- import json
13
- import json
14
- import chromadb
15
- from chromadb.api.types import Document
16
 
17
  # Initialize ChromaDB client
18
  chromadb_client = chromadb.Client()
 
1
  # utils/helpers.py
2
 
3
+ import json
4
+ from typing import Any, Dict, List
5
+
6
+ import chromadb
7
+ from chromadb.api.types import Document
8
  from llama_index.core import Response
9
+
10
  from rag.rag_pipeline import RAGPipeline
11
  from utils.prompts import (
 
 
12
  StudyCharacteristics,
13
+ VaccineCoverageVariables,
14
+ structured_follow_up_prompt,
15
  )
 
 
 
 
16
 
17
  # Initialize ChromaDB client
18
  chromadb_client = chromadb.Client()
utils/pdf_processor.py CHANGED
@@ -3,17 +3,17 @@ PDF processing module for ACRES RAG Platform.
3
  Handles PDF file processing, text extraction, and page rendering.
4
  """
5
 
6
- # utils/pdf_processor.py
7
- import os
8
- import fitz
9
- import logging
10
- from typing import Dict, List, Optional
11
  import datetime
12
- from slugify import slugify
13
  import json
14
- from PIL import Image
 
 
15
  import re
 
16
 
 
 
 
17
 
18
  logger = logging.getLogger(__name__)
19
 
 
3
  Handles PDF file processing, text extraction, and page rendering.
4
  """
5
 
 
 
 
 
 
6
  import datetime
 
7
  import json
8
+ import logging
9
+ # utils/pdf_processor.py
10
+ import os
11
  import re
12
+ from typing import Dict, List, Optional
13
 
14
+ import fitz
15
+ from PIL import Image
16
+ from slugify import slugify
17
 
18
  logger = logging.getLogger(__name__)
19
 
utils/prompts.py CHANGED
@@ -1,9 +1,10 @@
1
  # utils/prompts.py
2
 
 
 
3
  from llama_index.core import PromptTemplate
4
- from typing import Optional, List
5
- from pydantic import BaseModel, Field
6
  from llama_index.core.prompts import PromptTemplate
 
7
 
8
 
9
  class StudyCharacteristics(BaseModel):
 
1
  # utils/prompts.py
2
 
3
+ from typing import List, Optional
4
+
5
  from llama_index.core import PromptTemplate
 
 
6
  from llama_index.core.prompts import PromptTemplate
7
+ from pydantic import BaseModel, Field
8
 
9
 
10
  class StudyCharacteristics(BaseModel):