Spaces:
Sleeping
Sleeping
File size: 6,206 Bytes
d2ba52b |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
from fastapi import FastAPI, HTTPException, UploadFile, File
from fastapi.responses import JSONResponse, HTMLResponse, PlainTextResponse
from pydantic import BaseModel
from typing import List, Optional
import requests
import json
import base64
from PIL import Image
import io
import os
import time
import uvicorn
app = FastAPI(title="Ollama Fashion Analyzer API", version="1.0.0")
class OllamaFashionAnalyzer:
def __init__(self, base_url=None):
"""Initialize Ollama client"""
self.base_url = base_url or os.getenv("OLLAMA_BASE_URL", "http://localhost:11434")
self.model = "llava:7b" # Using LLaVA for vision analysis
def encode_image_from_bytes(self, image_bytes):
"""Encode image bytes to base64 for Ollama"""
image = Image.open(io.BytesIO(image_bytes))
# Convert to RGB if necessary
if image.mode != 'RGB':
image = image.convert('RGB')
# Convert to base64
buffered = io.BytesIO()
image.save(buffered, format="JPEG")
img_str = base64.b64encode(buffered.getvalue()).decode()
return img_str
def analyze_clothing_from_bytes(self, image_bytes):
"""Detailed clothing analysis using Ollama from image bytes"""
# Encode image
image_b64 = self.encode_image_from_bytes(image_bytes)
# Fashion analysis prompt
prompt = """Analyze this clothing item in detail and provide information about:
1. GARMENT TYPE: What type of clothing is this?
2. COLORS: Primary and secondary colors
3. COLLAR/NECKLINE: Style of collar or neckline
4. SLEEVES: Sleeve type and length
5. PATTERN: Any patterns or designs
6. FIT: How does it fit (loose, fitted, etc.)
7. MATERIAL: Apparent fabric type
8. FEATURES: Buttons, pockets, zippers, etc.
9. STYLE: Fashion style category
10. OCCASION: Suitable occasions for wearing
Be specific and detailed in your analysis."""
# Make request to Ollama
payload = {
"model": self.model,
"prompt": prompt,
"images": [image_b64],
"stream": False,
"options": {
"temperature": 0.2,
"num_predict": 500
}
}
try:
response = requests.post(
f"{self.base_url}/api/generate",
json=payload,
timeout=120 # Increased timeout for vision models
)
response.raise_for_status()
result = response.json()
return result.get('response', 'No response received')
except requests.exceptions.RequestException as e:
return f"Error: {str(e)}"
# Initialize analyzer
analyzer = OllamaFashionAnalyzer()
# Request/Response models
class AnalysisResponse(BaseModel):
analysis: str
# API Endpoints
@app.get("/", response_class=HTMLResponse)
async def root():
"""Main page with file upload interface"""
return """
<!DOCTYPE html>
<html>
<head>
<title>Fashion Analyzer</title>
<style>
body { font-family: Arial, sans-serif; max-width: 800px; margin: 50px auto; padding: 20px; }
.upload-area { border: 2px dashed #ccc; padding: 50px; text-align: center; margin: 20px 0; }
.result { background: #f5f5f5; padding: 20px; margin: 20px 0; border-radius: 5px; }
</style>
</head>
<body>
<h1>🎽 Fashion Analyzer</h1>
<p>Upload an image of clothing to get detailed fashion analysis</p>
<div class="upload-area">
<input type="file" id="imageInput" accept="image/*" style="margin: 10px;">
<br>
<button onclick="analyzeImage()" style="padding: 10px 20px; margin: 10px;">Analyze Fashion</button>
</div>
<div id="result" class="result" style="display: none;">
<h3>Analysis Result:</h3>
<pre id="analysisText"></pre>
</div>
<script>
async function analyzeImage() {
const input = document.getElementById('imageInput');
const file = input.files[0];
if (!file) {
alert('Please select an image file');
return;
}
const formData = new FormData();
formData.append('file', file);
document.getElementById('analysisText').textContent = 'Analyzing... Please wait...';
document.getElementById('result').style.display = 'block';
try {
const response = await fetch('/analyze-image', {
method: 'POST',
body: formData
});
const result = await response.json();
document.getElementById('analysisText').textContent = result.analysis;
} catch (error) {
document.getElementById('analysisText').textContent = 'Error: ' + error.message;
}
}
</script>
</body>
</html>
"""
@app.post("/analyze-image", response_model=AnalysisResponse)
async def analyze_image(file: UploadFile = File(...)):
"""Analyze uploaded image"""
try:
# Read image bytes
image_bytes = await file.read()
# Analyze the clothing
analysis = analyzer.analyze_clothing_from_bytes(image_bytes)
return AnalysisResponse(analysis=analysis)
except Exception as e:
raise HTTPException(status_code=500, detail=f"Error analyzing image: {str(e)}")
@app.get("/health")
async def health_check():
"""Health check endpoint"""
try:
# Test Ollama connection
response = requests.get(f"{analyzer.base_url}/api/tags", timeout=5)
if response.status_code == 200:
return {"status": "healthy", "ollama": "connected"}
else:
return {"status": "unhealthy", "ollama": "disconnected"}
except:
return {"status": "unhealthy", "ollama": "disconnected"}
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=7860) |