LeoNguyen101120 commited on
Commit
16f0db6
·
1 Parent(s): 60924bb

Refactor Dockerfile to copy all application files into the container; add .gitignore for IDE files; update main.py and image_service.py to use OUTPUT_DIR from config; streamline file handling in process_file_service.py; remove unused OpenAI client initialization; enhance vector_store_service.py with configuration constants for improved maintainability.

Browse files
.idea/.gitignore ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ # Default ignored files
2
+ /shelf/
3
+ /workspace.xml
Dockerfile CHANGED
@@ -43,8 +43,8 @@ RUN pip install --no-cache-dir --upgrade -r requirements.txt
43
  # Installs all Python dependencies listed in requirements.txt. --no-cache-dir reduces image size.
44
 
45
  # 6. Copy the rest of the application code
46
- COPY ./src ./src
47
- COPY ./README.md .
48
 
49
  # What is this?
50
  # Copies your source code and readme into the container.
@@ -54,6 +54,8 @@ EXPOSE 7860
54
 
55
  # What is this?
56
  # Documents that the container will listen on port 8080 (matches your uvicorn command).
 
 
57
 
58
  # 8. Set the default command to run the FastAPI app
59
  CMD ["fastapi", "run", "src/main.py", "--port", "7860"]
 
43
  # Installs all Python dependencies listed in requirements.txt. --no-cache-dir reduces image size.
44
 
45
  # 6. Copy the rest of the application code
46
+ # COPY ./src ./src
47
+ # COPY ./README.md .
48
 
49
  # What is this?
50
  # Copies your source code and readme into the container.
 
54
 
55
  # What is this?
56
  # Documents that the container will listen on port 8080 (matches your uvicorn command).
57
+ # Copy toàn bộ mã nguồn
58
+ COPY . .
59
 
60
  # 8. Set the default command to run the FastAPI app
61
  CMD ["fastapi", "run", "src/main.py", "--port", "7860"]
src/constants/config.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Device setup
2
+ import torch
3
+
4
+ TORCH_DEVICE = (
5
+ "cuda" if torch.cuda.is_available()
6
+ else "mps" if torch.backends.mps.is_available()
7
+ else "cpu"
8
+ )
9
+ IMAGE_MODEL_ID_OR_LINK = "stable-diffusion-v1-5/stable-diffusion-v1-5"
10
+ CACHE_DIR = "/tmp/cache"
11
+ DATA_DIR = "/tmp/data"
12
+ EMBEDDING_MODEL = "intfloat/multilingual-e5-large-instruct"
13
+ UPLOAD_DIR = "/tmp/uploads"
14
+ OUTPUT_DIR = "/tmp/outputs"
15
+ # EMBEDDING_MODEL = "sentence-transformers/all-MiniLM-L6-v2"
src/main.py CHANGED
@@ -4,6 +4,7 @@ from fastapi.exceptions import RequestValidationError
4
  from fastapi.middleware.cors import CORSMiddleware
5
  from fastapi.responses import JSONResponse
6
  from fastapi.staticfiles import StaticFiles
 
7
  from models.responses.base_response import BaseResponse
8
  from routes import chat_routes, process_file_routes, vector_store_routes
9
  from utils.exception import CustomException
@@ -48,5 +49,5 @@ app.include_router(vector_store_routes.router, prefix="/api/v1")
48
  def read_root():
49
  return {"message": "Welcome my API"}
50
 
51
- os.makedirs("outputs", exist_ok=True)
52
- app.mount("/outputs", StaticFiles(directory="outputs"), name="outputs")
 
4
  from fastapi.middleware.cors import CORSMiddleware
5
  from fastapi.responses import JSONResponse
6
  from fastapi.staticfiles import StaticFiles
7
+ from constants.config import OUTPUT_DIR
8
  from models.responses.base_response import BaseResponse
9
  from routes import chat_routes, process_file_routes, vector_store_routes
10
  from utils.exception import CustomException
 
49
  def read_root():
50
  return {"message": "Welcome my API"}
51
 
52
+ os.makedirs(OUTPUT_DIR, exist_ok=True)
53
+ app.mount(OUTPUT_DIR, StaticFiles(directory=OUTPUT_DIR), name="outputs")
src/services/chat_service.py CHANGED
@@ -3,8 +3,6 @@ from models.requests.chat_request import ChatRequest
3
  from services import vector_store_service
4
  from utils.timing import measure_time
5
  from utils.tools import tools_helper, tools_define
6
- from utils.client import openai_client
7
-
8
 
9
  def build_context_prompt(request: ChatRequest) -> list:
10
  """Build system prompt with context if file is provided."""
 
3
  from services import vector_store_service
4
  from utils.timing import measure_time
5
  from utils.tools import tools_helper, tools_define
 
 
6
 
7
  def build_context_prompt(request: ChatRequest) -> list:
8
  """Build system prompt with context if file is provided."""
src/services/image_service.py CHANGED
@@ -1,5 +1,6 @@
1
  import os
2
  import time
 
3
  from utils import image_pipeline
4
 
5
  negative_promt = "blurry, distorted, pixelated, incomplete, poorly drawn, misaligned, weird proportions, bad perspective, unnatural colors, noisy, out of focus, glitchy, unsharp, overexposed, underexposed, poorly lit, bad composition, excessive noise, oversaturated, too dark, too bright, inconsistent lighting, discolored, overly stylized, unrealistic, awkward pose, unbalanced, mismatched, distorted features, flat, unnatural texture, chaotic, unreadable, incoherent, asymmetrical, low quality, lowres, wrong anatomy, bad anatomy, deformed, disfigured, ugly"
@@ -8,7 +9,7 @@ height = 512
8
  guidance_scale = 7.5
9
  num_inference_steps = 30
10
 
11
- base_url = "http://localhost:8000"
12
 
13
  def generate_image_url(prompt: str) -> str:
14
  """
@@ -16,8 +17,7 @@ def generate_image_url(prompt: str) -> str:
16
  :param prompt: The prompt used for generate the image (must be in English)
17
  :output: URL of the new image
18
  """
19
- output_dir = "outputs"
20
- os.makedirs(output_dir, exist_ok=True)
21
  try:
22
  image = image_pipeline.pipeline(
23
  prompt=prompt,
@@ -29,9 +29,9 @@ def generate_image_url(prompt: str) -> str:
29
  ).images[0]
30
 
31
  file_name = f"image_{int(time.time())}.png"
32
- image_path = os.path.join(output_dir, file_name)
33
  image.save(image_path)
34
 
35
- return f"{base_url}/outputs/{file_name}"
36
  except Exception as e:
37
  raise RuntimeError(f"Failed to generate image: {e}")
 
1
  import os
2
  import time
3
+ from constants.config import OUTPUT_DIR
4
  from utils import image_pipeline
5
 
6
  negative_promt = "blurry, distorted, pixelated, incomplete, poorly drawn, misaligned, weird proportions, bad perspective, unnatural colors, noisy, out of focus, glitchy, unsharp, overexposed, underexposed, poorly lit, bad composition, excessive noise, oversaturated, too dark, too bright, inconsistent lighting, discolored, overly stylized, unrealistic, awkward pose, unbalanced, mismatched, distorted features, flat, unnatural texture, chaotic, unreadable, incoherent, asymmetrical, low quality, lowres, wrong anatomy, bad anatomy, deformed, disfigured, ugly"
 
9
  guidance_scale = 7.5
10
  num_inference_steps = 30
11
 
12
+ base_url = "http://0.0.0.0:7860"
13
 
14
  def generate_image_url(prompt: str) -> str:
15
  """
 
17
  :param prompt: The prompt used for generate the image (must be in English)
18
  :output: URL of the new image
19
  """
20
+ os.makedirs(OUTPUT_DIR, exist_ok=True)
 
21
  try:
22
  image = image_pipeline.pipeline(
23
  prompt=prompt,
 
29
  ).images[0]
30
 
31
  file_name = f"image_{int(time.time())}.png"
32
+ image_path = os.path.join(OUTPUT_DIR, file_name)
33
  image.save(image_path)
34
 
35
+ return f"{base_url}/{OUTPUT_DIR}/{file_name}"
36
  except Exception as e:
37
  raise RuntimeError(f"Failed to generate image: {e}")
src/services/process_file_service.py CHANGED
@@ -6,12 +6,10 @@ from PIL import Image
6
  import pytesseract
7
  from langchain_community.document_loaders import PyMuPDFLoader
8
  from langchain_text_splitters import RecursiveCharacterTextSplitter
 
9
  from constants.file_type import FileType
10
  from services import vector_store_service
11
 
12
- UPLOAD_DIR = "uploads"
13
- os.makedirs(UPLOAD_DIR, exist_ok=True)
14
-
15
  def save_file(file):
16
  ext = os.path.splitext(file.filename)[-1].lstrip(".")
17
  file_id = str(uuid.uuid4())
 
6
  import pytesseract
7
  from langchain_community.document_loaders import PyMuPDFLoader
8
  from langchain_text_splitters import RecursiveCharacterTextSplitter
9
+ from constants.config import UPLOAD_DIR
10
  from constants.file_type import FileType
11
  from services import vector_store_service
12
 
 
 
 
13
  def save_file(file):
14
  ext = os.path.splitext(file.filename)[-1].lstrip(".")
15
  file_id = str(uuid.uuid4())
src/services/vector_store_service.py CHANGED
@@ -1,17 +1,10 @@
1
  from chromadb import PersistentClient
2
  from langchain_chroma import Chroma
3
  from langchain_huggingface import HuggingFaceEmbeddings
4
- import torch
5
 
6
- client = PersistentClient(path="/data")
7
- # EMBEDDING_MODEL = "intfloat/multilingual-e5-large-instruct"
8
- EMBEDDING_MODEL = "sentence-transformers/all-MiniLM-L6-v2"
9
- _device = (
10
- "cuda" if torch.cuda.is_available()
11
- else "mps" if torch.backends.mps.is_available()
12
- else "cpu"
13
- )
14
- embeddings_function = HuggingFaceEmbeddings(model_name=EMBEDDING_MODEL, model_kwargs={'device': _device})
15
  vector_store = {}
16
 
17
  def get_all_collections_id():
@@ -25,7 +18,7 @@ def inspect_collection(collection_id: str):
25
  def get_vector_store(collection_name) -> Chroma:
26
  if collection_name not in vector_store:
27
  vector_store[collection_name] = Chroma(
28
- persist_directory="./data",
29
  collection_name=collection_name,
30
  embedding_function=embeddings_function,
31
  )
 
1
  from chromadb import PersistentClient
2
  from langchain_chroma import Chroma
3
  from langchain_huggingface import HuggingFaceEmbeddings
4
+ from constants.config import DATA_DIR, EMBEDDING_MODEL, TORCH_DEVICE
5
 
6
+ client = PersistentClient(path=DATA_DIR)
7
+ embeddings_function = HuggingFaceEmbeddings(model_name=EMBEDDING_MODEL, model_kwargs={'device': TORCH_DEVICE})
 
 
 
 
 
 
 
8
  vector_store = {}
9
 
10
  def get_all_collections_id():
 
18
  def get_vector_store(collection_name) -> Chroma:
19
  if collection_name not in vector_store:
20
  vector_store[collection_name] = Chroma(
21
+ persist_directory=DATA_DIR,
22
  collection_name=collection_name,
23
  embedding_function=embeddings_function,
24
  )
src/utils/client.py CHANGED
@@ -1,8 +1,4 @@
1
  import openai
2
- from dotenv import load_dotenv
3
-
4
- # Load environment variables
5
- load_dotenv()
6
 
7
  # Initialize OpenAI API client
8
  openai_client = openai.OpenAI(
 
1
  import openai
 
 
 
 
2
 
3
  # Initialize OpenAI API client
4
  openai_client = openai.OpenAI(
src/utils/image_pipeline.py CHANGED
@@ -1,14 +1,8 @@
1
  import torch
2
  from diffusers import StableDiffusionPipeline
 
3
 
4
- # Device setup
5
- _device = (
6
- "cuda" if torch.cuda.is_available()
7
- else "mps" if torch.backends.mps.is_available()
8
- else "cpu"
9
- )
10
  torch.backends.cuda.matmul.allow_tf32 = True # Enable TF32 for performance on CUDA
11
- _model_id_or_link = "stable-diffusion-v1-5/stable-diffusion-v1-5"
12
 
13
  _pipeline = None
14
 
@@ -17,20 +11,20 @@ def get_pipeline() -> StableDiffusionPipeline:
17
  if _pipeline is None:
18
  try:
19
  _pipeline = StableDiffusionPipeline.from_pretrained(
20
- _model_id_or_link,
21
  torch_dtype=torch.bfloat16,
22
  variant="fp16",
23
  # safety_checker=True,
24
  use_safetensors=True,
25
  )
26
  # _pipeline = StableDiffusionPipeline.from_single_file(
27
- # _model_id_or_link,
28
  # torch_dtype=torch.bfloat16,
29
  # variant="fp16",
30
  # # safety_checker=True,
31
  # use_safetensors=True,
32
  # )
33
- _pipeline.to(_device)
34
  except Exception as e:
35
  raise RuntimeError(f"Failed to load the model: {e}")
36
  return _pipeline
 
1
  import torch
2
  from diffusers import StableDiffusionPipeline
3
+ from constants.config import IMAGE_MODEL_ID_OR_LINK, TORCH_DEVICE
4
 
 
 
 
 
 
 
5
  torch.backends.cuda.matmul.allow_tf32 = True # Enable TF32 for performance on CUDA
 
6
 
7
  _pipeline = None
8
 
 
11
  if _pipeline is None:
12
  try:
13
  _pipeline = StableDiffusionPipeline.from_pretrained(
14
+ IMAGE_MODEL_ID_OR_LINK,
15
  torch_dtype=torch.bfloat16,
16
  variant="fp16",
17
  # safety_checker=True,
18
  use_safetensors=True,
19
  )
20
  # _pipeline = StableDiffusionPipeline.from_single_file(
21
+ # IMAGE_MODEL_ID_OR_LINK,
22
  # torch_dtype=torch.bfloat16,
23
  # variant="fp16",
24
  # # safety_checker=True,
25
  # use_safetensors=True,
26
  # )
27
+ _pipeline.to(TORCH_DEVICE)
28
  except Exception as e:
29
  raise RuntimeError(f"Failed to load the model: {e}")
30
  return _pipeline