Upload folder using huggingface_hub
Browse files- app.py +16 -49
- detectors/itsnotai.py +10 -2
- requirements.txt +0 -5
app.py
CHANGED
|
@@ -201,8 +201,13 @@ def analyze_forensics(
|
|
| 201 |
verdict_html += "</div>"
|
| 202 |
|
| 203 |
# Overlay Image (Original + Heatmap)
|
| 204 |
-
|
| 205 |
-
if
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 206 |
overlay_img = image
|
| 207 |
|
| 208 |
# Consensus Table
|
|
@@ -252,15 +257,18 @@ def analyze_forensics(
|
|
| 252 |
# ─────────────────────────────────────────────────────────────────────────────
|
| 253 |
# Interactive Forensic Investigator Chat (Multi-turn)
|
| 254 |
# ─────────────────────────────────────────────────────────────────────────────
|
| 255 |
-
async def chat_investigator_fn(message: str, history: List[
|
| 256 |
-
if not message.strip():
|
| 257 |
-
return history, ""
|
| 258 |
|
| 259 |
messages = []
|
| 260 |
if history:
|
| 261 |
for msg in history:
|
| 262 |
if isinstance(msg, dict):
|
| 263 |
messages.append({"role": msg.get("role", "user"), "content": msg.get("content", "")})
|
|
|
|
|
|
|
|
|
|
| 264 |
messages.append({"role": "user", "content": message})
|
| 265 |
|
| 266 |
result = await chat_with_forensic_context(
|
|
@@ -366,7 +374,7 @@ with gr.Blocks(title="DeepGuard — Forensic Detection") as demo:
|
|
| 366 |
gr.Markdown("### 🕵️ Interactive Forensic Investigator Chat")
|
| 367 |
gr.Markdown("Inquire deeper into model decision boundaries, specific attention zones, or contradictory detector signals.")
|
| 368 |
|
| 369 |
-
chatbot = gr.Chatbot(height=320, label="DeepGuard Forensic Investigator")
|
| 370 |
with gr.Row():
|
| 371 |
chat_input = gr.Textbox(
|
| 372 |
placeholder="Ask about this image's verdict, Grad-CAM peaks, or provenance flags...",
|
|
@@ -395,47 +403,6 @@ with gr.Blocks(title="DeepGuard — Forensic Detection") as demo:
|
|
| 395 |
|
| 396 |
|
| 397 |
# ─────────────────────────────────────────────────────────────────────────────
|
| 398 |
-
#
|
| 399 |
# ─────────────────────────────────────────────────────────────────────────────
|
| 400 |
-
|
| 401 |
-
api_app.add_middleware(
|
| 402 |
-
CORSMiddleware,
|
| 403 |
-
allow_origins=["*"],
|
| 404 |
-
allow_credentials=True,
|
| 405 |
-
allow_methods=["*"],
|
| 406 |
-
allow_headers=["*"],
|
| 407 |
-
)
|
| 408 |
-
|
| 409 |
-
|
| 410 |
-
@api_app.get("/health")
|
| 411 |
-
async def health():
|
| 412 |
-
return {
|
| 413 |
-
"status": "ok",
|
| 414 |
-
"service": "DeepGuard HF Space (ZeroGPU)",
|
| 415 |
-
"device": str(DEVICE),
|
| 416 |
-
"zerogpu": has_spaces,
|
| 417 |
-
}
|
| 418 |
-
|
| 419 |
-
|
| 420 |
-
class ChatRequest(BaseModel):
|
| 421 |
-
message: str
|
| 422 |
-
history: Optional[List[Dict[str, str]]] = []
|
| 423 |
-
forensic_context: Dict[str, Any]
|
| 424 |
-
|
| 425 |
-
|
| 426 |
-
@api_app.post("/chat")
|
| 427 |
-
async def api_chat(req: ChatRequest):
|
| 428 |
-
messages = list(req.history or [])
|
| 429 |
-
messages.append({"role": "user", "content": req.message})
|
| 430 |
-
result = await chat_with_forensic_context(
|
| 431 |
-
messages=messages,
|
| 432 |
-
forensic_context=req.forensic_context,
|
| 433 |
-
)
|
| 434 |
-
return {"reply": result.get("reply", "")}
|
| 435 |
-
|
| 436 |
-
|
| 437 |
-
# Mount Gradio onto FastAPI
|
| 438 |
-
app = gr.mount_gradio_app(api_app, demo, path="/")
|
| 439 |
-
|
| 440 |
-
if __name__ == "__main__":
|
| 441 |
-
demo.launch()
|
|
|
|
| 201 |
verdict_html += "</div>"
|
| 202 |
|
| 203 |
# Overlay Image (Original + Heatmap)
|
| 204 |
+
heatmap_bytes = explainability.get("heatmap_bytes")
|
| 205 |
+
if heatmap_bytes:
|
| 206 |
+
try:
|
| 207 |
+
overlay_img = Image.open(io.BytesIO(heatmap_bytes))
|
| 208 |
+
except Exception:
|
| 209 |
+
overlay_img = image
|
| 210 |
+
else:
|
| 211 |
overlay_img = image
|
| 212 |
|
| 213 |
# Consensus Table
|
|
|
|
| 257 |
# ─────────────────────────────────────────────────────────────────────────────
|
| 258 |
# Interactive Forensic Investigator Chat (Multi-turn)
|
| 259 |
# ─────────────────────────────────────────────────────────────────────────────
|
| 260 |
+
async def chat_investigator_fn(message: str, history: Optional[List[Any]], context: Dict[str, Any]):
|
| 261 |
+
if not message or not message.strip():
|
| 262 |
+
return history or [], ""
|
| 263 |
|
| 264 |
messages = []
|
| 265 |
if history:
|
| 266 |
for msg in history:
|
| 267 |
if isinstance(msg, dict):
|
| 268 |
messages.append({"role": msg.get("role", "user"), "content": msg.get("content", "")})
|
| 269 |
+
elif isinstance(msg, (list, tuple)) and len(msg) >= 2:
|
| 270 |
+
messages.append({"role": "user", "content": str(msg[0])})
|
| 271 |
+
messages.append({"role": "assistant", "content": str(msg[1])})
|
| 272 |
messages.append({"role": "user", "content": message})
|
| 273 |
|
| 274 |
result = await chat_with_forensic_context(
|
|
|
|
| 374 |
gr.Markdown("### 🕵️ Interactive Forensic Investigator Chat")
|
| 375 |
gr.Markdown("Inquire deeper into model decision boundaries, specific attention zones, or contradictory detector signals.")
|
| 376 |
|
| 377 |
+
chatbot = gr.Chatbot(height=320, label="DeepGuard Forensic Investigator", type="messages")
|
| 378 |
with gr.Row():
|
| 379 |
chat_input = gr.Textbox(
|
| 380 |
placeholder="Ask about this image's verdict, Grad-CAM peaks, or provenance flags...",
|
|
|
|
| 403 |
|
| 404 |
|
| 405 |
# ─────────────────────────────────────────────────────────────────────────────
|
| 406 |
+
# Launch ZeroGPU Space
|
| 407 |
# ─────────────────────────────────────────────────────────────────────────────
|
| 408 |
+
demo.queue(default_concurrency_limit=5).launch()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
detectors/itsnotai.py
CHANGED
|
@@ -160,5 +160,13 @@ class ItsNotAIDetector(BaseDetector):
|
|
| 160 |
|
| 161 |
def get_gradcam_target_layer(self) -> torch.nn.Module:
|
| 162 |
self._ensure_loaded()
|
| 163 |
-
|
| 164 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 160 |
|
| 161 |
def get_gradcam_target_layer(self) -> torch.nn.Module:
|
| 162 |
self._ensure_loaded()
|
| 163 |
+
if hasattr(self._model, "beit"):
|
| 164 |
+
beit = self._model.beit
|
| 165 |
+
if hasattr(beit, "encoder") and hasattr(beit.encoder, "layer") and len(beit.encoder.layer) > 0:
|
| 166 |
+
layer = beit.encoder.layer[-1]
|
| 167 |
+
return getattr(layer, "output", layer)
|
| 168 |
+
if hasattr(beit, "layers") and len(beit.layers) > 0:
|
| 169 |
+
layer = beit.layers[-1]
|
| 170 |
+
return getattr(layer, "mlp", layer)
|
| 171 |
+
children = list(self._model.children())
|
| 172 |
+
return children[-2] if len(children) >= 2 else children[-1]
|
requirements.txt
CHANGED
|
@@ -1,7 +1,5 @@
|
|
| 1 |
gradio>=5.0.0
|
| 2 |
transformers
|
| 3 |
-
torch
|
| 4 |
-
torchvision
|
| 5 |
Pillow
|
| 6 |
numpy
|
| 7 |
matplotlib
|
|
@@ -13,6 +11,3 @@ scikit-learn
|
|
| 13 |
grad-cam
|
| 14 |
scipy
|
| 15 |
peft
|
| 16 |
-
fastapi
|
| 17 |
-
python-multipart
|
| 18 |
-
uvicorn
|
|
|
|
| 1 |
gradio>=5.0.0
|
| 2 |
transformers
|
|
|
|
|
|
|
| 3 |
Pillow
|
| 4 |
numpy
|
| 5 |
matplotlib
|
|
|
|
| 11 |
grad-cam
|
| 12 |
scipy
|
| 13 |
peft
|
|
|
|
|
|
|
|
|