BuyingAgent/backend/scripts/demo.py
Lars b276758ee1
All checks were successful
Deploy Development / deploy (push) Successful in 1m19s
Test Suite / pytest-backend (push) Successful in 31s
Test Suite / smoke-dev (push) Successful in 0s
Test Suite / frontend-checks (push) Successful in 28s
Stelle den Frontend-MVP und die v0.3-API auf develop bereit, damit Dev API und PWA zusammen deployen.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-04 13:04:59 +02:00

139 lines
5.5 KiB
Python

from __future__ import annotations
import json
import urllib.error
import urllib.request
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
PROFILE = json.loads((ROOT / "profiles" / "mobile-development-notebook.json").read_text(encoding="utf-8"))
FIXTURE = json.loads((ROOT / "fixtures" / "manual-demo.json").read_text(encoding="utf-8"))
BASE = "http://127.0.0.1:8000"
AS_OF = "2026-10-03T12:00:00Z"
DEFINITIONS = [
{"key": "ram_gb", "value_type": "number", "canonical_unit": "GB", "minimum": 0, "description": "RAM in GB"},
{"key": "storage_gb", "value_type": "number", "canonical_unit": "GB", "minimum": 0, "description": "Storage in GB"},
{"key": "weight_kg", "value_type": "number", "canonical_unit": "kg", "minimum": 0, "description": "Weight in kg"},
{"key": "battery_score", "value_type": "number", "minimum": 0, "maximum": 100, "description": "Manual battery score"},
{"key": "display_score", "value_type": "number", "minimum": 0, "maximum": 100, "description": "Manual display score"},
{"key": "cpu_score", "value_type": "number", "minimum": 0, "maximum": 100, "description": "Manual CPU score"},
{"key": "ports", "value_type": "string_list", "description": "Ports"},
]
def request(method: str, path: str, body=None, expected=(200, 201, 409)):
data = None if body is None else json.dumps(body, default=str).encode()
req = urllib.request.Request(
f"{BASE}{path}",
data=data,
method=method,
headers={"Content-Type": "application/json"} if body is not None else {},
)
try:
with urllib.request.urlopen(req) as response:
payload = json.loads(response.read().decode())
if response.status not in expected:
raise SystemExit(f"{method} {path} -> {response.status}: {payload}")
return response.status, payload
except urllib.error.HTTPError as exc:
payload = json.loads(exc.read().decode())
if exc.code not in expected:
raise SystemExit(f"{method} {path} -> {exc.code}: {payload}") from exc
return exc.code, payload
def main() -> None:
for definition in DEFINITIONS:
request("POST", "/api/v1/attribute-definitions", definition)
request("POST", "/api/v1/profiles", PROFILE)
product = FIXTURE["products"][0]
request(
"POST",
"/api/v1/products",
{
"id": product["id"],
"category": product["category"],
"brand": product["brand"],
"name": product["name"],
"model": product.get("model"),
},
)
for variant in product["variants"]:
request(
"POST",
f"/api/v1/products/{product['id']}/variants",
{
"id": variant["id"],
"name": variant["name"],
"manufacturer_sku": variant.get("manufacturer_sku"),
"identifiers": variant.get("identifiers") or {},
},
)
for attribute in variant["attributes"]:
request("POST", f"/api/v1/variants/{variant['id']}/attributes", {**attribute, "source_id": "manual"})
for offer in FIXTURE["offers"]:
request(
"POST",
f"/api/v1/variants/{offer['variant_id']}/offers",
{
"id": offer["id"],
"source_id": "manual",
"external_id": offer["external_id"],
"seller": offer["seller"],
"url": offer.get("url"),
"market": offer["market"],
"currency": offer["currency"],
"condition": offer["condition"],
},
)
for price in FIXTURE["prices"]:
offer = next(item for item in FIXTURE["offers"] if item["external_id"] == price["external_offer_id"])
request(
"POST",
f"/api/v1/offers/{offer['id']}/prices",
{
"id": price["id"],
"source_id": "manual",
"external_observation_id": price["external_observation_id"],
"observed_at": price["observed_at"],
"item_price": price["item_price"],
"shipping_price": price["shipping_price"],
"currency": price["currency"],
"availability": price["availability"],
"raw_payload": price["raw_payload"],
"confidence": price["confidence"],
},
expected=(200, 201),
)
cases = {
"A": ("22222222-2222-4222-8222-222222222222", "33333333-3333-4333-8333-333333333333"),
"B": ("22222222-2222-4222-8222-22222222222b", "33333333-3333-4333-8333-33333333333b"),
"C": ("22222222-2222-4222-8222-22222222222c", "33333333-3333-4333-8333-33333333333c"),
"D": ("22222222-2222-4222-8222-222222222222", "33333333-3333-4333-8333-33333333333d"),
}
for label, (variant_id, offer_id) in cases.items():
status, result = request(
"POST",
f"/api/v1/evaluate/{variant_id}",
{
"profile_id": "mobile-development-notebook",
"profile_version": 1,
"offer_id": offer_id,
"as_of": AS_OF,
},
expected=(201,),
)
print(
f"case {label}: {status} overall={result['overall_eligibility']} "
f"product={result['product_score']} price={result['price_score']} "
f"deal={result['deal_score']} class={result['classification']}"
)
if __name__ == "__main__":
main()