Build [v1.7.0] - GitGuard - Infrastructure Hardening
This commit is contained in:
@@ -7,36 +7,55 @@ base_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
dotenv_path = os.path.join(base_dir, ".env")
|
||||
load_dotenv(dotenv_path)
|
||||
|
||||
def extract_label_info(image_bytes: bytes):
|
||||
def extract_label_info(image_bytes: bytes, mode: str = "item"):
|
||||
"""
|
||||
Orchestrates extraction across multiple AI providers.
|
||||
Order: Gemini (Flash/Pro) -> Claude (Haiku/Sonnet)
|
||||
"""
|
||||
prompt = """
|
||||
Extract technical inventory information from this label image.
|
||||
|
||||
CRITICAL INSTRUCTIONS:
|
||||
1. Look at the most prominent text (usually top 1-2 rows). This is the product NAME and MODEL.
|
||||
2. Extract the PART NUMBER (P/N, Model No, Type). If no explicit Part Number is found, synthesize one from the most unique identifier in the header (e.g. 'OM4-MMF-DX').
|
||||
3. Separate the COLOR (e.g. Turquoise, Yellow, Black).
|
||||
4. Extract CATEGORY based on the item type (e.g. Patchcord, SFP, Connector).
|
||||
5. Extract technical SPECS (e.g. '2.0mm', '10G', '850nm').
|
||||
|
||||
Return ONLY a valid JSON object:
|
||||
{
|
||||
"name": "Full descriptive name from header",
|
||||
"part_number": "Unique identifier for fast scanning",
|
||||
"category": "Broad category",
|
||||
"color": "Color if present",
|
||||
"specs": "Brief tech specs list",
|
||||
"barcode": "Barcode value if visible",
|
||||
"quantity": 1
|
||||
}
|
||||
Modes: 'item' (full technical extraction), 'box' (container discovery)
|
||||
"""
|
||||
if mode == "box":
|
||||
prompt = """
|
||||
Identify the CONTAINER or BOX name from this image.
|
||||
Look for large, prominent, bold, or hand-written text that identifies a storage unit.
|
||||
Ignore small technical details, quantities, or fine print.
|
||||
|
||||
Return ONLY a valid JSON object:
|
||||
{
|
||||
"box_label": "The identified container name",
|
||||
"name": "Same as box_label",
|
||||
"category": "Storage",
|
||||
"specs": "Brief description if useful",
|
||||
"quantity": 1
|
||||
}
|
||||
"""
|
||||
else:
|
||||
prompt = """
|
||||
Extract technical inventory information from this label image.
|
||||
|
||||
CRITICAL INSTRUCTIONS:
|
||||
1. Look at the most prominent text (usually top 1-2 rows). This is the product NAME and MODEL.
|
||||
2. Extract the PART NUMBER (P/N, Model No, Type). If no explicit Part Number is found, synthesize one from the most unique identifier in the header (e.g. 'OM4-MMF-DX').
|
||||
3. Separate the COLOR (e.g. Turquoise, Yellow, Black).
|
||||
4. Extract CATEGORY based on the item type (e.g. Patchcord, SFP, Connector).
|
||||
5. Extract technical SPECS (e.g. '2.0mm', '10G', '850nm').
|
||||
|
||||
Return ONLY a valid JSON object:
|
||||
{
|
||||
"name": "Full descriptive name from header",
|
||||
"part_number": "Unique identifier for fast scanning",
|
||||
"category": "Broad category",
|
||||
"color": "Color if present",
|
||||
"specs": "Brief tech specs list",
|
||||
"barcode": "Barcode value if visible",
|
||||
"quantity": 1
|
||||
}
|
||||
"""
|
||||
|
||||
# 1. Try Gemini
|
||||
result = gemini.extract(image_bytes, prompt)
|
||||
if result:
|
||||
# Maintenance: Ensure fields are mapped if mode was box
|
||||
if mode == "box" and "box_label" in result and "name" not in result:
|
||||
result["name"] = result["box_label"]
|
||||
return result
|
||||
|
||||
# 2. Try Claude (Fallback)
|
||||
|
||||
@@ -66,6 +66,7 @@ _MAX_IMAGE_SIZE = 10 * 1024 * 1024 # 10 MB
|
||||
async def extract_label(
|
||||
request: Request,
|
||||
file: UploadFile = File(...),
|
||||
mode: str = "item", # 'item' or 'box'
|
||||
current_user: auth.TokenData = Depends(auth.get_current_user)
|
||||
):
|
||||
"""[C-01] Extract label from image — only for authenticated users. [H-02] Rate limit: 10 req/min per IP."""
|
||||
@@ -86,7 +87,7 @@ async def extract_label(
|
||||
detail="File exceeds 10MB limit."
|
||||
)
|
||||
|
||||
result = extract_label_info(contents)
|
||||
result = extract_label_info(contents, mode=mode)
|
||||
return result
|
||||
|
||||
@router.post("/", response_model=schemas.Item, status_code=status.HTTP_201_CREATED)
|
||||
|
||||
Reference in New Issue
Block a user