jacopo22295 commited on
Commit
09fda8e
·
verified ·
1 Parent(s): 03451b6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +113 -9
app.py CHANGED
@@ -1,8 +1,15 @@
 
 
1
  import gradio as gr
2
  from PIL import Image
3
  import torch
4
  import torchvision.transforms as T
5
  import torchvision.models as models
 
 
 
 
 
6
 
7
  MODEL_PATH = "resnet50-corrosion-classifier-v1.pth"
8
 
@@ -39,7 +46,27 @@ transform = T.Compose([
39
  std=[0.229, 0.224, 0.225]),
40
  ])
41
 
42
- def predict(image: Image.Image):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  img = image.convert("RGB")
44
  x = transform(img).unsqueeze(0).to(device)
45
  with torch.no_grad():
@@ -48,16 +75,93 @@ def predict(image: Image.Image):
48
  idx = int(probs.argmax())
49
  label = IDX2LABEL.get(idx, f"class_{idx}")
50
  confidence = float(probs[idx])
51
- return {"label": label, "confidence": confidence}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
53
- demo = gr.Interface(
54
- fn=predict,
55
- inputs=gr.Image(type="pil", label="Upload o scatta"),
56
- outputs=gr.JSON(label="Risultato"),
57
- title="Corrosion Classifier API",
58
- description="Restituisce label e confidence per l'immagine"
59
- )
60
 
 
61
  demo.api_mode = "enabled"
62
 
63
  if __name__ == "__main__":
 
1
+ import os
2
+ import io
3
  import gradio as gr
4
  from PIL import Image
5
  import torch
6
  import torchvision.transforms as T
7
  import torchvision.models as models
8
+ from openai import OpenAI
9
+
10
+ # ======================
11
+ # Config / Model loading
12
+ # ======================
13
 
14
  MODEL_PATH = "resnet50-corrosion-classifier-v1.pth"
15
 
 
46
  std=[0.229, 0.224, 0.225]),
47
  ])
48
 
49
+ # ======================
50
+ # OpenAI client
51
+ # ======================
52
+
53
+ OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
54
+ if not OPENAI_API_KEY:
55
+ # Gradio UI mostrerà l'errore se mancano le secrets
56
+ print("WARNING: OPENAI_API_KEY not set. Set it in HF Space Secrets.")
57
+
58
+ client = OpenAI(api_key=OPENAI_API_KEY)
59
+
60
+ # Puoi forzare la 2a lingua con env, altrimenti auto → in base al testo utente, fallback IT
61
+ APP_FORCE_LANG = os.environ.get("APP_FORCE_LANG", "").strip()
62
+
63
+ OPENAI_MODEL = os.environ.get("OPENAI_MODEL", "gpt-4o-mini")
64
+
65
+ # ======================
66
+ # Inference functions
67
+ # ======================
68
+
69
+ def predict_image(image: Image.Image):
70
  img = image.convert("RGB")
71
  x = transform(img).unsqueeze(0).to(device)
72
  with torch.no_grad():
 
75
  idx = int(probs.argmax())
76
  label = IDX2LABEL.get(idx, f"class_{idx}")
77
  confidence = float(probs[idx])
78
+ return label, confidence
79
+
80
+ def build_prompt(label: str, confidence: float, user_note: str, second_lang_hint: str):
81
+ # Istruzioni:
82
+ # 1) Prima parte sempre in EN
83
+ # 2) Seconda parte nella lingua dell'input utente (se presente),
84
+ # altrimenti in IT, o forzata via APP_FORCE_LANG
85
+ second_lang_clause = ""
86
+ if APP_FORCE_LANG:
87
+ second_lang_clause = f"Then provide the same content in {APP_FORCE_LANG}."
88
+ else:
89
+ # Se l'utente ha scritto qualcosa, usa la sua lingua
90
+ if user_note and user_note.strip():
91
+ second_lang_clause = "Then repeat the same content in the same language used in the user note."
92
+ else:
93
+ second_lang_clause = "Then repeat the same content in Italian."
94
+
95
+ prompt = f"""
96
+ You are a marine coatings technical assistant (PPG style). You have an image classification result:
97
+ - Corrosion type: {label}
98
+ - Model confidence: {round(confidence*100,2)}%
99
+
100
+ Provide a technical advisory in two parts:
101
+
102
+ 1) English section (concise, structured as bullet points):
103
+ - Diagnosis
104
+ - Likely causes
105
+ - Generic paint system suggestion (no unrealistic promises)
106
+ - Warnings about substrate condition / prep
107
+
108
+ 2) {second_lang_clause}
109
+
110
+ Context from user (optional): {user_note or "(none)"}
111
+
112
+ Keep it pragmatic, accurate, and brief.
113
+ """
114
+ return prompt
115
+
116
+ def ask_openai(label: str, confidence: float, user_note: str):
117
+ prompt = build_prompt(label, confidence, user_note, APP_FORCE_LANG)
118
+ try:
119
+ resp = client.chat.completions.create(
120
+ model=OPENAI_MODEL,
121
+ messages=[{"role": "user", "content": prompt}],
122
+ temperature=0.3
123
+ )
124
+ return resp.choices[0].message.content.strip()
125
+ except Exception as e:
126
+ return f"OpenAI error: {e}"
127
+
128
+ def pipeline(image, note):
129
+ if image is None:
130
+ return "No image received."
131
+
132
+ label, conf = predict_image(image)
133
+ header = f"**Model result:** `{label}` — confidence **{round(conf*100,2)}%**\n\n"
134
+ advisory = ask_openai(label, conf, note or "")
135
+ return header + advisory
136
+
137
+ # ======================
138
+ # UI
139
+ # ======================
140
+
141
+ with gr.Blocks(title="Corrosion Assistant", theme=gr.themes.Soft()) as demo:
142
+ gr.Markdown(
143
+ """
144
+ # Corrosion Assistant
145
+ Upload or take a photo. The model classifies corrosion type and an AI assistant gives a short technical advisory.
146
+ """
147
+ )
148
+ with gr.Row():
149
+ with gr.Column(scale=2):
150
+ img = gr.Image(type="pil", sources=["upload","webcam"], label="Upload or webcam")
151
+ note = gr.Textbox(label="Notes / Context (optional)", placeholder="Write in your language. EN comes first, then your language.")
152
+ btn = gr.Button("Analyze image", variant="primary")
153
+ with gr.Column(scale=3):
154
+ out = gr.Markdown(label="Analysis")
155
+ gr.Markdown(
156
+ """
157
+ <small>Tip: keep photos under ~2MB. Secrets are stored server-side.
158
+ UI is lightly themed; HF outer shell isn't customizable.</small>
159
+ """
160
+ )
161
 
162
+ btn.click(pipeline, inputs=[img, note], outputs=[out])
 
 
 
 
 
 
163
 
164
+ # Enable programmatic API access to `pipeline`
165
  demo.api_mode = "enabled"
166
 
167
  if __name__ == "__main__":