Patrick Walukagga commited on
Commit
d3abbf7
·
1 Parent(s): 0b74ad1

Dockerize app and add aws infrastructure

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
.gitignore CHANGED
@@ -173,5 +173,7 @@ 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
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,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 8000
66
+
67
+ # Command to run the FastAPI app
68
+ 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"]
app.py CHANGED
@@ -15,6 +15,7 @@ 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
@@ -23,6 +24,7 @@ from utils.helpers import (
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
 
@@ -39,9 +41,25 @@ 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 +79,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 +142,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 +154,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 +165,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 +220,16 @@ 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 +237,25 @@ 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 +359,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 +369,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 +395,24 @@ 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 +482,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 +500,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):
 
15
  import openai
16
  from dotenv import load_dotenv
17
  from slugify import slugify
18
+ from cachetools import LRUCache
19
 
20
  from config import STUDY_FILES, OPENAI_API_KEY
21
  from rag.rag_pipeline import RAGPipeline
 
24
  add_study_files_to_chromadb,
25
  chromadb_client,
26
  )
27
+ from utils.db import create_db_and_tables, add_study_files_to_db, get_study_file_by_name, get_study_files_by_library_id, get_all_study_files
28
  from utils.prompts import highlight_prompt, evidence_based_prompt
29
  from utils.zotero_manager import ZoteroManager
30
 
 
41
  # Initialize ChromaDB with study files
42
  add_study_files_to_chromadb("study_files.json", "study_files_collection")
43
 
44
+ # Create sqlite study file data table
45
+ create_db_and_tables()
46
+
47
+
48
  # Cache for RAG pipelines
49
  rag_cache = {}
50
 
51
+ cache = LRUCache(maxsize=100)
52
+
53
+ # with open("study_files.json", "w") as file:
54
+ # data_ = {}
55
+ # json.dump(data_, file, indent=4)
56
+
57
+ def get_cache_value(key):
58
+ return cache.get(key)
59
+
60
+ zotero_library_id = get_cache_value("zotero_library_id")
61
+ logger.info(f"zotero_library_id: ======> {zotero_library_id}")
62
+
63
 
64
  def get_rag_pipeline(study_name: str) -> RAGPipeline:
65
  """Get or create a RAGPipeline instance for the given study by querying ChromaDB."""
 
79
  return rag_cache[study_name]
80
 
81
 
82
+ def get_study_info(study_name: str | list) -> str:
83
  """Retrieve information about the specified study."""
84
+ if isinstance(study_name, list):
85
+ study_name = study_name[0] if study_name else None
86
+
87
+ if not study_name:
88
+ return "No study selected"
89
+
90
+ study = get_study_file_by_name(study_name)
91
+ logger.info(f"Study: ======> {study}")
92
 
93
  collection = chromadb_client.get_or_create_collection("study_files_collection")
94
  result = collection.get(ids=[study_name]) # Query by study name (as a list)
95
+ logger.info(f"Result: ======> {result}")
96
 
97
  if not result or len(result["metadatas"]) == 0:
98
  raise ValueError(f"Invalid study name: {study_name}")
99
 
100
  study_file = result["metadatas"][0].get("file_path")
101
+ logger.info(f"study_file: =======> {study_file}")
102
  if not study_file:
103
  raise ValueError(f"File path not found for study name: {study_name}")
104
 
 
142
  try:
143
  os.remove(file)
144
  except Exception as e:
145
+ logger.warning(f"Failed to remove temp file {file}: {e}")
146
  except Exception as e:
147
+ logger.warning(f"Error during cleanup: {e}")
148
 
149
 
150
  def chat_function(message: str, study_name: str, prompt_type: str) -> str:
 
154
  return "Please enter a valid query."
155
 
156
  rag = get_rag_pipeline(study_name)
157
+ logger.info(f"rag: ==> {rag}")
158
  prompt = {
159
  "Highlight": highlight_prompt,
160
  "Evidence-based": evidence_based_prompt,
 
165
 
166
 
167
  def process_zotero_library_items(
168
+ zotero_library_id_param: str, zotero_api_access_key: str
169
  ) -> str:
170
+ global zotero_library_id
171
+ if not zotero_library_id_param or not zotero_api_access_key:
172
  return "Please enter your zotero library Id and API Access Key"
173
 
174
+ zotero_library_id = zotero_library_id_param
175
+ cache["zotero_library_id"] = zotero_library_id
176
  zotero_library_type = "user" # or "group"
177
  zotero_api_access_key = zotero_api_access_key
178
 
 
220
 
221
  # Update in-memory STUDY_FILES for reference in current session
222
  STUDY_FILES.update({collection_name: f"data/{export_file}"})
223
+ logger.info(f"STUDY_FILES: {STUDY_FILES}")
224
 
225
  # After loop, add all collected data to ChromaDB
226
  add_study_files_to_chromadb("study_files.json", "study_files_collection")
227
+ # Add collected data to sqlite
228
+ add_study_files_to_db("study_files.json", zotero_library_id)
229
+
230
+ # Dynamically update study choices
231
+ global study_choices
232
+ study_choices = [file.name for file in get_study_files_by_library_id([zotero_library_id])]
233
  message = "Successfully processed items in your zotero library"
234
  except Exception as e:
235
  message = f"Error process your zotero library: {str(e)}"
 
237
  return message
238
 
239
 
240
+ def refresh_study_choices():
241
+ """
242
+ Refresh study choices for a specific dropdown instance.
243
+
244
+ :return: Updated Dropdown with current study choices
245
+ """
246
+ global study_choices
247
+ zotero_library_id = get_cache_value("zotero_library_id")
248
+ logger.info(f"zotero_library_id: ====> {zotero_library_id}")
249
+ study_choices = [file.name for file in get_study_files_by_library_id([zotero_library_id])]
250
+ logger.info(f"Study choices: ====> {study_choices}")
251
+ return study_choices
252
+
253
+
254
  def process_multi_input(text, study_name, prompt_type):
255
  # Split input based on commas and strip any extra spaces
256
  variable_list = [word.strip().upper() for word in text.split(",")]
257
  user_message = f"Extract and present in a tabular format the following variables for each {study_name} study: {', '.join(variable_list)}"
258
+ logger.info(f"User message: ==> {user_message}")
259
  response = chat_function(user_message, study_name, prompt_type)
260
  return [response, gr.update(visible=True)]
261
 
 
359
 
360
  def create_gr_interface() -> gr.Blocks:
361
  """Create and configure the Gradio interface for the RAG platform."""
362
+ global zotero_library_id
363
+ with gr.Blocks(theme=gr.themes.Base()) as demo:
364
  gr.Markdown("# ACRES RAG Platform")
365
 
366
  with gr.Tabs() as tabs:
 
369
  with gr.Row():
370
  with gr.Column(scale=1):
371
  gr.Markdown("### Zotero Credentials")
372
+ zotero_library_id_param = gr.Textbox(
373
  label="Zotero Library ID",
374
  type="password",
375
  placeholder="Enter Your Zotero Library ID here...",
 
395
  if all_documents
396
  ]
397
 
398
+ print(f"zotero_library_id: {zotero_library_id_param.value}")
399
+ zotero_library_id = zotero_library_id_param.value
400
+ if zotero_library_id is None:
401
+ zotero_library_id = get_cache_value("zotero_library_id")
402
+ logger.info(f"zotero_library_id: =====> {zotero_library_id}")
403
+ study_choices_db = get_study_files_by_library_id([zotero_library_id])
404
+ logger.info(f"study_choices_db: =====> {study_choices_db}")
405
+ study_files = get_all_study_files()
406
+ logger.info(f"study_files: =====> {study_files}")
407
+
408
  study_dropdown = gr.Dropdown(
409
  choices=study_choices,
410
  label="Select Study",
411
  value=(study_choices[0] if study_choices else None),
412
  )
413
+ # In Gradio interface setup
414
+ refresh_button = gr.Button("Refresh Studies")
415
+
416
  study_info = gr.Markdown(label="Study Details")
417
  prompt_type = gr.Radio(
418
  ["Default", "Highlight", "Evidence-based"],
 
482
  # Event handlers for Study Analysis tab
483
  process_zotero_btn.click(
484
  process_zotero_library_items,
485
+ inputs=[zotero_library_id_param, zotero_api_access_key],
486
  outputs=[zotero_output],
487
  )
488
 
 
500
  fn=download_as_csv, inputs=[answer_output], outputs=[download_btn]
501
  ).then(fn=cleanup_temp_files, inputs=None, outputs=None)
502
 
503
+ refresh_button.click(
504
+ fn=refresh_study_choices,
505
+ outputs=[study_dropdown] # Update the same dropdown
506
+ )
507
+
508
  # Event handlers for PDF Chat tab
509
 
510
  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,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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=224427659724
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
+
33
+ docker build -f Dockerfile.gradio.prod -t gradio-app-prod .
34
+ docker tag gradio-app-prod:latest "${ECR_BACKEND_GRADIO_URL}:latest"
35
+ docker push "${ECR_BACKEND_GRADIO_URL}:latest"
36
+
37
+
38
+ docker build -f Dockerfile.api -t fastapi-app .
39
+ docker run -it -p 8000:8000 --rm --name fastapi --network=gradio-fastapi-network fastapi-app
40
+
41
+ aws ecr create-repository \
42
+ --repository-name fastapi-api-prod \
43
+ --image-tag-mutability MUTABLE
44
+
45
+ export ECR_BACKEND_FASTAPI_URL="$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/fastapi-api-prod"
46
+ echo $ECR_BACKEND_FASTAPI_URL
47
+
48
+ docker build -f Dockerfile.api.prod -t fastapi-api-prod .
49
+ docker tag fastapi-api-prod:latest "${ECR_BACKEND_FASTAPI_URL}:latest"
50
+ docker push "${ECR_BACKEND_FASTAPI_URL}:latest"
51
+
52
+
53
+ Now how can I configure the two load balancers such that I can just access them without providing the ports
54
+
55
+ fastapi
56
+
57
+
58
+ ```
59
+ http://dev-acres-fastapi-alb-1793670355.us-east-1.elb.amazonaws.com:8000/
60
+ ```
61
+
62
+ http://dev-acres-gradio-alb-1860302806.us-east-1.elb.amazonaws.com/
63
+
64
+ gradio
65
+
66
+
67
+ ```
68
+ http://dev-acres-gradio-alb-1860302806.us-east-1.elb.amazonaws.com:7860/
69
+ ```
infra/ecs_config.toml ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ [deploy]
2
+ bucket = 'dev-acres-gradio-bucket'
3
+ region = 'us-east-1'
4
+ stack_name = 'AcresRag'
5
+
6
+ [parameters]
7
+ ContainerImageGradio = '224427659724.dkr.ecr.us-east-1.amazonaws.com/gradio-app-prod:latest'
8
+ ContainerImageFastAPI = '224427659724.dkr.ecr.us-east-1.amazonaws.com/fastapi-api-prod:latest'
9
+ CertificateArn = 'arn:aws:acm:us-east-1:224427659724:certificate/37ae35a9-60d1-4ff2-8afc-07f0d6000e75'
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/
requirements.txt CHANGED
@@ -1,5 +1,5 @@
1
- chromadb==0.5.5
2
- fastapi==0.112.2
3
  gradio
4
  gradio_client
5
  llama-index
@@ -12,4 +12,6 @@ python-dotenv
12
  pyzotero
13
  python-slugify
14
  PyMuPDF==1.23.8
15
- Pillow==10.2.0
 
 
 
1
+ chromadb
2
+ fastapi
3
  gradio
4
  gradio_client
5
  llama-index
 
12
  pyzotero
13
  python-slugify
14
  PyMuPDF==1.23.8
15
+ Pillow==10.2.0
16
+ sqlmodel
17
+ cachetools
study_files.json CHANGED
@@ -1,10 +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
- "wb_1813-9450-6689": "data/wb-1813-9450-6689_zotero_items.json",
9
- "kayongo papers": "data/kayongo-papers_zotero_items.json"
10
  }
 
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
  }