AMontiB commited on
Commit
6a489d1
·
1 Parent(s): 48e51ec

update ALL

Browse files
__pycache__/app.cpython-310.pyc CHANGED
Binary files a/__pycache__/app.cpython-310.pyc and b/__pycache__/app.cpython-310.pyc differ
 
app.py CHANGED
@@ -6,6 +6,9 @@ import json
6
  import argparse
7
  from types import SimpleNamespace
8
  from PIL import Image
 
 
 
9
 
10
  # Try to import detector - if this fails, we'll show an error in the UI
11
  try:
@@ -29,7 +32,7 @@ if os.environ.get("SPACE_ID"):
29
  print(f"Warning: Could not download weights: {e}")
30
 
31
  # Available detectors based on launcher.py
32
- DETECTORS = ['R50_TF', 'R50_nodown', 'CLIP-D', 'P2G', 'NPR']
33
 
34
  def process_image(image_path):
35
  """
@@ -67,6 +70,38 @@ def process_image(image_path):
67
  print(f"Error processing image: {e}")
68
  return image_path
69
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  def predict(image_path, detector_name):
71
  # Check if detector is available
72
  if not DETECTOR_AVAILABLE:
@@ -74,10 +109,10 @@ def predict(image_path, detector_name):
74
  "error": "Detector module not available",
75
  "details": IMPORT_ERROR,
76
  "message": "The detection system could not be initialized. Please check the logs."
77
- }, indent=2)
78
 
79
  if not image_path:
80
- return json.dumps({"error": "Please upload an image."}, indent=2)
81
 
82
  # Process image (central crop if too large)
83
  processed_path = image_path
@@ -87,64 +122,117 @@ def predict(image_path, detector_name):
87
  print(f"Warning: Image processing failed: {e}")
88
  # Continue with original image if processing fails
89
 
90
- # Create a temporary output file path
91
- output_path = "temp_result.json"
92
-
93
- # Mock args object
94
- args = SimpleNamespace(
95
- image=processed_path,
96
- detector=detector_name,
97
- config_dir='configs',
98
- output=output_path,
99
- weights='pretrained', # Use default/pretrained
100
- device='cpu', # Force CPU
101
- dry_run=False,
102
- verbose=False
103
- )
104
-
105
  try:
106
- # Run detection
107
- # We need to capture stdout/stderr or just trust the function
108
- # run_detect might raise FileNotFoundError if weights are missing
109
- run_detect(args)
110
-
111
- # Read results
112
- if os.path.exists(output_path):
113
- with open(output_path, 'r') as f:
114
- result = json.load(f)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
 
116
- # Format output
117
- prediction = result.get('prediction', 'Unknown')
118
- confidence = result.get('confidence', 0.0)
119
- elapsed_time = result.get('elapsed_time', 0.0)
120
- if prediction == 'fake':
121
- output = {
122
- "Prediction": prediction,
123
- "Confidence": f"{confidence:.4f}",
124
- "Elapsed Time": f"{elapsed_time:.3f}s"
125
- }
126
  else:
127
- output = {
128
- "Prediction": prediction,
129
- "Confidence": f"{1-confidence:.4f}",
130
- "Elapsed Time": f"{elapsed_time:.3f}s"
131
- }
132
- return json.dumps(output, indent=2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
  else:
134
- return json.dumps({"error": "No result file generated. Check console logs for details."}, indent=2)
 
135
 
136
- except FileNotFoundError as e:
137
- return json.dumps({
138
- "error": str(e),
139
- "message": f"Please ensure you have downloaded the weights for {detector_name}."
140
- }, indent=2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  except Exception as e:
142
- return json.dumps({"error": str(e)}, indent=2)
143
- finally:
144
- # Cleanup
145
- if os.path.exists(output_path):
146
- os.remove(output_path)
147
 
 
148
  # Cleanup cropped image if it's different from original
149
  if processed_path != image_path and os.path.exists(processed_path):
150
  try:
@@ -193,6 +281,7 @@ with demo:
193
  max_lines=20,
194
  show_copy_button=True
195
  )
 
196
 
197
  with gr.Accordion("📚 Model Details", open=False):
198
  gr.Markdown("""
@@ -235,7 +324,7 @@ with demo:
235
  submit_btn.click(
236
  fn=predict,
237
  inputs=[image_input, detector_input],
238
- outputs=output_display
239
  )
240
 
241
  if __name__ == "__main__":
 
6
  import argparse
7
  from types import SimpleNamespace
8
  from PIL import Image
9
+ import matplotlib.pyplot as plt
10
+ import io
11
+ import numpy as np
12
 
13
  # Try to import detector - if this fails, we'll show an error in the UI
14
  try:
 
32
  print(f"Warning: Could not download weights: {e}")
33
 
34
  # Available detectors based on launcher.py
35
+ DETECTORS = ['ALL', 'R50_TF', 'R50_nodown', 'CLIP-D', 'P2G', 'NPR']
36
 
37
  def process_image(image_path):
38
  """
 
70
  print(f"Error processing image: {e}")
71
  return image_path
72
 
73
+ def run_single_detection(image_path, detector_name):
74
+ output_path = f"temp_result_{detector_name}.json"
75
+ # Mock args object
76
+ args = SimpleNamespace(
77
+ image=image_path,
78
+ detector=detector_name,
79
+ config_dir='configs',
80
+ output=output_path,
81
+ weights='pretrained', # Use default/pretrained
82
+ device='cpu', # Force CPU
83
+ dry_run=False,
84
+ verbose=False
85
+ )
86
+
87
+ try:
88
+ run_detect(args)
89
+
90
+ if os.path.exists(output_path):
91
+ with open(output_path, 'r') as f:
92
+ result = json.load(f)
93
+ os.remove(output_path)
94
+ return result
95
+ return None
96
+ except Exception as e:
97
+ if os.path.exists(output_path):
98
+ try:
99
+ os.remove(output_path)
100
+ except:
101
+ pass
102
+ print(f"Error running {detector_name}: {e}")
103
+ return None
104
+
105
  def predict(image_path, detector_name):
106
  # Check if detector is available
107
  if not DETECTOR_AVAILABLE:
 
109
  "error": "Detector module not available",
110
  "details": IMPORT_ERROR,
111
  "message": "The detection system could not be initialized. Please check the logs."
112
+ }, indent=2), None
113
 
114
  if not image_path:
115
+ return json.dumps({"error": "Please upload an image."}, indent=2), None
116
 
117
  # Process image (central crop if too large)
118
  processed_path = image_path
 
122
  print(f"Warning: Image processing failed: {e}")
123
  # Continue with original image if processing fails
124
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
  try:
126
+ if detector_name == 'ALL':
127
+ results = []
128
+ # Filter out 'ALL' from detectors list
129
+ real_detectors = [d for d in DETECTORS if d != 'ALL']
130
+
131
+ for det in real_detectors:
132
+ res = run_single_detection(processed_path, det)
133
+ if res:
134
+ results.append((det, res))
135
+
136
+ if not results:
137
+ return "Error: No results obtained from detectors.", None
138
+
139
+ votes_real = 0
140
+ votes_fake = 0
141
+ confidences = []
142
+ labels = []
143
+ colors = []
144
+ total_conf = 0
145
+
146
+ for det, res in results:
147
+ pred = res.get('prediction', 'Unknown')
148
+ raw_conf = res.get('confidence', 0.0)
149
+
150
+ # Calculate display confidence (confidence of the prediction)
151
+ if pred == 'fake':
152
+ score = raw_conf
153
+ color = 'red'
154
+ else:
155
+ score = 1 - raw_conf
156
+ color = 'green'
157
+
158
+ labels.append(det)
159
+ confidences.append(score)
160
+ colors.append(color)
161
+ total_conf += score
162
+
163
+ # Voting logic
164
+ if score > 0.6:
165
+ if pred == 'fake':
166
+ votes_fake += 1
167
+ elif pred == 'real':
168
+ votes_real += 1
169
 
170
+ # Majority Voting
171
+ if votes_real > votes_fake:
172
+ verdict = "REAL"
173
+ elif votes_fake > votes_real:
174
+ verdict = "FAKE"
 
 
 
 
 
175
  else:
176
+ verdict = "UNCERTAIN"
177
+
178
+ avg_conf = total_conf / len(results) if results else 0
179
+
180
+ # Explanation
181
+ if verdict == "REAL":
182
+ explanation = f"Considering the results obtained by all models, the analyzed image results, with an average confidence of {avg_conf:.4f}, not produced by a generative AI."
183
+ elif verdict == "FAKE":
184
+ explanation = f"Considering the results obtained by all models, the analyzed image results, with an average confidence of {avg_conf:.4f}, produced by a generative AI."
185
+ else:
186
+ explanation = f"The result is uncertain. The detectors produced unconsistent results. The average confidence is {avg_conf:.4f}."
187
+
188
+ # Plotting
189
+ fig, ax = plt.subplots(figsize=(10, 5))
190
+ bars = ax.bar(labels, confidences, color=colors)
191
+ ax.set_ylim(0, 1.05)
192
+ ax.set_ylabel('Confidence')
193
+ ax.set_title('Detector Confidence Scores')
194
+ ax.axhline(y=0.6, color='gray', linestyle='--', alpha=0.5, label='Vote Threshold (0.6)')
195
+ ax.legend()
196
+
197
+ # Add value labels
198
+ for bar in bars:
199
+ height = bar.get_height()
200
+ ax.text(bar.get_x() + bar.get_width()/2., height,
201
+ f'{height:.2f}',
202
+ ha='center', va='bottom')
203
+
204
+ plt.tight_layout()
205
+ return explanation, fig
206
+
207
  else:
208
+ # Single Detector
209
+ res = run_single_detection(processed_path, detector_name)
210
 
211
+ if res:
212
+ prediction = res.get('prediction', 'Unknown')
213
+ confidence = res.get('confidence', 0.0)
214
+ elapsed_time = res.get('elapsed_time', 0.0)
215
+
216
+ if prediction == 'fake':
217
+ output = {
218
+ "Prediction": prediction,
219
+ "Confidence": f"{confidence:.4f}",
220
+ "Elapsed Time": f"{elapsed_time:.3f}s"
221
+ }
222
+ else:
223
+ output = {
224
+ "Prediction": prediction,
225
+ "Confidence": f"{1-confidence:.4f}",
226
+ "Elapsed Time": f"{elapsed_time:.3f}s"
227
+ }
228
+ return json.dumps(output, indent=2), None
229
+ else:
230
+ return json.dumps({"error": "Detection failed"}), None
231
+
232
  except Exception as e:
233
+ return json.dumps({"error": str(e)}), None
 
 
 
 
234
 
235
+ finally:
236
  # Cleanup cropped image if it's different from original
237
  if processed_path != image_path and os.path.exists(processed_path):
238
  try:
 
281
  max_lines=20,
282
  show_copy_button=True
283
  )
284
+ plot_output = gr.Plot(label="Confidence Scores")
285
 
286
  with gr.Accordion("📚 Model Details", open=False):
287
  gr.Markdown("""
 
324
  submit_btn.click(
325
  fn=predict,
326
  inputs=[image_input, detector_input],
327
+ outputs=[output_display, plot_output]
328
  )
329
 
330
  if __name__ == "__main__":
requirements.txt CHANGED
@@ -13,6 +13,7 @@ pandas==2.2.3
13
  scikit-image==0.22.0
14
  scikit-learn==1.5.2
15
  numpy<2.0
 
16
 
17
  # MLOps & Infrastructure
18
  wandb==0.16.6
 
13
  scikit-image==0.22.0
14
  scikit-learn==1.5.2
15
  numpy<2.0
16
+ matplotlib
17
 
18
  # MLOps & Infrastructure
19
  wandb==0.16.6
support/__pycache__/detect.cpython-310.pyc CHANGED
Binary files a/support/__pycache__/detect.cpython-310.pyc and b/support/__pycache__/detect.cpython-310.pyc differ
 
verify_all_option.py ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from PIL import Image
3
+ import matplotlib.pyplot as plt
4
+ import json
5
+ import sys
6
+ from unittest.mock import patch
7
+
8
+ # Add current directory to path
9
+ sys.path.append(os.getcwd())
10
+
11
+ import app
12
+ from app import predict, DETECTORS
13
+
14
+ def create_dummy_image(path):
15
+ img = Image.new('RGB', (512, 512), color = 'red')
16
+ img.save(path)
17
+ return path
18
+
19
+ def mock_run_single_detection(image_path, detector_name):
20
+ # Mock results
21
+ results = {
22
+ 'R50_TF': {'prediction': 'fake', 'confidence': 0.9, 'elapsed_time': 0.1},
23
+ 'R50_nodown': {'prediction': 'real', 'confidence': 0.2, 'elapsed_time': 0.1}, # Score 0.8 (Real)
24
+ 'CLIP-D': {'prediction': 'fake', 'confidence': 0.8, 'elapsed_time': 0.1},
25
+ 'P2G': {'prediction': 'real', 'confidence': 0.45, 'elapsed_time': 0.1}, # Score 0.55 (Real) - Invalid Vote
26
+ 'NPR': {'prediction': 'fake', 'confidence': 0.95, 'elapsed_time': 0.1}
27
+ }
28
+ return results.get(detector_name)
29
+
30
+ def test_all_option():
31
+ print("Testing 'ALL' option with MOCKED results...")
32
+ img_path = create_dummy_image("test_image.jpg")
33
+
34
+ with patch('app.run_single_detection', side_effect=mock_run_single_detection):
35
+ try:
36
+ # Run predict with 'ALL'
37
+ text, fig = predict(img_path, 'ALL')
38
+
39
+ print(f"Output type: {type(text)}, {type(fig)}")
40
+ print(f"Text output: {text}")
41
+
42
+ if isinstance(fig, plt.Figure):
43
+ print("Figure created successfully.")
44
+ # Optional: check plot content if needed
45
+ else:
46
+ print("Figure creation failed or None returned.")
47
+
48
+ expected_verdict = "produced by a generative AI" # Majority Fake
49
+ if expected_verdict in text:
50
+ print("Verdict seems correct (Fake majority).")
51
+ else:
52
+ print(f"Unexpected verdict. Expected '{expected_verdict}' in text.")
53
+
54
+ except Exception as e:
55
+ print(f"Test failed with exception: {e}")
56
+ finally:
57
+ if os.path.exists(img_path):
58
+ os.remove(img_path)
59
+
60
+ def test_single_option():
61
+ print("\nTesting 'R50_TF' option with MOCKED results...")
62
+ img_path = create_dummy_image("test_image_single.jpg")
63
+
64
+ with patch('app.run_single_detection', side_effect=mock_run_single_detection):
65
+ try:
66
+ # Run predict with single detector
67
+ text, fig = predict(img_path, 'R50_TF')
68
+
69
+ print(f"Output type: {type(text)}, {type(fig)}")
70
+ print(f"Text output: {text}")
71
+
72
+ if fig is None:
73
+ print("Figure is None as expected.")
74
+ else:
75
+ print("Figure should be None for single detector.")
76
+
77
+ try:
78
+ json_out = json.loads(text)
79
+ print("JSON output parsed successfully.")
80
+ if json_out.get("Prediction") == "fake":
81
+ print("JSON content seems correct.")
82
+ except:
83
+ print("Failed to parse JSON output.")
84
+
85
+ except Exception as e:
86
+ print(f"Test failed with exception: {e}")
87
+ finally:
88
+ if os.path.exists(img_path):
89
+ os.remove(img_path)
90
+
91
+ if __name__ == "__main__":
92
+ test_all_option()
93
+ test_single_option()