CooLLegend commited on
Commit
02f8392
·
1 Parent(s): e1c2128

Added fashionclip model

Browse files
Files changed (4) hide show
  1. .vscode/settings.json +4 -0
  2. Dockerfile +6 -3
  3. app.py +38 -41
  4. requirements.txt +3 -2
.vscode/settings.json ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ {
2
+ "python-envs.defaultEnvManager": "ms-python.python:conda",
3
+ "python-envs.defaultPackageManager": "ms-python.python:conda"
4
+ }
Dockerfile CHANGED
@@ -7,9 +7,12 @@ WORKDIR /app
7
  COPY requirements.txt .
8
  RUN pip install --no-cache-dir -r requirements.txt
9
 
10
- # 4. Pre-download the model during the build process
11
  # (This prevents the app from timing out when it first starts up)
12
- RUN python -c "from sentence_transformers import SentenceTransformer; SentenceTransformer('clip-ViT-B-32')"
 
 
 
13
 
14
  # 5. Copy the rest of the application code
15
  COPY . .
@@ -21,4 +24,4 @@ ENV HOME=/home/user \
21
  PATH=/home/user/.local/bin:$PATH
22
 
23
  # 7. Start the application
24
- CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
 
7
  COPY requirements.txt .
8
  RUN pip install --no-cache-dir -r requirements.txt
9
 
10
+ # 4. Pre-download the Fashion-CLIP model during the build process
11
  # (This prevents the app from timing out when it first starts up)
12
+ RUN python -c "from transformers import CLIPModel, CLIPProcessor; \
13
+ model = CLIPModel.from_pretrained('patrickjohncyh/fashion-clip'); \
14
+ processor = CLIPProcessor.from_pretrained('patrickjohncyh/fashion-clip'); \
15
+ print('Fashion-CLIP model preloaded!')"
16
 
17
  # 5. Copy the rest of the application code
18
  COPY . .
 
24
  PATH=/home/user/.local/bin:$PATH
25
 
26
  # 7. Start the application
27
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
app.py CHANGED
@@ -1,81 +1,78 @@
1
  from fastapi import FastAPI, HTTPException
2
  from pydantic import BaseModel
3
- from sentence_transformers import SentenceTransformer
4
  from PIL import Image
5
  import requests
6
  from io import BytesIO
7
- import numpy as np
8
 
9
  # 1. Initialize the App
10
  app = FastAPI()
11
 
12
- # 2. Load the Model
13
- # We use 'clip-ViT-B-32'. It is small, fast, and excellent for connecting text/images.
14
  # This runs ONCE when the server starts.
15
- print("Loading Model...")
16
- model = SentenceTransformer('clip-ViT-B-32')
17
- tokenizer = model.tokenizer
 
18
  print("Model Loaded!")
19
 
20
- # 3. Define chunking parameters
21
- CHUNK_SIZE = 50 # tokens per chunk (CLIP has 77 token limit)
22
-
23
- # 4. Define Input Data Structures
24
  class TextRequest(BaseModel):
25
  text: str
26
 
27
  class ImageRequest(BaseModel):
28
  image_url: str
29
 
30
- # 5. The Home Route (Health Check)
31
  @app.get("/")
32
  def home():
33
- return {"status": "Online", "message": "Send POST requests to /embed-text or /embed-image"}
34
 
35
- # 6. Endpoint: Convert Text to Vector
36
  @app.post("/embed-text")
37
  def embed_text(req: TextRequest):
38
  try:
39
- # A. Tokenize the input text
40
- tokens = tokenizer.encode(req.text)
41
- num_tokens = len(tokens)
42
-
43
- # B. If text fits within chunk size, use direct embedding
44
- if num_tokens <= CHUNK_SIZE:
45
- embedding = model.encode(req.text).tolist()
46
- return {"vector": embedding}
47
 
48
- # C. Split tokens into chunks of CHUNK_SIZE
49
- chunks = []
50
- for i in range(0, num_tokens, CHUNK_SIZE):
51
- chunk_tokens = tokens[i:i + CHUNK_SIZE]
52
- chunk_text = tokenizer.decode(chunk_tokens)
53
- chunks.append(chunk_text)
54
 
55
- # D. Generate embeddings for each chunk
56
- chunk_embeddings = model.encode(chunks)
57
 
58
- # E. Average all chunk embeddings
59
- avg_embedding = np.mean(chunk_embeddings, axis=0).tolist()
60
-
61
- return {"vector": avg_embedding}
62
  except Exception as e:
63
  raise HTTPException(status_code=500, detail=str(e))
64
 
65
- # 7. Endpoint: Convert Image URL to Vector
66
  @app.post("/embed-image")
67
  def embed_image(req: ImageRequest):
68
  try:
69
- # A. Download the image from Cloudinary/Web
70
  response = requests.get(req.image_url)
71
  if response.status_code != 200:
72
  raise HTTPException(status_code=400, detail="Could not download image")
73
 
74
- # B. Open image in memory (don't save to disk)
75
  image = Image.open(BytesIO(response.content))
 
 
 
76
 
77
- # C. Generate Vector
78
- embedding = model.encode(image).tolist()
79
- return {"vector": embedding}
 
 
 
 
 
 
 
80
  except Exception as e:
81
- raise HTTPException(status_code=500, detail=str(e))
 
1
  from fastapi import FastAPI, HTTPException
2
  from pydantic import BaseModel
3
+ from transformers import CLIPProcessor, CLIPModel
4
  from PIL import Image
5
  import requests
6
  from io import BytesIO
7
+ import torch
8
 
9
  # 1. Initialize the App
10
  app = FastAPI()
11
 
12
+ # 2. Load the Fashion-CLIP Model
13
+ # We use 'CLIPModel' directly to get access to the vector layers.
14
  # This runs ONCE when the server starts.
15
+ print("Loading Fashion-CLIP Model...")
16
+ model_id = "patrickjohncyh/fashion-clip"
17
+ model = CLIPModel.from_pretrained(model_id)
18
+ processor = CLIPProcessor.from_pretrained(model_id)
19
  print("Model Loaded!")
20
 
21
+ # 3. Define Input Data Structures
 
 
 
22
  class TextRequest(BaseModel):
23
  text: str
24
 
25
  class ImageRequest(BaseModel):
26
  image_url: str
27
 
28
+ # 4. The Home Route (Health Check)
29
  @app.get("/")
30
  def home():
31
+ return {"status": "Online", "model": "Fashion-CLIP"}
32
 
33
+ # 5. Endpoint: Convert Text to Vector
34
  @app.post("/embed-text")
35
  def embed_text(req: TextRequest):
36
  try:
37
+ # Process text
38
+ inputs = processor(text=[req.text], return_tensors="pt", padding=True)
 
 
 
 
 
 
39
 
40
+ # Calculate features
41
+ with torch.no_grad(): # Disable gradient calculation for CPU speed
42
+ text_features = model.get_text_features(**inputs)
 
 
 
43
 
44
+ # Normalize the vector (Crucial for Cosine Similarity!)
45
+ text_features = text_features / text_features.norm(p=2, dim=-1, keepdim=True)
46
 
47
+ # Convert to standard Python list
48
+ vector = text_features[0].tolist()
49
+ return {"vector": vector}
 
50
  except Exception as e:
51
  raise HTTPException(status_code=500, detail=str(e))
52
 
53
+ # 6. Endpoint: Convert Image URL to Vector
54
  @app.post("/embed-image")
55
  def embed_image(req: ImageRequest):
56
  try:
57
+ # Download image
58
  response = requests.get(req.image_url)
59
  if response.status_code != 200:
60
  raise HTTPException(status_code=400, detail="Could not download image")
61
 
 
62
  image = Image.open(BytesIO(response.content))
63
+
64
+ # Process image
65
+ inputs = processor(images=image, return_tensors="pt", padding=True)
66
 
67
+ # Calculate features
68
+ with torch.no_grad(): # Disable gradient calculation for CPU speed
69
+ image_features = model.get_image_features(**inputs)
70
+
71
+ # Normalize the vector (Crucial for Cosine Similarity!)
72
+ image_features = image_features / image_features.norm(p=2, dim=-1, keepdim=True)
73
+
74
+ # Convert to standard Python list
75
+ vector = image_features[0].tolist()
76
+ return {"vector": vector}
77
  except Exception as e:
78
+ raise HTTPException(status_code=500, detail=str(e))
requirements.txt CHANGED
@@ -1,6 +1,7 @@
1
  fastapi
2
  uvicorn
3
- sentence-transformers
 
4
  requests
5
  Pillow
6
- pydantic
 
1
  fastapi
2
  uvicorn
3
+ transformers
4
+ torch
5
  requests
6
  Pillow
7
+ pydantic