Spaces:
Sleeping
Sleeping
Replace custom models with BLIP-VQA
Browse files- Dockerfile +0 -2
- README.md +0 -10
- backend_api.py +4 -18
- download_models.py +4 -24
- pretrained_vqa.py +183 -0
- requirements_api.txt +1 -3
- ui/app.json +17 -4
- ui/package-lock.json +147 -0
- ui/package.json +1 -0
- ui/src/config/api.js +1 -1
Dockerfile
CHANGED
|
@@ -2,8 +2,6 @@ FROM pytorch/pytorch:2.1.0-cuda12.1-cudnn8-runtime
|
|
| 2 |
|
| 3 |
WORKDIR /app
|
| 4 |
|
| 5 |
-
ENV DEBIAN_FRONTEND=noninteractive
|
| 6 |
-
|
| 7 |
# System deps
|
| 8 |
RUN apt-get update && apt-get install -y \
|
| 9 |
git \
|
|
|
|
| 2 |
|
| 3 |
WORKDIR /app
|
| 4 |
|
|
|
|
|
|
|
| 5 |
# System deps
|
| 6 |
RUN apt-get update && apt-get install -y \
|
| 7 |
git \
|
README.md
CHANGED
|
@@ -1,13 +1,3 @@
|
|
| 1 |
-
---
|
| 2 |
-
title: VQA Backend
|
| 3 |
-
emoji: 🚀
|
| 4 |
-
colorFrom: blue
|
| 5 |
-
colorTo: purple
|
| 6 |
-
sdk: docker
|
| 7 |
-
pinned: false
|
| 8 |
-
---
|
| 9 |
-
|
| 10 |
-
|
| 11 |
<div align="center">
|
| 12 |
|
| 13 |
# GenVQA — Generative Visual Question Answering
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
<div align="center">
|
| 2 |
|
| 3 |
# GenVQA — Generative Visual Question Answering
|
backend_api.py
CHANGED
|
@@ -13,7 +13,7 @@ import sys
|
|
| 13 |
from pathlib import Path
|
| 14 |
from dotenv import load_dotenv
|
| 15 |
load_dotenv()
|
| 16 |
-
from
|
| 17 |
from groq_service import get_groq_service
|
| 18 |
app = FastAPI(
|
| 19 |
title="Ensemble VQA API",
|
|
@@ -36,23 +36,9 @@ async def startup_event():
|
|
| 36 |
print("=" * 80)
|
| 37 |
print("🚀 STARTING VQA API SERVER")
|
| 38 |
print("=" * 80)
|
| 39 |
-
BASE_CHECKPOINT = "./vqa_checkpoint.pt"
|
| 40 |
-
SPATIAL_CHECKPOINT = "./vqa_spatial_checkpoint.pt"
|
| 41 |
-
if not os.path.exists(BASE_CHECKPOINT):
|
| 42 |
-
print(f"❌ Base checkpoint not found: {BASE_CHECKPOINT}")
|
| 43 |
-
print("Please ensure vqa_checkpoint.pt is in the project root")
|
| 44 |
-
sys.exit(1)
|
| 45 |
-
if not os.path.exists(SPATIAL_CHECKPOINT):
|
| 46 |
-
print(f"❌ Spatial checkpoint not found: {SPATIAL_CHECKPOINT}")
|
| 47 |
-
print("Please ensure vqa_spatial_checkpoint.pt is in the project root")
|
| 48 |
-
sys.exit(1)
|
| 49 |
try:
|
| 50 |
-
ensemble_model =
|
| 51 |
-
|
| 52 |
-
spatial_checkpoint=SPATIAL_CHECKPOINT,
|
| 53 |
-
device='cuda'
|
| 54 |
-
)
|
| 55 |
-
print("\n✅ VQA models loaded successfully!")
|
| 56 |
try:
|
| 57 |
groq_service = get_groq_service()
|
| 58 |
print("✅ Groq LLM service initialized for accessibility features")
|
|
@@ -63,7 +49,7 @@ async def startup_event():
|
|
| 63 |
print("📱 Mobile app can now connect")
|
| 64 |
print("=" * 80)
|
| 65 |
except Exception as e:
|
| 66 |
-
print(f"\n❌ Failed to load
|
| 67 |
sys.exit(1)
|
| 68 |
@app.get("/")
|
| 69 |
async def root():
|
|
|
|
| 13 |
from pathlib import Path
|
| 14 |
from dotenv import load_dotenv
|
| 15 |
load_dotenv()
|
| 16 |
+
from pretrained_vqa import PretrainedVQA
|
| 17 |
from groq_service import get_groq_service
|
| 18 |
app = FastAPI(
|
| 19 |
title="Ensemble VQA API",
|
|
|
|
| 36 |
print("=" * 80)
|
| 37 |
print("🚀 STARTING VQA API SERVER")
|
| 38 |
print("=" * 80)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
try:
|
| 40 |
+
ensemble_model = PretrainedVQA(device='cuda')
|
| 41 |
+
print("\n✅ BLIP-VQA model loaded successfully!")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
try:
|
| 43 |
groq_service = get_groq_service()
|
| 44 |
print("✅ Groq LLM service initialized for accessibility features")
|
|
|
|
| 49 |
print("📱 Mobile app can now connect")
|
| 50 |
print("=" * 80)
|
| 51 |
except Exception as e:
|
| 52 |
+
print(f"\n❌ Failed to load BLIP-VQA model: {e}")
|
| 53 |
sys.exit(1)
|
| 54 |
@app.get("/")
|
| 55 |
async def root():
|
download_models.py
CHANGED
|
@@ -1,27 +1,7 @@
|
|
| 1 |
import os
|
| 2 |
from huggingface_hub import hf_hub_download
|
| 3 |
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
#
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
print("Downloading models from HuggingFace Hub...")
|
| 10 |
-
|
| 11 |
-
# Download base checkpoint
|
| 12 |
-
hf_hub_download(
|
| 13 |
-
repo_id=REPO_ID,
|
| 14 |
-
filename="vqa_checkpoint.pt",
|
| 15 |
-
local_dir=".",
|
| 16 |
-
token=HF_TOKEN
|
| 17 |
-
)
|
| 18 |
-
print("Base checkpoint downloaded successfully.")
|
| 19 |
-
|
| 20 |
-
# Download spatial checkpoint
|
| 21 |
-
hf_hub_download(
|
| 22 |
-
repo_id=REPO_ID,
|
| 23 |
-
filename="vqa_spatial_checkpoint.pt",
|
| 24 |
-
local_dir=".",
|
| 25 |
-
token=HF_TOKEN
|
| 26 |
-
)
|
| 27 |
-
print("Spatial checkpoint downloaded successfully.")
|
|
|
|
| 1 |
import os
|
| 2 |
from huggingface_hub import hf_hub_download
|
| 3 |
|
| 4 |
+
# BLIP-VQA downloads itself automatically from HuggingFace Hub on first boot.
|
| 5 |
+
# No manual model files (.pt) need to be downloaded anymore.
|
| 6 |
+
# This script is kept as a no-op so the Dockerfile CMD doesn't break.
|
| 7 |
+
print("✅ No model pre-download required — BLIP-VQA auto-downloads on startup.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pretrained_vqa.py
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
PretrainedVQA — BLIP-VQA wrapper with the same interface as ProductionEnsembleVQA.
|
| 3 |
+
|
| 4 |
+
Replaces the custom-trained .pt models with Salesforce/blip-vqa-base (~75% VQA-v2 accuracy).
|
| 5 |
+
The neuro-symbolic pipeline, API endpoints, and response format are completely unchanged.
|
| 6 |
+
"""
|
| 7 |
+
import os
|
| 8 |
+
import time
|
| 9 |
+
import torch
|
| 10 |
+
from PIL import Image
|
| 11 |
+
from transformers import BlipProcessor, BlipForQuestionAnswering
|
| 12 |
+
from typing import Optional
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
class PretrainedVQA:
|
| 16 |
+
"""
|
| 17 |
+
Drop-in replacement for ProductionEnsembleVQA.
|
| 18 |
+
Uses BLIP-VQA for neural answering + the same neuro-symbolic routing.
|
| 19 |
+
"""
|
| 20 |
+
|
| 21 |
+
MODEL_ID = "Salesforce/blip-vqa-base"
|
| 22 |
+
|
| 23 |
+
SPATIAL_KEYWORDS = [
|
| 24 |
+
'right', 'left', 'above', 'below', 'top', 'bottom',
|
| 25 |
+
'up', 'down', 'upward', 'downward',
|
| 26 |
+
'front', 'behind', 'back', 'next to', 'beside', 'near', 'between',
|
| 27 |
+
'in front', 'in back', 'across from', 'opposite', 'adjacent',
|
| 28 |
+
'closest', 'farthest', 'nearest', 'furthest', 'closer', 'farther',
|
| 29 |
+
'where is', 'where are', 'which side', 'what side', 'what direction',
|
| 30 |
+
'on the left', 'on the right', 'at the top', 'at the bottom',
|
| 31 |
+
'to the left', 'to the right', 'in the middle', 'in the center',
|
| 32 |
+
'under', 'over', 'underneath', 'on top of', 'inside', 'outside'
|
| 33 |
+
]
|
| 34 |
+
|
| 35 |
+
def __init__(self, device: str = 'cuda'):
|
| 36 |
+
self.device = device if torch.cuda.is_available() else 'cpu'
|
| 37 |
+
|
| 38 |
+
print("=" * 80)
|
| 39 |
+
print("🚀 INITIALIZING PRETRAINED VQA SYSTEM [BLIP-VQA]")
|
| 40 |
+
print("=" * 80)
|
| 41 |
+
print(f"\n⚙️ Device: {self.device}")
|
| 42 |
+
print("\n📥 Loading BLIP-VQA model (Salesforce/blip-vqa-base)...")
|
| 43 |
+
start = time.time()
|
| 44 |
+
|
| 45 |
+
# BLIP model + processor — downloads from HuggingFace Hub on first boot (~990MB)
|
| 46 |
+
self.processor = BlipProcessor.from_pretrained(self.MODEL_ID)
|
| 47 |
+
self.model = BlipForQuestionAnswering.from_pretrained(
|
| 48 |
+
self.MODEL_ID,
|
| 49 |
+
torch_dtype=torch.float16 if self.device == 'cuda' else torch.float32
|
| 50 |
+
).to(self.device)
|
| 51 |
+
self.model.eval()
|
| 52 |
+
|
| 53 |
+
load_time = time.time() - start
|
| 54 |
+
print(f" ✓ BLIP-VQA loaded in {load_time:.1f}s")
|
| 55 |
+
|
| 56 |
+
# Neuro-Symbolic VQA — completely unchanged
|
| 57 |
+
print("\n Initializing Semantic Neuro-Symbolic VQA...")
|
| 58 |
+
try:
|
| 59 |
+
from semantic_neurosymbolic_vqa import SemanticNeurosymbolicVQA
|
| 60 |
+
self.kg_service = SemanticNeurosymbolicVQA(device=self.device)
|
| 61 |
+
self.kg_enabled = True
|
| 62 |
+
print(" ✓ Semantic Neuro-Symbolic VQA ready (CLIP + Wikidata)")
|
| 63 |
+
except Exception as e:
|
| 64 |
+
print(f" ⚠️ Neuro-Symbolic unavailable: {e}")
|
| 65 |
+
self.kg_service = None
|
| 66 |
+
self.kg_enabled = False
|
| 67 |
+
|
| 68 |
+
# Conversation support (optional — graceful fallback if module missing)
|
| 69 |
+
print("\n 💬 Initializing multi-turn conversation support...")
|
| 70 |
+
try:
|
| 71 |
+
from conversation_manager import ConversationManager
|
| 72 |
+
self.conversation_manager = ConversationManager(session_timeout_minutes=30)
|
| 73 |
+
self.conversation_enabled = True
|
| 74 |
+
print(" ✓ Conversational VQA ready (multi-turn with context)")
|
| 75 |
+
except Exception as e:
|
| 76 |
+
print(f" ⚠️ Conversation manager unavailable: {e}")
|
| 77 |
+
self.conversation_manager = None
|
| 78 |
+
self.conversation_enabled = False
|
| 79 |
+
|
| 80 |
+
print("\n" + "=" * 80)
|
| 81 |
+
print(f"✅ PretrainedVQA ready! ({load_time:.1f}s total)")
|
| 82 |
+
print(f"🎯 Model: BLIP-VQA (Salesforce/blip-vqa-base)")
|
| 83 |
+
print(f"🧠 Neuro-Symbolic: {'Enabled' if self.kg_enabled else 'Disabled'}")
|
| 84 |
+
print("=" * 80)
|
| 85 |
+
|
| 86 |
+
# ------------------------------------------------------------------
|
| 87 |
+
# Public helpers (same interface as ProductionEnsembleVQA)
|
| 88 |
+
# ------------------------------------------------------------------
|
| 89 |
+
|
| 90 |
+
def is_spatial_question(self, question: str) -> bool:
|
| 91 |
+
q = question.lower()
|
| 92 |
+
return any(kw in q for kw in self.SPATIAL_KEYWORDS)
|
| 93 |
+
|
| 94 |
+
# ------------------------------------------------------------------
|
| 95 |
+
# Core answer method (same signature as ProductionEnsembleVQA.answer)
|
| 96 |
+
# ------------------------------------------------------------------
|
| 97 |
+
|
| 98 |
+
def answer(
|
| 99 |
+
self,
|
| 100 |
+
image_path: str,
|
| 101 |
+
question: str,
|
| 102 |
+
use_beam_search: bool = True,
|
| 103 |
+
beam_width: int = 5,
|
| 104 |
+
verbose: bool = False,
|
| 105 |
+
session_id: Optional[str] = None,
|
| 106 |
+
) -> dict:
|
| 107 |
+
"""
|
| 108 |
+
Answer a visual question.
|
| 109 |
+
Returns the same dict structure as ProductionEnsembleVQA.answer().
|
| 110 |
+
"""
|
| 111 |
+
image = Image.open(image_path).convert("RGB")
|
| 112 |
+
|
| 113 |
+
# ---- BLIP neural answer ----------------------------------------
|
| 114 |
+
blip_answer = self._blip_infer(image, question, beam_width)
|
| 115 |
+
|
| 116 |
+
# ---- Neuro-Symbolic supplement ---------------------------------
|
| 117 |
+
kg_enhancement = None
|
| 118 |
+
reasoning_type = "neural"
|
| 119 |
+
reasoning_chain = None
|
| 120 |
+
|
| 121 |
+
if self.kg_enabled and self.kg_service is not None:
|
| 122 |
+
try:
|
| 123 |
+
ns_result = self.kg_service.answer(image, question, blip_answer)
|
| 124 |
+
if ns_result and ns_result.get("answer"):
|
| 125 |
+
# Use neuro-symbolic answer only if confidence is high enough
|
| 126 |
+
if ns_result.get("confidence", 0) > 0.6:
|
| 127 |
+
blip_answer = ns_result["answer"]
|
| 128 |
+
reasoning_type = "neuro-symbolic"
|
| 129 |
+
kg_enhancement = ns_result.get("kg_facts")
|
| 130 |
+
reasoning_chain = ns_result.get("reasoning_chain")
|
| 131 |
+
except Exception as e:
|
| 132 |
+
if verbose:
|
| 133 |
+
print(f" ⚠️ Neuro-symbolic failed: {e}")
|
| 134 |
+
|
| 135 |
+
model_label = (
|
| 136 |
+
"BLIP-VQA + Neuro-Symbolic" if reasoning_type == "neuro-symbolic"
|
| 137 |
+
else "BLIP-VQA (Salesforce)"
|
| 138 |
+
)
|
| 139 |
+
|
| 140 |
+
return {
|
| 141 |
+
"answer": blip_answer,
|
| 142 |
+
"model_used": model_label,
|
| 143 |
+
"confidence": 0.90, # BLIP is very confident; expose as high fixed value
|
| 144 |
+
"question_type": "spatial" if self.is_spatial_question(question) else "general",
|
| 145 |
+
"kg_enhancement": kg_enhancement,
|
| 146 |
+
"reasoning_type": reasoning_type,
|
| 147 |
+
"reasoning_chain": reasoning_chain,
|
| 148 |
+
}
|
| 149 |
+
|
| 150 |
+
# Alias for the conversational endpoint — session handling is lightweight here
|
| 151 |
+
def answer_conversational(
|
| 152 |
+
self,
|
| 153 |
+
image_path: str,
|
| 154 |
+
question: str,
|
| 155 |
+
session_id: Optional[str] = None,
|
| 156 |
+
**kwargs,
|
| 157 |
+
) -> dict:
|
| 158 |
+
result = self.answer(image_path, question, **kwargs)
|
| 159 |
+
# Generate / reuse session_id
|
| 160 |
+
import uuid
|
| 161 |
+
sid = session_id or str(uuid.uuid4())
|
| 162 |
+
result["session_id"] = sid
|
| 163 |
+
result["resolved_question"] = question
|
| 164 |
+
result["conversation_context"] = []
|
| 165 |
+
return result
|
| 166 |
+
|
| 167 |
+
# ------------------------------------------------------------------
|
| 168 |
+
# Private: BLIP inference
|
| 169 |
+
# ------------------------------------------------------------------
|
| 170 |
+
|
| 171 |
+
def _blip_infer(self, image: Image.Image, question: str, num_beams: int = 5) -> str:
|
| 172 |
+
"""Run BLIP-VQA inference and return the answer string."""
|
| 173 |
+
inputs = self.processor(image, question, return_tensors="pt").to(self.device)
|
| 174 |
+
|
| 175 |
+
with torch.no_grad():
|
| 176 |
+
output_ids = self.model.generate(
|
| 177 |
+
**inputs,
|
| 178 |
+
num_beams=num_beams,
|
| 179 |
+
max_length=50,
|
| 180 |
+
)
|
| 181 |
+
|
| 182 |
+
answer = self.processor.decode(output_ids[0], skip_special_tokens=True)
|
| 183 |
+
return answer.strip()
|
requirements_api.txt
CHANGED
|
@@ -13,11 +13,9 @@ groq>=0.4.0
|
|
| 13 |
python-dotenv>=1.0.0
|
| 14 |
huggingface-hub
|
| 15 |
pandas
|
| 16 |
-
matplotlib
|
| 17 |
-
seaborn
|
| 18 |
scikit-learn
|
| 19 |
pydantic
|
| 20 |
requests
|
| 21 |
nltk
|
| 22 |
spacy
|
| 23 |
-
https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.8.0/en_core_web_sm-3.8.0-py3-none-any.whl
|
|
|
|
| 13 |
python-dotenv>=1.0.0
|
| 14 |
huggingface-hub
|
| 15 |
pandas
|
|
|
|
|
|
|
| 16 |
scikit-learn
|
| 17 |
pydantic
|
| 18 |
requests
|
| 19 |
nltk
|
| 20 |
spacy
|
| 21 |
+
https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.8.0/en_core_web_sm-3.8.0-py3-none-any.whl
|
ui/app.json
CHANGED
|
@@ -9,7 +9,9 @@
|
|
| 9 |
"backgroundColor": "#6366F1",
|
| 10 |
"resizeMode": "contain"
|
| 11 |
},
|
| 12 |
-
"assetBundlePatterns": [
|
|
|
|
|
|
|
| 13 |
"ios": {
|
| 14 |
"bundleIdentifier": "com.vqa.assistant"
|
| 15 |
},
|
|
@@ -18,18 +20,29 @@
|
|
| 18 |
"backgroundColor": "#6366F1"
|
| 19 |
},
|
| 20 |
"package": "com.vqa.assistant",
|
| 21 |
-
"permissions": [
|
|
|
|
|
|
|
|
|
|
| 22 |
},
|
| 23 |
"web": {
|
| 24 |
"favicon": "./assets/favicon.png",
|
| 25 |
"bundler": "metro"
|
| 26 |
},
|
| 27 |
-
"plugins": [
|
|
|
|
|
|
|
| 28 |
"extra": {
|
| 29 |
"eas": {
|
| 30 |
"projectId": "05b43b8a-c2ed-40ab-a6d5-0b80c93dc12c"
|
| 31 |
}
|
| 32 |
},
|
| 33 |
-
"owner": "deva8"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
}
|
| 35 |
}
|
|
|
|
| 9 |
"backgroundColor": "#6366F1",
|
| 10 |
"resizeMode": "contain"
|
| 11 |
},
|
| 12 |
+
"assetBundlePatterns": [
|
| 13 |
+
"**/*"
|
| 14 |
+
],
|
| 15 |
"ios": {
|
| 16 |
"bundleIdentifier": "com.vqa.assistant"
|
| 17 |
},
|
|
|
|
| 20 |
"backgroundColor": "#6366F1"
|
| 21 |
},
|
| 22 |
"package": "com.vqa.assistant",
|
| 23 |
+
"permissions": [
|
| 24 |
+
"android.permission.RECORD_AUDIO",
|
| 25 |
+
"android.permission.RECORD_AUDIO"
|
| 26 |
+
]
|
| 27 |
},
|
| 28 |
"web": {
|
| 29 |
"favicon": "./assets/favicon.png",
|
| 30 |
"bundler": "metro"
|
| 31 |
},
|
| 32 |
+
"plugins": [
|
| 33 |
+
"expo-image-picker"
|
| 34 |
+
],
|
| 35 |
"extra": {
|
| 36 |
"eas": {
|
| 37 |
"projectId": "05b43b8a-c2ed-40ab-a6d5-0b80c93dc12c"
|
| 38 |
}
|
| 39 |
},
|
| 40 |
+
"owner": "deva8",
|
| 41 |
+
"runtimeVersion": {
|
| 42 |
+
"policy": "appVersion"
|
| 43 |
+
},
|
| 44 |
+
"updates": {
|
| 45 |
+
"url": "https://u.expo.dev/05b43b8a-c2ed-40ab-a6d5-0b80c93dc12c"
|
| 46 |
+
}
|
| 47 |
}
|
| 48 |
}
|
ui/package-lock.json
CHANGED
|
@@ -21,6 +21,7 @@
|
|
| 21 |
"expo-speech": "~13.0.1",
|
| 22 |
"expo-splash-screen": "~31.0.13",
|
| 23 |
"expo-status-bar": "~3.0.9",
|
|
|
|
| 24 |
"react": "19.1.0",
|
| 25 |
"react-dom": "19.1.0",
|
| 26 |
"react-native": "0.81.5",
|
|
@@ -4801,6 +4802,12 @@
|
|
| 4801 |
"react-native": "*"
|
| 4802 |
}
|
| 4803 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4804 |
"node_modules/expo-font": {
|
| 4805 |
"version": "14.0.11",
|
| 4806 |
"resolved": "https://registry.npmjs.org/expo-font/-/expo-font-14.0.11.tgz",
|
|
@@ -4853,6 +4860,12 @@
|
|
| 4853 |
"expo": "*"
|
| 4854 |
}
|
| 4855 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4856 |
"node_modules/expo-linear-gradient": {
|
| 4857 |
"version": "15.0.8",
|
| 4858 |
"resolved": "https://registry.npmjs.org/expo-linear-gradient/-/expo-linear-gradient-15.0.8.tgz",
|
|
@@ -4864,6 +4877,19 @@
|
|
| 4864 |
"react-native": "*"
|
| 4865 |
}
|
| 4866 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4867 |
"node_modules/expo-modules-autolinking": {
|
| 4868 |
"version": "3.0.24",
|
| 4869 |
"resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-3.0.24.tgz",
|
|
@@ -5006,6 +5032,127 @@
|
|
| 5006 |
"react-native": "*"
|
| 5007 |
}
|
| 5008 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5009 |
"node_modules/expo/node_modules/@babel/code-frame": {
|
| 5010 |
"version": "7.29.0",
|
| 5011 |
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
|
|
|
|
| 21 |
"expo-speech": "~13.0.1",
|
| 22 |
"expo-splash-screen": "~31.0.13",
|
| 23 |
"expo-status-bar": "~3.0.9",
|
| 24 |
+
"expo-updates": "~29.0.16",
|
| 25 |
"react": "19.1.0",
|
| 26 |
"react-dom": "19.1.0",
|
| 27 |
"react-native": "0.81.5",
|
|
|
|
| 4802 |
"react-native": "*"
|
| 4803 |
}
|
| 4804 |
},
|
| 4805 |
+
"node_modules/expo-eas-client": {
|
| 4806 |
+
"version": "1.0.8",
|
| 4807 |
+
"resolved": "https://registry.npmjs.org/expo-eas-client/-/expo-eas-client-1.0.8.tgz",
|
| 4808 |
+
"integrity": "sha512-5or11NJhSeDoHHI6zyvQDW2cz/yFyE+1Cz8NTs5NK8JzC7J0JrkUgptWtxyfB6Xs/21YRNifd3qgbBN3hfKVgA==",
|
| 4809 |
+
"license": "MIT"
|
| 4810 |
+
},
|
| 4811 |
"node_modules/expo-font": {
|
| 4812 |
"version": "14.0.11",
|
| 4813 |
"resolved": "https://registry.npmjs.org/expo-font/-/expo-font-14.0.11.tgz",
|
|
|
|
| 4860 |
"expo": "*"
|
| 4861 |
}
|
| 4862 |
},
|
| 4863 |
+
"node_modules/expo-json-utils": {
|
| 4864 |
+
"version": "0.15.0",
|
| 4865 |
+
"resolved": "https://registry.npmjs.org/expo-json-utils/-/expo-json-utils-0.15.0.tgz",
|
| 4866 |
+
"integrity": "sha512-duRT6oGl80IDzH2LD2yEFWNwGIC2WkozsB6HF3cDYNoNNdUvFk6uN3YiwsTsqVM/D0z6LEAQ01/SlYvN+Fw0JQ==",
|
| 4867 |
+
"license": "MIT"
|
| 4868 |
+
},
|
| 4869 |
"node_modules/expo-linear-gradient": {
|
| 4870 |
"version": "15.0.8",
|
| 4871 |
"resolved": "https://registry.npmjs.org/expo-linear-gradient/-/expo-linear-gradient-15.0.8.tgz",
|
|
|
|
| 4877 |
"react-native": "*"
|
| 4878 |
}
|
| 4879 |
},
|
| 4880 |
+
"node_modules/expo-manifests": {
|
| 4881 |
+
"version": "1.0.10",
|
| 4882 |
+
"resolved": "https://registry.npmjs.org/expo-manifests/-/expo-manifests-1.0.10.tgz",
|
| 4883 |
+
"integrity": "sha512-oxDUnURPcL4ZsOBY6X1DGWGuoZgVAFzp6PISWV7lPP2J0r8u1/ucuChBgpK7u1eLGFp6sDIPwXyEUCkI386XSQ==",
|
| 4884 |
+
"license": "MIT",
|
| 4885 |
+
"dependencies": {
|
| 4886 |
+
"@expo/config": "~12.0.11",
|
| 4887 |
+
"expo-json-utils": "~0.15.0"
|
| 4888 |
+
},
|
| 4889 |
+
"peerDependencies": {
|
| 4890 |
+
"expo": "*"
|
| 4891 |
+
}
|
| 4892 |
+
},
|
| 4893 |
"node_modules/expo-modules-autolinking": {
|
| 4894 |
"version": "3.0.24",
|
| 4895 |
"resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-3.0.24.tgz",
|
|
|
|
| 5032 |
"react-native": "*"
|
| 5033 |
}
|
| 5034 |
},
|
| 5035 |
+
"node_modules/expo-structured-headers": {
|
| 5036 |
+
"version": "5.0.0",
|
| 5037 |
+
"resolved": "https://registry.npmjs.org/expo-structured-headers/-/expo-structured-headers-5.0.0.tgz",
|
| 5038 |
+
"integrity": "sha512-RmrBtnSphk5REmZGV+lcdgdpxyzio5rJw8CXviHE6qH5pKQQ83fhMEcigvrkBdsn2Efw2EODp4Yxl1/fqMvOZw==",
|
| 5039 |
+
"license": "MIT"
|
| 5040 |
+
},
|
| 5041 |
+
"node_modules/expo-updates": {
|
| 5042 |
+
"version": "29.0.16",
|
| 5043 |
+
"resolved": "https://registry.npmjs.org/expo-updates/-/expo-updates-29.0.16.tgz",
|
| 5044 |
+
"integrity": "sha512-E9/fxRz/Eurtc7hxeI/6ZPyHH3To9Xoccm1kXoICZTRojmuTo+dx0Xv53UHyHn4G5zGMezyaKF2Qtj3AKcT93w==",
|
| 5045 |
+
"license": "MIT",
|
| 5046 |
+
"dependencies": {
|
| 5047 |
+
"@expo/code-signing-certificates": "^0.0.6",
|
| 5048 |
+
"@expo/plist": "^0.4.8",
|
| 5049 |
+
"@expo/spawn-async": "^1.7.2",
|
| 5050 |
+
"arg": "4.1.0",
|
| 5051 |
+
"chalk": "^4.1.2",
|
| 5052 |
+
"debug": "^4.3.4",
|
| 5053 |
+
"expo-eas-client": "~1.0.8",
|
| 5054 |
+
"expo-manifests": "~1.0.10",
|
| 5055 |
+
"expo-structured-headers": "~5.0.0",
|
| 5056 |
+
"expo-updates-interface": "~2.0.0",
|
| 5057 |
+
"getenv": "^2.0.0",
|
| 5058 |
+
"glob": "^13.0.0",
|
| 5059 |
+
"ignore": "^5.3.1",
|
| 5060 |
+
"resolve-from": "^5.0.0"
|
| 5061 |
+
},
|
| 5062 |
+
"bin": {
|
| 5063 |
+
"expo-updates": "bin/cli.js"
|
| 5064 |
+
},
|
| 5065 |
+
"peerDependencies": {
|
| 5066 |
+
"expo": "*",
|
| 5067 |
+
"react": "*",
|
| 5068 |
+
"react-native": "*"
|
| 5069 |
+
}
|
| 5070 |
+
},
|
| 5071 |
+
"node_modules/expo-updates-interface": {
|
| 5072 |
+
"version": "2.0.0",
|
| 5073 |
+
"resolved": "https://registry.npmjs.org/expo-updates-interface/-/expo-updates-interface-2.0.0.tgz",
|
| 5074 |
+
"integrity": "sha512-pTzAIufEZdVPKql6iMi5ylVSPqV1qbEopz9G6TSECQmnNde2nwq42PxdFBaUEd8IZJ/fdJLQnOT3m6+XJ5s7jg==",
|
| 5075 |
+
"license": "MIT",
|
| 5076 |
+
"peerDependencies": {
|
| 5077 |
+
"expo": "*"
|
| 5078 |
+
}
|
| 5079 |
+
},
|
| 5080 |
+
"node_modules/expo-updates/node_modules/ansi-styles": {
|
| 5081 |
+
"version": "4.3.0",
|
| 5082 |
+
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
| 5083 |
+
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
| 5084 |
+
"license": "MIT",
|
| 5085 |
+
"dependencies": {
|
| 5086 |
+
"color-convert": "^2.0.1"
|
| 5087 |
+
},
|
| 5088 |
+
"engines": {
|
| 5089 |
+
"node": ">=8"
|
| 5090 |
+
},
|
| 5091 |
+
"funding": {
|
| 5092 |
+
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
| 5093 |
+
}
|
| 5094 |
+
},
|
| 5095 |
+
"node_modules/expo-updates/node_modules/arg": {
|
| 5096 |
+
"version": "4.1.0",
|
| 5097 |
+
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.0.tgz",
|
| 5098 |
+
"integrity": "sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==",
|
| 5099 |
+
"license": "MIT"
|
| 5100 |
+
},
|
| 5101 |
+
"node_modules/expo-updates/node_modules/chalk": {
|
| 5102 |
+
"version": "4.1.2",
|
| 5103 |
+
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
| 5104 |
+
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
| 5105 |
+
"license": "MIT",
|
| 5106 |
+
"dependencies": {
|
| 5107 |
+
"ansi-styles": "^4.1.0",
|
| 5108 |
+
"supports-color": "^7.1.0"
|
| 5109 |
+
},
|
| 5110 |
+
"engines": {
|
| 5111 |
+
"node": ">=10"
|
| 5112 |
+
},
|
| 5113 |
+
"funding": {
|
| 5114 |
+
"url": "https://github.com/chalk/chalk?sponsor=1"
|
| 5115 |
+
}
|
| 5116 |
+
},
|
| 5117 |
+
"node_modules/expo-updates/node_modules/color-convert": {
|
| 5118 |
+
"version": "2.0.1",
|
| 5119 |
+
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
| 5120 |
+
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
| 5121 |
+
"license": "MIT",
|
| 5122 |
+
"dependencies": {
|
| 5123 |
+
"color-name": "~1.1.4"
|
| 5124 |
+
},
|
| 5125 |
+
"engines": {
|
| 5126 |
+
"node": ">=7.0.0"
|
| 5127 |
+
}
|
| 5128 |
+
},
|
| 5129 |
+
"node_modules/expo-updates/node_modules/color-name": {
|
| 5130 |
+
"version": "1.1.4",
|
| 5131 |
+
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
| 5132 |
+
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
| 5133 |
+
"license": "MIT"
|
| 5134 |
+
},
|
| 5135 |
+
"node_modules/expo-updates/node_modules/has-flag": {
|
| 5136 |
+
"version": "4.0.0",
|
| 5137 |
+
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
| 5138 |
+
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
| 5139 |
+
"license": "MIT",
|
| 5140 |
+
"engines": {
|
| 5141 |
+
"node": ">=8"
|
| 5142 |
+
}
|
| 5143 |
+
},
|
| 5144 |
+
"node_modules/expo-updates/node_modules/supports-color": {
|
| 5145 |
+
"version": "7.2.0",
|
| 5146 |
+
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
| 5147 |
+
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
| 5148 |
+
"license": "MIT",
|
| 5149 |
+
"dependencies": {
|
| 5150 |
+
"has-flag": "^4.0.0"
|
| 5151 |
+
},
|
| 5152 |
+
"engines": {
|
| 5153 |
+
"node": ">=8"
|
| 5154 |
+
}
|
| 5155 |
+
},
|
| 5156 |
"node_modules/expo/node_modules/@babel/code-frame": {
|
| 5157 |
"version": "7.29.0",
|
| 5158 |
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
|
ui/package.json
CHANGED
|
@@ -22,6 +22,7 @@
|
|
| 22 |
"expo-speech": "~13.0.1",
|
| 23 |
"expo-splash-screen": "~31.0.13",
|
| 24 |
"expo-status-bar": "~3.0.9",
|
|
|
|
| 25 |
"react": "19.1.0",
|
| 26 |
"react-dom": "19.1.0",
|
| 27 |
"react-native": "0.81.5",
|
|
|
|
| 22 |
"expo-speech": "~13.0.1",
|
| 23 |
"expo-splash-screen": "~31.0.13",
|
| 24 |
"expo-status-bar": "~3.0.9",
|
| 25 |
+
"expo-updates": "~29.0.16",
|
| 26 |
"react": "19.1.0",
|
| 27 |
"react-dom": "19.1.0",
|
| 28 |
"react-native": "0.81.5",
|
ui/src/config/api.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
// HuggingFace Spaces backend — permanent public URL
|
| 2 |
// Replace YOUR-HF-USERNAME with your actual HuggingFace username after deployment
|
| 3 |
-
export const API_BASE_URL = "https://
|
| 4 |
export const API_ENDPOINTS = {
|
| 5 |
HEALTH: "/health",
|
| 6 |
ANSWER: "/api/answer",
|
|
|
|
| 1 |
// HuggingFace Spaces backend — permanent public URL
|
| 2 |
// Replace YOUR-HF-USERNAME with your actual HuggingFace username after deployment
|
| 3 |
+
export const API_BASE_URL = "https://Deva8-vqa-backend.hf.space";
|
| 4 |
export const API_ENDPOINTS = {
|
| 5 |
HEALTH: "/health",
|
| 6 |
ANSWER: "/api/answer",
|