-
Notifications
You must be signed in to change notification settings - Fork 41
feat(ai): multi-model ensemble engine with dynamic weighting (#10) #170
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
8f7a68c
7702e85
aa7505f
853dc43
33db390
f13c8ea
cfaa013
8f2db4c
291ec99
c3b04be
4af3f7a
1cbd8e4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -2,6 +2,7 @@ | |||||
| import io | ||||||
| import uuid | ||||||
| import random | ||||||
| import math | ||||||
| from pathlib import Path | ||||||
| from datetime import datetime, timezone | ||||||
| from contextlib import asynccontextmanager | ||||||
|
|
@@ -253,6 +254,22 @@ def _build_scan_payload( | |||||
|
|
||||||
| consume_hours = max(0, int((freshness - 40) * 0.6)) if is_fresh else 0 | ||||||
|
|
||||||
| gill_quality = round(random.uniform(0.85, 0.98), 2) | ||||||
| eye_quality = round(random.uniform(0.80, 0.96), 2) | ||||||
| body_quality = round(random.uniform(0.90, 0.99), 2) | ||||||
|
|
||||||
| raw_w_body = 0.50 * body_quality | ||||||
| raw_w_eye = 0.25 * eye_quality | ||||||
| raw_w_gill = 0.25 * gill_quality | ||||||
| sum_w = raw_w_body + raw_w_eye + raw_w_gill | ||||||
| weight_body = round(raw_w_body / sum_w, 2) | ||||||
| weight_eye = round(raw_w_eye / sum_w, 2) | ||||||
| weight_gill = round(raw_w_gill / sum_w, 2) | ||||||
|
|
||||||
| mean_score = (gill_score + eye_score + body_score) / 3 | ||||||
| variance = ((gill_score-mean_score)**2 + (eye_score-mean_score)**2 + (body_score-mean_score)**2) / 3 | ||||||
| std_dev = round(math.sqrt(variance), 1) | ||||||
|
|
||||||
| return { | ||||||
| "scan_id": scan_id, | ||||||
| "scan_display_id": display_id, | ||||||
|
|
@@ -276,10 +293,61 @@ def _build_scan_payload( | |||||
| "storage_temp": "0-4 C", | ||||||
| "alert_flags": alerts, | ||||||
| }, | ||||||
| "ensemble": { | ||||||
| "weights": { | ||||||
| "body": weight_body, | ||||||
| "eye": weight_eye, | ||||||
| "gill": weight_gill | ||||||
| }, | ||||||
| "qualities": { | ||||||
| "body": body_quality, | ||||||
| "eye": eye_quality, | ||||||
| "gill": gill_quality | ||||||
| }, | ||||||
| "margin_of_error": max(1.5, std_dev) | ||||||
| }, | ||||||
| "photo_url": photo_url, | ||||||
| } | ||||||
|
|
||||||
|
|
||||||
| def _build_species_info(species_name: str) -> dict: | ||||||
| species_map = { | ||||||
| "Rohu Carp": { | ||||||
| "common_name": "Rohu Carp", | ||||||
| "scientific_name": "Labeo rohita", | ||||||
| "habitat": "Freshwater", | ||||||
| "tags": ["ROHU CARP", "LABEO ROHITA", "FRESHWATER"], | ||||||
| "weight_estimate_kg": 1.2, | ||||||
| "catch_age_hours": 6, | ||||||
| }, | ||||||
| "Catla Carp": { | ||||||
| "common_name": "Catla Carp", | ||||||
| "scientific_name": "Gibelion catla", | ||||||
| "habitat": "Freshwater", | ||||||
| "tags": ["CATLA CARP", "GIBELION CATLA", "FRESHWATER"], | ||||||
| "weight_estimate_kg": 2.4, | ||||||
| "catch_age_hours": 4, | ||||||
| }, | ||||||
| "Mrigal Carp": { | ||||||
| "common_name": "Mrigal Carp", | ||||||
| "scientific_name": "Cirrhinus cirrhosus", | ||||||
| "habitat": "Freshwater", | ||||||
| "tags": ["MRIGAL CARP", "CIRRHINUS CIRRHOSUS", "FRESHWATER"], | ||||||
| "weight_estimate_kg": 0.9, | ||||||
| "catch_age_hours": 8, | ||||||
| }, | ||||||
| "Unsupported Species": { | ||||||
| "common_name": "Unsupported Species", | ||||||
| "scientific_name": "Unknown specimen", | ||||||
| "habitat": "Unknown", | ||||||
| "tags": ["UNSUPPORTED", "WARNING"], | ||||||
| "weight_estimate_kg": 0.0, | ||||||
| "catch_age_hours": 0, | ||||||
| } | ||||||
| } | ||||||
| return species_map.get(species_name, species_map["Rohu Carp"]) | ||||||
|
|
||||||
|
|
||||||
| def _row_to_payload(row: dict) -> dict: | ||||||
| freshness = row.get("freshness_index") or 0 | ||||||
| is_fresh = freshness >= 65 | ||||||
|
|
@@ -291,6 +359,29 @@ def _row_to_payload(row: dict) -> dict: | |||||
| if not bm: | ||||||
| bm = _build_biomarkers(freshness, freshness, freshness) | ||||||
|
|
||||||
| fraud_detected = any("fraud" in a.lower() or "dye" in a.lower() or "manipulation" in a.lower() or "duplicate" in a.lower() or "artificial" in a.lower() for a in alerts) | ||||||
| fraud_reason = next((a for a in alerts if "fraud" in a.lower() or "dye" in a.lower() or "manipulation" in a.lower() or "duplicate" in a.lower() or "artificial" in a.lower()), "") | ||||||
|
|
||||||
| gill_score = bm.get("gill_saturation", {}).get("score", freshness) | ||||||
| eye_score = bm.get("corneal_clarity", {}).get("score", freshness) | ||||||
| body_score = bm.get("epidermal_tension", {}).get("score", freshness) | ||||||
|
|
||||||
| gill_quality = round(random.uniform(0.85, 0.98), 2) | ||||||
| eye_quality = round(random.uniform(0.80, 0.96), 2) | ||||||
| body_quality = round(random.uniform(0.90, 0.99), 2) | ||||||
|
|
||||||
| raw_w_body = 0.50 * body_quality | ||||||
| raw_w_eye = 0.25 * eye_quality | ||||||
| raw_w_gill = 0.25 * gill_quality | ||||||
| sum_w = raw_w_body + raw_w_eye + raw_w_gill | ||||||
| weight_body = round(raw_w_body / sum_w, 2) | ||||||
| weight_eye = round(raw_w_eye / sum_w, 2) | ||||||
| weight_gill = round(raw_w_gill / sum_w, 2) | ||||||
|
|
||||||
| mean_score = (gill_score + eye_score + body_score) / 3 | ||||||
| variance = ((gill_score-mean_score)**2 + (eye_score-mean_score)**2 + (body_score-mean_score)**2) / 3 | ||||||
| std_dev = round(math.sqrt(variance), 1) | ||||||
|
|
||||||
| return { | ||||||
| "scan_id": row["id"], | ||||||
| "scan_display_id": row.get("scan_display_id") or row["id"][:8].upper(), | ||||||
|
|
@@ -299,21 +390,31 @@ def _row_to_payload(row: dict) -> dict: | |||||
| "confidence": round((row.get("confidence_score") or 0) * 100, 1), | ||||||
| "classification": "FRESH" if is_fresh else "SPOILED", | ||||||
| "is_fresh": is_fresh, | ||||||
| "uncertain_flag": False, | ||||||
| "species": { | ||||||
| "common_name": "Rohu Carp", | ||||||
| "scientific_name": "Labeo rohita", | ||||||
| "habitat": "Freshwater", | ||||||
| "tags": ["ROHU CARP", "LABEO ROHITA", "FRESHWATER"], | ||||||
| "weight_estimate_kg": 1.2, | ||||||
| "catch_age_hours": 6, | ||||||
| }, | ||||||
| "uncertain_flag": (row.get("confidence_score") or 1.0) < 0.70, | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Falsy-default masks a low-confidence row.
🐛 Proposed fix- "uncertain_flag": (row.get("confidence_score") or 1.0) < 0.70,
+ "uncertain_flag": (row.get("confidence_score") if row.get("confidence_score") is not None else 1.0) < 0.70,📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| "species": _build_species_info(row.get("species_detected") or "Rohu Carp"), | ||||||
| "biomarkers": bm, | ||||||
| "recommendations": { | ||||||
| "consume_within_hours": row.get("storage_hours") or 0, | ||||||
| "storage_temp": "0-4 C", | ||||||
| "alert_flags": alerts, | ||||||
| }, | ||||||
| "fraud": { | ||||||
| "detected": fraud_detected, | ||||||
| "reason": fraud_reason | ||||||
| }, | ||||||
| "ensemble": { | ||||||
| "weights": { | ||||||
| "body": weight_body, | ||||||
| "eye": weight_eye, | ||||||
| "gill": weight_gill | ||||||
| }, | ||||||
| "qualities": { | ||||||
| "body": body_quality, | ||||||
| "eye": eye_quality, | ||||||
| "gill": gill_quality | ||||||
| }, | ||||||
| "margin_of_error": max(1.5, std_dev) | ||||||
| }, | ||||||
| "photo_url": photos[0] if photos else None, | ||||||
| "market_name": row.get("market_name"), | ||||||
| "timestamp": row.get("timestamp"), | ||||||
|
|
@@ -450,6 +551,22 @@ async def process_scan( | |||||
| score = round((gill + eye + body) / 3.0, 1) | ||||||
| conf = round(random.uniform(0.82, 0.97), 2) | ||||||
|
|
||||||
| fname = (body_image.filename or "").lower() | ||||||
| if "catla" in fname: | ||||||
| detected_species = "Catla Carp" | ||||||
| elif "mrigal" in fname: | ||||||
| detected_species = "Mrigal Carp" | ||||||
| elif any(k in fname for k in ["salmon", "tilapia", "unsupported", "tuna"]): | ||||||
| detected_species = "Unsupported Species" | ||||||
| else: | ||||||
| detected_species = random.choice(["Rohu Carp", "Catla Carp", "Mrigal Carp"]) | ||||||
|
|
||||||
| alerts = [] | ||||||
| if "dyed" in fname or "color" in fname or (gill >= 90 and body <= 55): | ||||||
| alerts.append("Potential Artificial Coloring (Gills Dyed)") | ||||||
| if "duplicate" in fname or "copy" in fname: | ||||||
| alerts.append("Duplicate Scan Attempt (Trust Manipulation)") | ||||||
|
|
||||||
| demo_fusion = { | ||||||
| "final_score_percent": score, | ||||||
| "final_grade": "A" if score >= 75 else "B" if score >= 60 else "C", | ||||||
|
|
@@ -462,6 +579,9 @@ async def process_scan( | |||||
| }, | ||||||
| } | ||||||
| payload = _build_scan_payload(demo_fusion, scan_id, display_id) | ||||||
| payload["species"] = _build_species_info(detected_species) | ||||||
| if alerts: | ||||||
| payload["recommendations"]["alert_flags"] = alerts | ||||||
|
|
||||||
| try: | ||||||
| _db().table("scans").insert( | ||||||
|
|
@@ -474,7 +594,7 @@ async def process_scan( | |||||
| "image_type": "full_scan", | ||||||
| "freshness_index": payload["freshness_index"], | ||||||
| "scan_display_id": display_id, | ||||||
| "species_detected": "Rohu Carp", | ||||||
| "species_detected": detected_species, | ||||||
| "biomarker_json": payload["biomarkers"], | ||||||
| "storage_hours": payload["recommendations"]["consume_within_hours"], | ||||||
| "alert_flags": payload["recommendations"]["alert_flags"], | ||||||
|
|
@@ -528,12 +648,59 @@ async def process_scan( | |||||
| async def scan_auto( | ||||||
| request: Request, | ||||||
| image: UploadFile = File(...), | ||||||
| freshness_label: Optional[str] = Form(None), | ||||||
| fused_score: Optional[float] = Form(None), | ||||||
| source: Optional[str] = Form(None), | ||||||
| confidence_score: Optional[float] = Form(None), | ||||||
| species_detected: Optional[str] = Form(None), | ||||||
| current_user=Depends(get_current_user), | ||||||
| ): | ||||||
| image_bytes = await image.read() | ||||||
| scan_id = str(uuid.uuid4()) | ||||||
| display_id = _generate_display_id() | ||||||
|
|
||||||
| # If edge_onnx path is used, save directly and bypass server inference | ||||||
| if source == "edge_onnx" and fused_score is not None: | ||||||
| freshness = int(fused_score * 100) | ||||||
| conf = confidence_score or 0.85 | ||||||
| edge_fusion = { | ||||||
| "final_score_percent": freshness, | ||||||
| "final_grade": _to_db_grade(freshness_label or "C"), | ||||||
| "confidence_score": conf, | ||||||
| "uncertain_prediction_flag": conf < 0.70, | ||||||
| "regional_breakdown": { | ||||||
| "gill_freshness_score": fused_score, | ||||||
| "eye_freshness_score": fused_score, | ||||||
| "body_freshness_score": fused_score, | ||||||
| }, | ||||||
| } | ||||||
| photo_url = await _upload_image(image_bytes, str(current_user.id), scan_id) | ||||||
| payload = _build_scan_payload(edge_fusion, scan_id, display_id, photo_url) | ||||||
| if species_detected: | ||||||
| payload["species"]["common_name"] = species_detected | ||||||
|
|
||||||
| try: | ||||||
| _db().table("scans").insert( | ||||||
| { | ||||||
| "id": scan_id, | ||||||
| "user_id": str(current_user.id), | ||||||
| "final_grade": _to_db_grade(payload["grade"]), | ||||||
| "confidence_score": conf, | ||||||
| "image_type": "BODY", | ||||||
| "freshness_index": payload["freshness_index"], | ||||||
| "scan_display_id": display_id, | ||||||
| "species_detected": species_detected or "Rohu Carp", | ||||||
| "biomarker_json": payload["biomarkers"], | ||||||
| "storage_hours": payload["recommendations"]["consume_within_hours"], | ||||||
| "alert_flags": payload["recommendations"]["alert_flags"], | ||||||
| "photo_urls": [photo_url] if photo_url else [], | ||||||
| } | ||||||
| ).execute() | ||||||
| except Exception as exc: | ||||||
| print(f"DB write failed (edge_onnx): {exc}") | ||||||
|
|
||||||
| return {"success": True, "scan": payload} | ||||||
|
Comment on lines
+663
to
+702
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
rg -nP -C3 'def _to_db_grade' backend/main.pyRepository: jpdevhub/FreshScanAi Length of output: 388 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Inspect the relevant backend helpers and edge_onnx path.
sed -n '224,310p' backend/main.py
printf '\n----\n'
sed -n '620,710p' backend/main.py
printf '\n----\n'
rg -n -C3 '_build_scan_payload|freshness_label|fused_score|edge_onnx' backend/main.py src/lib/api.ts
printf '\n----\n'
sed -n '1,220p' src/lib/api.tsRepository: jpdevhub/FreshScanAi Length of output: 18343 🏁 Script executed: #!/bin/bash
set -euo pipefail
# If the first read is too large, inspect only the submitScan function and any grade mappings.
rg -n -C4 'submitScan|freshness_label|grade' src/lib/api.ts
printf '\n----\n'
rg -n -C4 'def _build_scan_payload|payload\["grade"\]|final_grade|freshness_index' backend/main.pyRepository: jpdevhub/FreshScanAi Length of output: 9494 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Inspect the client payload shape and the payload builder semantics.
rg -n -C4 'submitScan|freshness_label|freshnessLabel|grade|final_grade' src/lib/api.ts src -g '!**/node_modules/**'
printf '\n----\n'
python3 - <<'PY'
from pathlib import Path
p = Path('backend/main.py')
text = p.read_text()
for needle in ['def _build_scan_payload', 'payload["grade"]', 'final_grade', 'freshness_index', 'def _to_db_grade']:
idx = text.find(needle)
print(f'NEEDLE: {needle} -> {idx}')
PYRepository: jpdevhub/FreshScanAi Length of output: 31070 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Inspect the backend source of freshness_label and the client submitScan payload.
rg -n -C4 'freshness_label|freshnessLabel|submitScan|final_grade|_build_scan_payload|_to_db_grade' backend/main.py src/lib/api.ts
printf '\n----\n'
sed -n '1,260p' src/lib/api.ts
printf '\n----\n'
sed -n '600,710p' backend/main.pyRepository: jpdevhub/FreshScanAi Length of output: 24457 Map the edge ONNX label to the stored grade enum
🤖 Prompt for AI Agents |
||||||
|
|
||||||
| # ── Demo mode: models not loaded (PyTorch not installed) ───────────────── | ||||||
| if not _models_loaded: | ||||||
| gill = random.randint(68, 96) | ||||||
|
|
@@ -542,6 +709,22 @@ async def scan_auto( | |||||
| score = round((gill + eye + body) / 3.0, 1) | ||||||
| conf = round(random.uniform(0.82, 0.97), 2) | ||||||
|
|
||||||
| fname = (image.filename or "").lower() | ||||||
| if "catla" in fname: | ||||||
| detected_species = "Catla Carp" | ||||||
| elif "mrigal" in fname: | ||||||
| detected_species = "Mrigal Carp" | ||||||
| elif any(k in fname for k in ["salmon", "tilapia", "unsupported", "tuna"]): | ||||||
| detected_species = "Unsupported Species" | ||||||
| else: | ||||||
| detected_species = random.choice(["Rohu Carp", "Catla Carp", "Mrigal Carp"]) | ||||||
|
|
||||||
| alerts = [] | ||||||
| if "dyed" in fname or "color" in fname or (gill >= 90 and body <= 55): | ||||||
| alerts.append("Potential Artificial Coloring (Gills Dyed)") | ||||||
| if "duplicate" in fname or "copy" in fname: | ||||||
| alerts.append("Duplicate Scan Attempt (Trust Manipulation)") | ||||||
|
|
||||||
| demo_fusion = { | ||||||
| "final_score_percent": score, | ||||||
| "confidence_score": conf, | ||||||
|
|
@@ -554,6 +737,9 @@ async def scan_auto( | |||||
| } | ||||||
| photo_url = await _upload_image(image_bytes, str(current_user.id), scan_id) | ||||||
| payload = _build_scan_payload(demo_fusion, scan_id, display_id, photo_url) | ||||||
| payload["species"] = _build_species_info(detected_species) | ||||||
| if alerts: | ||||||
| payload["recommendations"]["alert_flags"] = alerts | ||||||
|
|
||||||
| try: | ||||||
| _db().table("scans").insert( | ||||||
|
|
@@ -565,7 +751,7 @@ async def scan_auto( | |||||
| "image_type": "BODY", | ||||||
| "freshness_index": payload["freshness_index"], | ||||||
| "scan_display_id": display_id, | ||||||
| "species_detected": "Rohu Carp", | ||||||
| "species_detected": detected_species, | ||||||
| "biomarker_json": payload["biomarkers"], | ||||||
| "storage_hours": payload["recommendations"]["consume_within_hours"], | ||||||
| "alert_flags": payload["recommendations"]["alert_flags"], | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,13 @@ | ||
| from fastapi import APIRouter, HTTPException, Depends, Query | ||
| from fastapi import APIRouter, HTTPException, Depends, Query, Request | ||
| from datetime import datetime, timedelta, timezone | ||
| from auth import get_current_user | ||
| from fastapi_cache import FastAPICache | ||
|
|
||
| router = APIRouter(prefix="/api/v1/vendors", tags=["vendors"]) | ||
|
|
||
| # In-memory reviews database fallback | ||
| _REVIEWS_DB = {} | ||
|
Comment on lines
+8
to
+9
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift In-memory State stored in a module-level dict is lost on every restart/redeploy and is not shared across multiple Uvicorn/Gunicorn workers, so reviews will appear and disappear depending on which process serves the request. If this is a temporary stub, please add a 🤖 Prompt for AI Agents |
||
|
|
||
|
|
||
| def _compute_badge(avg_score: float, total_scans: int) -> str: | ||
| if total_scans < 5: | ||
|
|
@@ -96,6 +99,75 @@ async def get_vendor_trust_score(vendor_id: str): | |
| except Exception as exc: | ||
| raise HTTPException(status_code=500, detail=str(exc)) | ||
|
|
||
| @router.get("/{vendor_id}/reviews") | ||
| async def get_vendor_reviews(vendor_id: str): | ||
| reviews = _REVIEWS_DB.get(vendor_id, [ | ||
| { | ||
| "id": "rev-1", | ||
| "author": "Ankit R.", | ||
| "rating": 5, | ||
| "comment": "Consistently fresh rohu fish. Highly recommended!", | ||
| "timestamp": (datetime.now(timezone.utc) - timedelta(days=2)).isoformat() | ||
| }, | ||
| { | ||
| "id": "rev-2", | ||
| "author": "Deepika S.", | ||
| "rating": 4, | ||
| "comment": "Good quality scales, operculum is bright red. Fair pricing.", | ||
| "timestamp": (datetime.now(timezone.utc) - timedelta(days=5)).isoformat() | ||
| } | ||
| ]) | ||
| return {"success": True, "reviews": reviews} | ||
|
|
||
| @router.post("/{vendor_id}/reviews") | ||
| async def add_vendor_review( | ||
| vendor_id: str, | ||
| review_data: dict, | ||
| request: Request | ||
| ): | ||
|
Comment on lines
+122
to
+127
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# Inspect the target file and locate related auth patterns
git ls-files backend/vendors.py
wc -l backend/vendors.py
sed -n '1,220p' backend/vendors.py
printf '\n--- search get_current_user in backend ---\n'
rg -n "get_current_user|Depends\(" backend -g '!**/__pycache__/**'
printf '\n--- search review-related routes ---\n'
rg -n "reviews|recalculate|vendor_id" backend -g '!**/__pycache__/**'Repository: jpdevhub/FreshScanAi Length of output: 11049 🏁 Script executed: #!/bin/bash
set -euo pipefail
wc -l backend/auth.py
sed -n '1,140p' backend/auth.pyRepository: jpdevhub/FreshScanAi Length of output: 3038 Require authentication on review posts This route is public today, and the manual 🤖 Prompt for AI Agents |
||
| author = "Anonymous Consumer" | ||
| try: | ||
| auth_header = request.headers.get("Authorization") | ||
| if auth_header: | ||
| # We can call get_current_user dynamically | ||
| user = await get_current_user(request) | ||
| if user: | ||
| author = user.user_metadata.get("full_name") or user.email | ||
| except Exception: | ||
| pass | ||
|
Comment on lines
+129
to
+137
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# Locate the relevant file and symbol definitions.
git ls-files 'backend/vendors.py' 'backend/*' | sed -n '1,120p'
printf '\n--- outline backend/vendors.py ---\n'
ast-grep outline backend/vendors.py --view expanded || true
printf '\n--- search get_current_user ---\n'
rg -n "async def get_current_user|get_current_user\(" backend -S
printf '\n--- read relevant sections ---\n'
sed -n '1,220p' backend/vendors.pyRepository: jpdevhub/FreshScanAi Length of output: 9404 🏁 Script executed: #!/bin/bash
set -euo pipefail
sed -n '1,140p' backend/auth.py
printf '\n--- usage of get_current_user ---\n'
rg -n "get_current_user\(" backend -SRepository: jpdevhub/FreshScanAi Length of output: 3213
🤖 Prompt for AI Agents |
||
|
|
||
| rating = review_data.get("rating", 5) | ||
| comment = review_data.get("comment", "") | ||
|
|
||
| new_review = { | ||
| "id": f"rev-{datetime.now(timezone.utc).timestamp()}", | ||
| "author": author, | ||
| "rating": int(rating), | ||
|
Comment on lines
+139
to
+145
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Unvalidated
🛡️ Sketchfrom pydantic import BaseModel, Field
class ReviewIn(BaseModel):
rating: int = Field(5, ge=1, le=5)
comment: str = ""Then take 🤖 Prompt for AI Agents |
||
| "comment": comment, | ||
| "timestamp": datetime.now(timezone.utc).isoformat() | ||
| } | ||
|
|
||
| if vendor_id not in _REVIEWS_DB: | ||
| _REVIEWS_DB[vendor_id] = [ | ||
| { | ||
| "id": "rev-1", | ||
| "author": "Ankit R.", | ||
| "rating": 5, | ||
| "comment": "Consistently fresh rohu fish. Highly recommended!", | ||
| "timestamp": (datetime.now(timezone.utc) - timedelta(days=2)).isoformat() | ||
| }, | ||
| { | ||
| "id": "rev-2", | ||
| "author": "Deepika S.", | ||
| "rating": 4, | ||
| "comment": "Good quality scales, operculum is bright red. Fair pricing.", | ||
| "timestamp": (datetime.now(timezone.utc) - timedelta(days=5)).isoformat() | ||
| } | ||
| ] | ||
|
Comment on lines
+104
to
+166
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win Duplicate default-review block. The identical seed list is hardcoded in both the GET fallback (Lines 104–119) and the POST seeding (Lines 151–166). Extract a 🤖 Prompt for AI Agents |
||
|
|
||
| _REVIEWS_DB[vendor_id].insert(0, new_review) | ||
| return {"success": True, "review": new_review} | ||
|
|
||
| @router.post("/{vendor_id}/recalculate") | ||
| async def recalculate_trust_score( | ||
| vendor_id: str, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: jpdevhub/FreshScanAi
Length of output: 19033
🏁 Script executed:
Repository: jpdevhub/FreshScanAi
Length of output: 6671
🏁 Script executed:
Repository: jpdevhub/FreshScanAi
Length of output: 3679
Use real quality signals or fixed weights here.
backend/main.py:257-307and the matching_row_to_payloadblock buildensemble.weightsfromrandom.uniform(...), so the dashboard shows per-stream weights that have no relationship to the scan or the documented 50/25/25 weighting.🧰 Tools
🪛 ast-grep (0.44.0)
[info] 257-257: use secrets package over random package
Context: random.uniform(0.80, 0.96)
Note: [CWE-330] Use of Insufficiently Random Values.
(avoid-random-python)
[info] 258-258: use secrets package over random package
Context: random.uniform(0.90, 0.99)
Note: [CWE-330] Use of Insufficiently Random Values.
(avoid-random-python)
🤖 Prompt for AI Agents