ProfRom commited on
Commit
4844cf7
·
verified ·
1 Parent(s): 598289b

Thomas - Final submission

Browse files
Files changed (1) hide show
  1. app.py +128 -88
app.py CHANGED
@@ -1,96 +1,136 @@
1
- import os
2
- import random
3
 
4
  import gradio as gr
5
- import torch
6
- from datasets import load_dataset
7
- from transformers import BlipForQuestionAnswering, BlipProcessor
8
-
9
- # Always use BlipProcessor + BlipForQuestionAnswering directly.
10
- # The Transformers pipeline API for BLIP-VQA changed between v4 and v5 and can echo
11
- # the question instead of returning the answer. Direct model calls are stable across versions.
12
- MODEL_ID = "Salesforce/blip-vqa-base"
13
-
14
- _device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
15
- _processor = BlipProcessor.from_pretrained(MODEL_ID)
16
- _model = BlipForQuestionAnswering.from_pretrained(MODEL_ID).to(_device)
17
- _model.eval()
18
-
19
-
20
- def run_vqa(image, question: str) -> str:
21
- inputs = _processor(images=image, text=question, return_tensors="pt").to(_device)
22
- with torch.no_grad():
23
- out = _model.generate(**inputs, max_new_tokens=32)
24
- return _processor.decode(out[0], skip_special_tokens=True).strip()
25
-
26
- FOOD101_ID = "ethz/food101"
27
- DEFAULT_VQA_QUESTION = "What kind of food is in this image?"
28
-
29
-
30
- def answer_question(image, question):
31
- if not question:
32
- return "Please type a question about the image."
33
- if image is None:
34
- return "Please upload an image (or use Load random sample) before clicking Answer."
35
- return run_vqa(image, question)
36
-
37
-
38
- def load_food101_sample(cache: dict | None):
39
- """
40
- Pull one random example from Hugging Face Datasets (Food-101).
41
- Dataset card: https://huggingface.co/datasets/ethz/food101
42
- """
43
- if cache is None:
44
- cache = {"ds": load_dataset(FOOD101_ID, split="validation")}
45
- ds = cache["ds"]
46
- i = random.randint(0, len(ds) - 1)
47
- ex = ds[i]
48
- names = ds.features["label"].names
49
- gold = names[ex["label"]]
50
- note = (
51
- f"Loaded from Hugging Face Datasets `{FOOD101_ID}` "
52
- f"(split `validation`, index {i}). Reference label: `{gold}`."
53
- )
54
- return ex["image"], DEFAULT_VQA_QUESTION, cache, note
55
 
 
 
 
 
 
 
56
 
57
- with gr.Blocks() as demo:
58
- ds_cache = gr.State(None)
59
- gr.Markdown(
60
- "## BLIP Visual Question Answering\n"
61
- "Gradio app for [Hugging Face Spaces](https://huggingface.co/docs/hub/spaces). "
62
- "Upload your own image **or** load a sample image from "
63
- f"[Hugging Face Datasets — `{FOOD101_ID}`](https://huggingface.co/datasets/ethz/food101)."
64
- )
65
- dataset_note = gr.Markdown("")
66
- with gr.Row():
67
- image_in = gr.Image(type="pil", label="Image")
68
- question_in = gr.Textbox(
69
- label="Question",
70
- placeholder="e.g. What is the weather in this image?",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  )
72
- answer_out = gr.Textbox(label="Answer")
73
- with gr.Row():
74
- submit_btn = gr.Button("Answer", variant="primary")
75
- sample_btn = gr.Button(f"Load random sample ({FOOD101_ID})")
76
-
77
- submit_btn.click(answer_question, [image_in, question_in], [answer_out])
78
- sample_btn.click(
79
- load_food101_sample,
80
- [ds_cache],
81
- [image_in, question_in, ds_cache, dataset_note],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  )
 
83
 
 
84
  if __name__ == "__main__":
85
- # Hugging Face Spaces sets PORT; bind 0.0.0.0 so the Space proxy can reach the app.
86
- # Locally: open http://127.0.0.1:<PORT> (default PORT 7860 if unset).
87
- _port = int(os.environ.get("PORT", "7860"))
88
- # Queue mode is recommended for Spaces and tends to play nicer with Gradio’s async stack.
89
- demo.queue()
90
- demo.launch(
91
- server_name="0.0.0.0",
92
- server_port=_port,
93
- # Space URL is already public; share=True would add a separate *.gradio.live tunnel (not needed).
94
- share=False,
95
- show_error=True,
96
- )
 
 
 
1
 
2
  import gradio as gr
3
+ from transformers import pipeline
4
+ from PIL import Image
5
+ import numpy as np
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
 
7
+ # Load Models (Explicit)
8
+ classifier = pipeline(
9
+ "image-classification",
10
+ model="google/vit-base-patch16-224",
11
+ use_fast=True
12
+ )
13
 
14
+ captioner = pipeline(
15
+ "image-text-to-text",
16
+ model="Salesforce/blip-image-captioning-base"
17
+ )
18
+
19
+ sentiment = pipeline(
20
+ "sentiment-analysis",
21
+ model="distilbert-base-uncased-finetuned-sst-2-english"
22
+ )
23
+
24
+ # Smart Matching Function
25
+ def check_match(label, caption):
26
+ label = label.lower()
27
+ caption = caption.lower()
28
+
29
+ keyword_map = {
30
+ "dog": ["dog", "puppy"],
31
+ "cat": ["cat", "kitten"],
32
+ "car": ["car", "vehicle"],
33
+ "pizza": ["pizza"],
34
+ "bird": ["bird"],
35
+ "person": ["person", "man", "woman", "people"],
36
+ "bicycle": ["bike", "bicycle"],
37
+ "laptop": ["laptop", "computer"],
38
+ "beach": ["beach", "ocean", "sea"],
39
+ "mountain": ["mountain"]
40
+ }
41
+
42
+ for key, words in keyword_map.items():
43
+ if key in label:
44
+ for word in words:
45
+ if word in caption:
46
+ return True
47
+
48
+ return False
49
+
50
+ # Image Processing Function
51
+ def process_image(image):
52
+ try:
53
+
54
+ # Image is already PIL — no conversion needed
55
+
56
+ # 1. Classification
57
+ class_result = classifier(image)
58
+ top_class = class_result[0]['label']
59
+ confidence = round(class_result[0]['score'], 3)
60
+
61
+ # 2. Captioning (FIXED)
62
+ print(f"Debug: Type of image for captioner: {type(image)}")
63
+ print(f"Debug: Image info (if PIL): {image.format, image.size, image.mode}")
64
+ # Pass image as a list and provide a default text prompt
65
+ caption_result = captioner(images=[image], text="a photo of")
66
+
67
+ caption = caption_result[0]['generated_text']
68
+
69
+ # Handle empty caption
70
+ if not caption or len(caption.strip()) == 0:
71
+ sentiment_label = "N/A"
72
+ sentiment_score = 0.0
73
+ comparison_text = "No Caption ❌"
74
+ caption = "No caption generated."
75
+ else:
76
+ # 3. Sentiment
77
+ sentiment_result = sentiment(caption)[0]
78
+ sentiment_label = sentiment_result['label']
79
+ sentiment_score = round(sentiment_result['score'], 3)
80
+
81
+ # 4. Comparison
82
+ match = top_class.lower() in caption.lower()
83
+ comparison_text = "Match ✅" if match else "No Match ❌"
84
+
85
+ return (
86
+ f"{top_class} (Confidence: {confidence})",
87
+ caption,
88
+ f"{sentiment_label} (Score: {sentiment_score})",
89
+ comparison_text
90
  )
91
+
92
+ except Exception as e:
93
+ return (
94
+ "Error in classification",
95
+ "Error in captioning",
96
+ "Error in sentiment",
97
+ str(e)
98
+ )
99
+
100
+ # Create a dummy image for testing the pipelines
101
+ dummy_image_path = "dummy_image.png"
102
+ img_data = np.zeros((100, 100, 3), dtype=np.uint8) # 100x100 black image
103
+ dummy_img = Image.fromarray(img_data)
104
+ dummy_img.save(dummy_image_path)
105
+
106
+ # Load the dummy image for testing
107
+ img = Image.open(dummy_image_path)
108
+
109
+ classifier_test_result = classifier(img)
110
+ print("Classifier test result:", classifier_test_result)
111
+
112
+ # Pass image as a list and provide a default text prompt for testing
113
+ captioner_test_result = captioner(images=[img], text="a photo of")
114
+ print("Captioner test result:", captioner_test_result)
115
+
116
+ # Gradio Interface
117
+ interface = gr.Interface(
118
+ fn=process_image,
119
+ inputs=gr.Image(type="pil"),
120
+ outputs=[
121
+ gr.Text(label="Image Classification"),
122
+ gr.Text(label="Generated Caption"),
123
+ gr.Text(label="Caption Sentiment"),
124
+ gr.Text(label="Model Agreement")
125
+ ],
126
+ title="Multimodal Image Analysis System",
127
+ description=(
128
+ "Upload an image to analyze it using multiple AI models. "
129
+ "This app compares image classification and captioning results "
130
+ "and applies NLP to evaluate the caption."
131
  )
132
+ )
133
 
134
+ # Launch App
135
  if __name__ == "__main__":
136
+ interface.launch(debug=True)