Spaces:
Running
Running
Commit ·
caff5a8
1
Parent(s): a05aa5d
Expand to 5 models safely, no secrets
Browse files- ai_router.py +7 -1
- error.log +0 -0
- models/blip_yolo_model.py +47 -0
- models/hf_boss_api.py +84 -0
- requirements.txt +2 -1
- static/app.js +8 -6
- templates/index.html +3 -1
ai_router.py
CHANGED
|
@@ -2,6 +2,8 @@ from models.blip_model import blip_answer
|
|
| 2 |
from models.reasoning_model import reasoning_answer
|
| 3 |
from models.gemini_vision import gemini_vision_answer
|
| 4 |
from models.groq_vision import groq_vision_answer
|
|
|
|
|
|
|
| 5 |
|
| 6 |
try:
|
| 7 |
from deep_translator import GoogleTranslator
|
|
@@ -19,11 +21,15 @@ def route_model(model_choice, image, question, lang="en"):
|
|
| 19 |
|
| 20 |
# Model Execution
|
| 21 |
if model_choice == "local":
|
| 22 |
-
cap, ans, exp =
|
|
|
|
|
|
|
| 23 |
elif model_choice == "gemini":
|
| 24 |
cap, ans, exp = gemini_vision_answer(image, question, lang)
|
| 25 |
elif model_choice == "groq":
|
| 26 |
cap, ans, exp = groq_vision_answer(image, question, lang)
|
|
|
|
|
|
|
| 27 |
else:
|
| 28 |
cap, ans, exp = "Unknown", "Invalid", "Invalid"
|
| 29 |
|
|
|
|
| 2 |
from models.reasoning_model import reasoning_answer
|
| 3 |
from models.gemini_vision import gemini_vision_answer
|
| 4 |
from models.groq_vision import groq_vision_answer
|
| 5 |
+
from models.blip_yolo_model import blip_yolo_answer
|
| 6 |
+
from models.hf_boss_api import hf_boss_answer
|
| 7 |
|
| 8 |
try:
|
| 9 |
from deep_translator import GoogleTranslator
|
|
|
|
| 21 |
|
| 22 |
# Model Execution
|
| 23 |
if model_choice == "local":
|
| 24 |
+
cap, ans, exp = blip_answer(image, question, lang)
|
| 25 |
+
elif model_choice == "local_yolo":
|
| 26 |
+
cap, ans, exp = blip_yolo_answer(image, question, lang)
|
| 27 |
elif model_choice == "gemini":
|
| 28 |
cap, ans, exp = gemini_vision_answer(image, question, lang)
|
| 29 |
elif model_choice == "groq":
|
| 30 |
cap, ans, exp = groq_vision_answer(image, question, lang)
|
| 31 |
+
elif model_choice == "hf_boss":
|
| 32 |
+
cap, ans, exp = hf_boss_answer(image, question, lang)
|
| 33 |
else:
|
| 34 |
cap, ans, exp = "Unknown", "Invalid", "Invalid"
|
| 35 |
|
error.log
ADDED
|
Binary file (2.82 kB). View file
|
|
|
models/blip_yolo_model.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from models.blip_model import processor_blip, model_blip, tokenizer_t5, model_t5
|
| 2 |
+
try:
|
| 3 |
+
from ultralytics import YOLO
|
| 4 |
+
yolo_model = YOLO("yolov8n.pt")
|
| 5 |
+
except Exception as e:
|
| 6 |
+
print("YOLO initialization failed:", e)
|
| 7 |
+
yolo_model = None
|
| 8 |
+
|
| 9 |
+
def blip_yolo_answer(image, question, lang="en"):
|
| 10 |
+
objects_detected = []
|
| 11 |
+
if yolo_model is not None:
|
| 12 |
+
try:
|
| 13 |
+
results = yolo_model(image)
|
| 14 |
+
for r in results:
|
| 15 |
+
for c in r.boxes.cls:
|
| 16 |
+
objects_detected.append(yolo_model.names[int(c)])
|
| 17 |
+
except:
|
| 18 |
+
pass
|
| 19 |
+
|
| 20 |
+
yolo_context = ""
|
| 21 |
+
det_str = "None"
|
| 22 |
+
if objects_detected:
|
| 23 |
+
unique_objs = list(set(objects_detected))
|
| 24 |
+
counts = {obj: objects_detected.count(obj) for obj in unique_objs}
|
| 25 |
+
det_str = ", ".join([f"{count} {obj}(s)" for obj, count in counts.items()])
|
| 26 |
+
yolo_context = f"YOLO precisely detected: {det_str}. "
|
| 27 |
+
|
| 28 |
+
inputs = processor_blip(image, return_tensors="pt")
|
| 29 |
+
out = model_blip.generate(**inputs, max_new_tokens=50)
|
| 30 |
+
blip_caption = processor_blip.decode(out[0], skip_special_tokens=True)
|
| 31 |
+
|
| 32 |
+
caption = f"{yolo_context}General context: {blip_caption}".strip()
|
| 33 |
+
|
| 34 |
+
prompt = f"""Based on this visual context:
|
| 35 |
+
{caption}
|
| 36 |
+
|
| 37 |
+
Question: {question}
|
| 38 |
+
|
| 39 |
+
Provide ONLY the final answer in exact one line. Do not explain here."""
|
| 40 |
+
|
| 41 |
+
input_ids = tokenizer_t5(prompt, return_tensors="pt").input_ids
|
| 42 |
+
out_answer = model_t5.generate(input_ids, max_new_tokens=50)
|
| 43 |
+
answer = tokenizer_t5.decode(out_answer[0], skip_special_tokens=True)
|
| 44 |
+
|
| 45 |
+
explanation = f"YOLO identified specific objects: {det_str}. BLIP provided the overall scene context. FLAN synthesized the concise answer based on these inputs."
|
| 46 |
+
|
| 47 |
+
return caption, answer, explanation
|
models/hf_boss_api.py
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import io
|
| 3 |
+
import base64
|
| 4 |
+
import requests
|
| 5 |
+
import re
|
| 6 |
+
|
| 7 |
+
def hf_boss_answer(image, question, lang="en"):
|
| 8 |
+
token = os.getenv("HF_TOKEN")
|
| 9 |
+
if not token:
|
| 10 |
+
return "Setup Required", "HF Token is missing.", "Please set HF_TOKEN."
|
| 11 |
+
|
| 12 |
+
try:
|
| 13 |
+
model_id = "meta-llama/Llama-3.2-11B-Vision-Instruct"
|
| 14 |
+
api_url = f"https://api-inference.huggingface.co/models/{model_id}/v1/chat/completions"
|
| 15 |
+
|
| 16 |
+
headers = {
|
| 17 |
+
"Authorization": f"Bearer {token}",
|
| 18 |
+
"Content-Type": "application/json"
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
if image.mode != 'RGB':
|
| 22 |
+
image = image.convert('RGB')
|
| 23 |
+
|
| 24 |
+
image.thumbnail((800, 800))
|
| 25 |
+
buffered = io.BytesIO()
|
| 26 |
+
image.save(buffered, format="JPEG", quality=85)
|
| 27 |
+
img_b64 = base64.b64encode(buffered.getvalue()).decode("utf-8")
|
| 28 |
+
img_data_url = f"data:image/jpeg;base64,{img_b64}"
|
| 29 |
+
|
| 30 |
+
prompt = f"""Analyze this image carefully.
|
| 31 |
+
|
| 32 |
+
Question: {question}
|
| 33 |
+
|
| 34 |
+
CRITICAL RULES:
|
| 35 |
+
1. You MUST respond strictly in language code: {lang}. All text in output must be translated to '{lang}'.
|
| 36 |
+
2. You MUST use EXACTLY the format below with these English labels.
|
| 37 |
+
3. Caption MUST be exactly 1 line only.
|
| 38 |
+
4. Final Answer MUST be exactly 1 line only.
|
| 39 |
+
5. Explanation MUST be strictly 2 to 3 lines maximum.
|
| 40 |
+
|
| 41 |
+
Respond exactly like this:
|
| 42 |
+
Caption: <one-line caption>
|
| 43 |
+
Final Answer: <one-line answer>
|
| 44 |
+
Explanation: <2-3 lines max explanation>"""
|
| 45 |
+
|
| 46 |
+
payload = {
|
| 47 |
+
"model": model_id,
|
| 48 |
+
"messages": [
|
| 49 |
+
{
|
| 50 |
+
"role": "user",
|
| 51 |
+
"content": [
|
| 52 |
+
{"type": "text", "text": prompt},
|
| 53 |
+
{"type": "image_url", "image_url": {"url": img_data_url}}
|
| 54 |
+
]
|
| 55 |
+
}
|
| 56 |
+
],
|
| 57 |
+
"max_tokens": 512,
|
| 58 |
+
"temperature": 0.2
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
response = requests.post(api_url, headers=headers, json=payload, timeout=60)
|
| 62 |
+
|
| 63 |
+
if response.status_code != 200:
|
| 64 |
+
return "HF Boss Server Error", f"HTTP {response.status_code}", response.text
|
| 65 |
+
|
| 66 |
+
data = response.json()
|
| 67 |
+
raw_text = data["choices"][0]["message"]["content"]
|
| 68 |
+
|
| 69 |
+
caption_match = re.search(r'Caption:\s*(.*?)(?=Final Answer:|$)', raw_text, re.IGNORECASE | re.DOTALL)
|
| 70 |
+
answer_match = re.search(r'Final Answer:\s*(.*?)(?=Explanation:|$)', raw_text, re.IGNORECASE | re.DOTALL)
|
| 71 |
+
explanation_match = re.search(r'Explanation:\s*(.*)', raw_text, re.IGNORECASE | re.DOTALL)
|
| 72 |
+
|
| 73 |
+
caption = caption_match.group(1).strip() if caption_match else "Caption not generated correctly."
|
| 74 |
+
answer = answer_match.group(1).strip() if answer_match else raw_text.split('\n')[0]
|
| 75 |
+
explanation = explanation_match.group(1).strip() if explanation_match else "Explanation not generated correctly."
|
| 76 |
+
|
| 77 |
+
caption = caption.replace("**", "").replace("\n", " ")
|
| 78 |
+
answer = answer.replace("**", "").replace("\n", " ")
|
| 79 |
+
explanation = explanation.replace("**", "")
|
| 80 |
+
|
| 81 |
+
return caption, answer, explanation
|
| 82 |
+
|
| 83 |
+
except Exception as e:
|
| 84 |
+
return "HF Boss API Error", "The request crashed.", repr(e)
|
requirements.txt
CHANGED
|
@@ -10,4 +10,5 @@ deep-translator==1.11.4
|
|
| 10 |
einops>=0.6.1
|
| 11 |
timm>=0.9.2
|
| 12 |
huggingface_hub>=0.24.6
|
| 13 |
-
|
|
|
|
|
|
| 10 |
einops>=0.6.1
|
| 11 |
timm>=0.9.2
|
| 12 |
huggingface_hub>=0.24.6
|
| 13 |
+
ultralytics==8.1.0
|
| 14 |
+
opencv-python-headless
|
static/app.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
| 2 |
let appState = {
|
| 3 |
username: '',
|
| 4 |
logs: [],
|
| 5 |
-
stats: { total: 0, local: 0, gemini: 0, groq: 0 },
|
| 6 |
geminiEnabled: true
|
| 7 |
};
|
| 8 |
|
|
@@ -353,9 +353,11 @@ async function fetchLogs() {
|
|
| 353 |
|
| 354 |
appState.logs = data.logs || [];
|
| 355 |
appState.stats.total = appState.logs.length;
|
| 356 |
-
appState.stats.local = appState.logs.filter(l => ['local', 'blip'
|
|
|
|
| 357 |
appState.stats.gemini = appState.logs.filter(l => ['gemini', 'external'].includes(l.model.toLowerCase())).length;
|
| 358 |
appState.stats.groq = appState.logs.filter(l => l.model.toLowerCase().includes('groq')).length;
|
|
|
|
| 359 |
|
| 360 |
updateDashboardView();
|
| 361 |
} catch(err) {
|
|
@@ -409,12 +411,12 @@ function initChart() {
|
|
| 409 |
|
| 410 |
function getChartData() {
|
| 411 |
return {
|
| 412 |
-
labels: ['BLIP
|
| 413 |
datasets: [{
|
| 414 |
label: 'Queries',
|
| 415 |
-
data: [appState.stats.local, appState.stats.gemini, appState.stats.groq],
|
| 416 |
-
backgroundColor: ['rgba(16, 185, 129, 0.6)', 'rgba(99, 102, 241, 0.6)', 'rgba(245, 158, 11, 0.6)'],
|
| 417 |
-
borderColor: ['rgba(16, 185, 129, 1)', 'rgba(99, 102, 241, 1)', 'rgba(245, 158, 11, 1)'],
|
| 418 |
borderWidth: 1, borderRadius: 6
|
| 419 |
}]
|
| 420 |
};
|
|
|
|
| 2 |
let appState = {
|
| 3 |
username: '',
|
| 4 |
logs: [],
|
| 5 |
+
stats: { total: 0, local: 0, yolo: 0, gemini: 0, groq: 0, hf_boss: 0 },
|
| 6 |
geminiEnabled: true
|
| 7 |
};
|
| 8 |
|
|
|
|
| 353 |
|
| 354 |
appState.logs = data.logs || [];
|
| 355 |
appState.stats.total = appState.logs.length;
|
| 356 |
+
appState.stats.local = appState.logs.filter(l => ['local', 'blip'].includes(l.model.toLowerCase())).length;
|
| 357 |
+
appState.stats.yolo = appState.logs.filter(l => ['yolo', 'local_yolo'].includes(l.model.toLowerCase())).length;
|
| 358 |
appState.stats.gemini = appState.logs.filter(l => ['gemini', 'external'].includes(l.model.toLowerCase())).length;
|
| 359 |
appState.stats.groq = appState.logs.filter(l => l.model.toLowerCase().includes('groq')).length;
|
| 360 |
+
appState.stats.hf_boss = appState.logs.filter(l => l.model.toLowerCase().includes('hf_boss') || l.model.toLowerCase().includes('boss')).length;
|
| 361 |
|
| 362 |
updateDashboardView();
|
| 363 |
} catch(err) {
|
|
|
|
| 411 |
|
| 412 |
function getChartData() {
|
| 413 |
return {
|
| 414 |
+
labels: ['Local BLIP', 'Local YOLO', 'Gemini AI', 'Groq Vision', 'HF Boss API'],
|
| 415 |
datasets: [{
|
| 416 |
label: 'Queries',
|
| 417 |
+
data: [appState.stats.local, appState.stats.yolo, appState.stats.gemini, appState.stats.groq, appState.stats.hf_boss],
|
| 418 |
+
backgroundColor: ['rgba(16, 185, 129, 0.6)', 'rgba(52, 211, 153, 0.6)', 'rgba(99, 102, 241, 0.6)', 'rgba(245, 158, 11, 0.6)', 'rgba(139, 92, 246, 0.6)'],
|
| 419 |
+
borderColor: ['rgba(16, 185, 129, 1)', 'rgba(52, 211, 153, 1)', 'rgba(99, 102, 241, 1)', 'rgba(245, 158, 11, 1)', 'rgba(139, 92, 246, 1)'],
|
| 420 |
borderWidth: 1, borderRadius: 6
|
| 421 |
}]
|
| 422 |
};
|
templates/index.html
CHANGED
|
@@ -96,8 +96,10 @@
|
|
| 96 |
<label><i class="fa-solid fa-microchip"></i> Select Model</label>
|
| 97 |
<select id="model-selector">
|
| 98 |
<option value="local">BLIP + FLAN (Local)</option>
|
|
|
|
| 99 |
<option value="gemini" id="gemini-option">Gemini 3.1 Flash Vision (High Quota)</option>
|
| 100 |
-
<option value="groq" id="groq-option">Groq Native Vision: Llama 4 Scout
|
|
|
|
| 101 |
</select>
|
| 102 |
</div>
|
| 103 |
<div class="control-group" style="flex: 1;">
|
|
|
|
| 96 |
<label><i class="fa-solid fa-microchip"></i> Select Model</label>
|
| 97 |
<select id="model-selector">
|
| 98 |
<option value="local">BLIP + FLAN (Local)</option>
|
| 99 |
+
<option value="local_yolo">BLIP + FLAN + YOLO (Local Advanced)</option>
|
| 100 |
<option value="gemini" id="gemini-option">Gemini 3.1 Flash Vision (High Quota)</option>
|
| 101 |
+
<option value="groq" id="groq-option">Groq Native Vision: Llama 4 Scout</option>
|
| 102 |
+
<option value="hf_boss" id="hf-option">Hugging Face API: Llama 11B Vision (Unlimited Boss)</option>
|
| 103 |
</select>
|
| 104 |
</div>
|
| 105 |
<div class="control-group" style="flex: 1;">
|