ChandraP12330 commited on
Commit
8608da2
·
verified ·
1 Parent(s): d5d2a40

Upload 4 files

Browse files
Files changed (4) hide show
  1. Dockerfile +27 -0
  2. fastapi_app.py +58 -0
  3. llm_backend.py +51 -0
  4. pyproject.toml +12 -0
Dockerfile ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use a lightweight Python image
2
+ FROM python:3.12-slim
3
+
4
+ # Install uv from the official image
5
+ COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
6
+
7
+ # Set working directory
8
+ WORKDIR /app
9
+
10
+ # Copy pyproject.toml to install dependencies first (caching)
11
+ COPY pyproject.toml .
12
+
13
+ # Install dependencies using uv sync
14
+ # This creates a virtual environment at /app/.venv
15
+ RUN uv sync --no-install-project
16
+
17
+ # Add the virtual environment to the PATH
18
+ ENV PATH="/app/.venv/bin:$PATH"
19
+
20
+ # Copy the rest of the application code
21
+ COPY . .
22
+
23
+ # Expose the port the app runs on
24
+ EXPOSE 8000
25
+
26
+ # Command to run the application
27
+ CMD ["uvicorn", "fastapi_app:app", "--host", "0.0.0.0", "--port", "8000"]
fastapi_app.py ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #fastapi_app.py
2
+ from fastapi import FastAPI, HTTPException
3
+ from fastapi.middleware.cors import CORSMiddleware
4
+ from pydantic import BaseModel
5
+ from llm_backend import process_shelf_image
6
+ import uvicorn
7
+ import os
8
+
9
+ app = FastAPI(title="Retail Shelf Analyzer API")
10
+
11
+ # Add CORS middleware
12
+ app.add_middleware(
13
+ CORSMiddleware,
14
+ allow_origins=["*"], # Allows all origins
15
+ allow_credentials=True,
16
+ allow_methods=["*"], # Allows all methods
17
+ allow_headers=["*"], # Allows all headers
18
+ )
19
+
20
+ class ImageRequest(BaseModel):
21
+ image_url: str
22
+
23
+ @app.get("/", summary="Health Check", tags=["System"])
24
+ def read_root():
25
+ """
26
+ Checks if the API is running and reachable.
27
+
28
+ Returns:
29
+ dict: A simple message confirming the API status.
30
+ """
31
+ return {"message": "Retail Shelf Analyzer API is running"}
32
+
33
+ @app.post("/analyze_shelf", summary="Analyze Retail Shelf Image", tags=["Shelf Analysis"])
34
+ def analyze_shelf(request: ImageRequest):
35
+ """
36
+ Analyzes a retail shelf image to extract product information.
37
+
38
+ This endpoint accepts an image URL, processes it using a Generative AI model,
39
+ and returns a structured Markdown table containing:
40
+ - **ID**: Unique identifier for each item.
41
+ - **Product_SKU**: Identified product name or type.
42
+ - **Shelf_ID**: Shelf location identifier.
43
+ - **Last_Updated**: Timestamp of the analysis.
44
+
45
+ If the image is unclear, it returns an error message requesting a re-upload.
46
+ """
47
+ try:
48
+ # Validate URL (basic check)
49
+ if not request.image_url:
50
+ raise HTTPException(status_code=400, detail="Image URL is required")
51
+
52
+ markdown_output = process_shelf_image(request.image_url)
53
+ return {"markdown_output": markdown_output}
54
+ except Exception as e:
55
+ raise HTTPException(status_code=500, detail=str(e))
56
+
57
+ if __name__ == "__main__":
58
+ uvicorn.run("fastapi_app:app", host="0.0.0.0", port=8000, reload=True)
llm_backend.py ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #llm_backend.py
2
+ from langchain.chat_models import init_chat_model
3
+ from dotenv import load_dotenv
4
+ from langchain_core.messages import HumanMessage
5
+ from datetime import datetime
6
+
7
+ load_dotenv()
8
+
9
+ # Initialize the model
10
+ llm = init_chat_model("google_genai:gemini-2.5-flash")
11
+
12
+ def process_shelf_image(image_url: str):
13
+ current_timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
14
+ # Create the HumanMessage
15
+ message = HumanMessage(
16
+ content=[
17
+ {
18
+ "type": "text",
19
+ "text": f"""You are an Expert Retail Inventory Manager.
20
+ Analyze the provided image of a retail shelf and extract the product information into a structured Markdown table.
21
+
22
+ The table must have the following columns:
23
+ | ID | Product_SKU | Shelf_ID | Last_Updated |
24
+
25
+ Rules for extraction:
26
+ - **ID**: Generate a unique identifier for each distinct item (e.g., ITEM_001, ITEM_002).
27
+ - **Product_SKU**: Identify the product name or type visible on the label or packaging. Be as specific as possible.
28
+ - **Shelf_ID**: Identify the shelf number or location code if visible. If not explicitly visible, assign a logical identifier (e.g., SHELF_01).
29
+ - **Last_Updated**: {current_timestamp}
30
+
31
+ **Exception Handling:**
32
+ - If the image is very blurry, too dark, or the product details are not legible for many of the products to accurately identify the SKU, DO NOT output the table. If only few products labels are not legible, output the table for the products that are legible.
33
+ - Instead, output a single line message: "Error: Unable to identify products. Please re-upload a clearer image."
34
+
35
+ Output ONLY the markdown table or the error message. Do not include any other text."""
36
+ },
37
+ {
38
+ "type": "image",
39
+ "url": image_url
40
+ },
41
+ ]
42
+ )
43
+
44
+ # Invoke the model
45
+ response = llm.invoke([message])
46
+ return response.content
47
+
48
+ if __name__ == "__main__":
49
+ # Test with a default image if run directly
50
+ test_url = "https://drive.google.com/uc?export=download&id=1MyH2a4rgjYjnPcmV8W-7k4vjCRIaZo8y"
51
+ print(f"Response: {process_shelf_image(test_url)}")
pyproject.toml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [project]
2
+ name = "backend"
3
+ version = "0.1.0"
4
+ description = "Add your description here"
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ dependencies = [
8
+ "fastapi[standard]>=0.122.0",
9
+ "langchain[google-genai]>=1.1.0",
10
+ "pillow>=12.0.0",
11
+ "python-dotenv>=1.2.1",
12
+ ]