serviceadvisor / app.py
viswanani's picture
Upload 16 files
94332c9 verified
import os, io, base64
from typing import List, Dict, Any
import gradio as gr
from PIL import Image
from car_core.specs_model_space import build_label_space
from car_core.models_zeroshot import ModelIDZeroShot
from car_core.color_detect import dominant_color
from car_core.issues import detect_issues
from car_core.pricing import price_issues, load_regions
from car_core.exporter import export_pdf, export_json
LABEL_SPACE = build_label_space()
MODEL = ModelIDZeroShot(LABEL_SPACE)
REGIONS = load_regions()
def _to_pil(obj):
if isinstance(obj, dict) and "image" in obj:
# Gradio File with base64 'image' key
return Image.open(io.BytesIO(base64.b64decode(obj["image"].split(",")[-1])))
if isinstance(obj, str):
return Image.open(obj)
if hasattr(obj, "read"):
return Image.open(obj)
return obj
def analyze(images: list, region: str):
if not images:
raise gr.Error("Upload at least one car image.")
imgs = []
for it in images:
try:
imgs.append(_to_pil(it))
except Exception:
pass
if not imgs:
raise gr.Error("Failed to decode images. Use JPG/PNG.")
# Model decision: pick the most frequent top label across images
votes = {}
for im in imgs:
lbl = MODEL.top_label(im)
votes[lbl] = votes.get(lbl, 0) + 1
model_final = sorted(votes.items(), key=lambda kv: kv[1], reverse=True)[0][0]
# Color decision: take the most frequent named color across images
color_votes = {}
for im in imgs:
c = dominant_color(im)["name"]
color_votes[c] = color_votes.get(c, 0) + 1
color_name = sorted(color_votes.items(), key=lambda kv: kv[1], reverse=True)[0][0]
color_any = None
# Recompute once to get rgb/hex for the chosen name
for im in imgs:
d = dominant_color(im)
if d["name"] == color_name:
color_any = d; break
color_final = color_any or {"name": color_name, "rgb": (0,0,0), "hex": "#000000"}
# Issues (deterministic)
issues = detect_issues(imgs)
# Pricing
pricing = price_issues(issues, region_code=region)
payload = {
"vehicle": {"model": model_final, "color": color_final},
"region": region,
"issues": issues,
"pricing": pricing
}
os.makedirs("exports", exist_ok=True)
pdf_path = "exports/report.pdf"
json_path = "exports/report.json"
export_pdf(payload, pdf_path)
export_json(payload, json_path)
def to_dl(path):
with open(path, "rb") as f:
return (os.path.basename(path), f.read())
# Deterministic, actionable output only
result = {
"vehicle": payload["vehicle"],
"region": pricing["region"],
"currency": pricing["currency"],
"issues_with_solutions": [
{
"issue": it["issue"],
"solution": it["solution"],
"labor_hours": it["labor_hours"],
"labor_cost": it["labor_cost"],
"parts_cost": it["parts_cost"],
"line_total": it["line_total"]
} for it in pricing["items"]
],
"totals": {
"subtotal": pricing["subtotal"],
"tax": pricing["tax"],
"grand_total": pricing["grand_total"]
}
}
return result, to_dl(pdf_path), to_dl(json_path)
with gr.Blocks(fill_height=True) as demo:
gr.Markdown("## 🛠️ Car Analysis Advisor — multi‑image model/color/issue detection with exact pricing")
with gr.Row():
with gr.Column(scale=1):
imgs = gr.File(label="Upload car image(s)", file_count="multiple", file_types=["image"])
region = gr.Dropdown(choices=list(REGIONS["regions"].keys()), value=REGIONS.get("default_region","IN-HYD"), label="Region (pricing)")
run = gr.Button("Analyze", variant="primary")
with gr.Column(scale=1):
out = gr.JSON(label="Actionable results")
pdf = gr.File(label="Download PDF")
jj = gr.File(label="Download JSON")
run.click(analyze, inputs=[imgs, region], outputs=[out, pdf, jj])
if __name__ == "__main__":
demo.launch()