Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -2,13 +2,25 @@ import requests
|
|
| 2 |
import gradio as gr
|
| 3 |
import pandas as pd
|
| 4 |
import time
|
|
|
|
| 5 |
|
| 6 |
API_URL = "https://yata.yt/api/v1/travel/export/"
|
| 7 |
|
| 8 |
# Simple cache
|
| 9 |
_cache = {"data": None, "timestamp": 0, "last_update": "Unknown"}
|
| 10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
def fetch_yata(force_refresh=False):
|
|
|
|
| 12 |
if not force_refresh and _cache["data"] and (time.time() - _cache["timestamp"] < 300):
|
| 13 |
return _cache["data"], _cache["last_update"]
|
| 14 |
|
|
@@ -24,35 +36,25 @@ def fetch_yata(force_refresh=False):
|
|
| 24 |
try:
|
| 25 |
response = requests.get(API_URL, headers=headers, timeout=10)
|
| 26 |
response.raise_for_status()
|
| 27 |
-
|
| 28 |
-
# Debug logging: check what we actually got
|
| 29 |
-
content_type = response.headers.get("Content-Type", "")
|
| 30 |
-
print(f"ℹ️ Response Content-Type: {content_type}")
|
| 31 |
-
print(f"ℹ️ First 200 chars of response:\n{response.text[:200]!r}")
|
| 32 |
-
|
| 33 |
data = response.json()
|
| 34 |
|
| 35 |
-
if "stocks" not in data:
|
| 36 |
-
print("⚠️ 'stocks' key not found — response may not be valid YATA JSON")
|
| 37 |
-
|
| 38 |
_cache["data"] = data
|
| 39 |
_cache["timestamp"] = time.time()
|
| 40 |
-
_cache["last_update"] =
|
| 41 |
|
| 42 |
-
print(f"✅ Successfully
|
| 43 |
return data, _cache["last_update"]
|
| 44 |
|
| 45 |
except Exception as e:
|
| 46 |
print(f"❌ Error fetching YATA data: {e}")
|
| 47 |
-
return {"stocks": {}}, "Fetch failed (likely blocked
|
| 48 |
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
data,
|
| 52 |
stocks = data.get("stocks", {})
|
| 53 |
rows = []
|
| 54 |
|
| 55 |
-
# Mapping of country codes to readable names (you can expand this)
|
| 56 |
COUNTRY_NAMES = {
|
| 57 |
"arg": "Argentina",
|
| 58 |
"mex": "Mexico",
|
|
@@ -63,13 +65,11 @@ def query_inventory(item_term="", country_name="", refresh=False):
|
|
| 63 |
"swi": "Switzerland",
|
| 64 |
"uae": "United Arab Emirates",
|
| 65 |
"chi": "China",
|
| 66 |
-
"haw": "Hawaii"
|
| 67 |
}
|
| 68 |
|
| 69 |
for country_code, cdata in stocks.items():
|
| 70 |
cname = COUNTRY_NAMES.get(country_code, country_code.upper())
|
| 71 |
-
|
| 72 |
-
# Handle per-country 'update' timestamp
|
| 73 |
update_ts = cdata.get("update")
|
| 74 |
update_str = (
|
| 75 |
time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(update_ts))
|
|
@@ -78,48 +78,59 @@ def query_inventory(item_term="", country_name="", refresh=False):
|
|
| 78 |
|
| 79 |
for item in cdata.get("stocks", []):
|
| 80 |
iname = item.get("name", "")
|
| 81 |
-
|
|
|
|
|
|
|
| 82 |
match_country = country_name.lower() in cname.lower() if country_name else True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 83 |
if match_item and match_country:
|
| 84 |
rows.append({
|
| 85 |
"Country": cname,
|
| 86 |
"Item": iname,
|
|
|
|
| 87 |
"Quantity": item.get("quantity", 0),
|
| 88 |
"Cost": item.get("cost", 0),
|
| 89 |
"Updated": update_str
|
| 90 |
})
|
| 91 |
|
| 92 |
if not rows:
|
| 93 |
-
return pd.DataFrame([{"Result": "No inventory found for that query."}]),
|
| 94 |
|
| 95 |
df = pd.DataFrame(rows)
|
| 96 |
df = df.sort_values(by=["Country", "Item"])
|
| 97 |
total_quantity = df["Quantity"].sum()
|
| 98 |
-
df.loc[len(df)] = {"Country": "—", "Item": "TOTAL", "Quantity": total_quantity, "Cost": "", "Updated": ""}
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
return df, last_update_display
|
| 102 |
|
|
|
|
| 103 |
|
| 104 |
-
def run_query(item, country, refresh):
|
| 105 |
-
df, timestamp = query_inventory(item, country, refresh)
|
| 106 |
return df, timestamp
|
| 107 |
|
| 108 |
iface = gr.Interface(
|
| 109 |
fn=run_query,
|
| 110 |
inputs=[
|
| 111 |
-
gr.Textbox(label="Item name (e.g.
|
| 112 |
-
gr.
|
|
|
|
| 113 |
gr.Checkbox(label="Force refresh (ignore cache)", value=False)
|
| 114 |
],
|
| 115 |
outputs=[
|
| 116 |
gr.Dataframe(label="Results"),
|
| 117 |
gr.Textbox(label="Metadata / Last Update")
|
| 118 |
],
|
| 119 |
-
title="🧳 Torn Inventory Viewer (YATA
|
| 120 |
description=(
|
| 121 |
-
"Fetches live
|
| 122 |
-
"
|
| 123 |
),
|
| 124 |
)
|
| 125 |
|
|
|
|
| 2 |
import gradio as gr
|
| 3 |
import pandas as pd
|
| 4 |
import time
|
| 5 |
+
import json
|
| 6 |
|
| 7 |
API_URL = "https://yata.yt/api/v1/travel/export/"
|
| 8 |
|
| 9 |
# Simple cache
|
| 10 |
_cache = {"data": None, "timestamp": 0, "last_update": "Unknown"}
|
| 11 |
|
| 12 |
+
# Load item category data from your uploaded file
|
| 13 |
+
with open("items.json", "r", encoding="utf-8") as f:
|
| 14 |
+
items_data = json.load(f)["items"]
|
| 15 |
+
|
| 16 |
+
# Build lookup tables
|
| 17 |
+
ITEM_TO_TYPE = {v["name"]: v["type"].lower() for v in items_data.values() if "name" in v and "type" in v}
|
| 18 |
+
|
| 19 |
+
# All available categories
|
| 20 |
+
ALL_CATEGORIES = sorted(set(ITEM_TO_TYPE.values()))
|
| 21 |
+
|
| 22 |
def fetch_yata(force_refresh=False):
|
| 23 |
+
"""Fetch and cache YATA travel data"""
|
| 24 |
if not force_refresh and _cache["data"] and (time.time() - _cache["timestamp"] < 300):
|
| 25 |
return _cache["data"], _cache["last_update"]
|
| 26 |
|
|
|
|
| 36 |
try:
|
| 37 |
response = requests.get(API_URL, headers=headers, timeout=10)
|
| 38 |
response.raise_for_status()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
data = response.json()
|
| 40 |
|
|
|
|
|
|
|
|
|
|
| 41 |
_cache["data"] = data
|
| 42 |
_cache["timestamp"] = time.time()
|
| 43 |
+
_cache["last_update"] = "Updated at " + time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime())
|
| 44 |
|
| 45 |
+
print(f"✅ Successfully fetched YATA data at {_cache['last_update']}")
|
| 46 |
return data, _cache["last_update"]
|
| 47 |
|
| 48 |
except Exception as e:
|
| 49 |
print(f"❌ Error fetching YATA data: {e}")
|
| 50 |
+
return {"stocks": {}}, "Fetch failed (likely blocked by YATA)"
|
| 51 |
|
| 52 |
+
def query_inventory(item_term="", category="", country_name="", refresh=False):
|
| 53 |
+
"""Filter and display inventory data"""
|
| 54 |
+
data, last_update = fetch_yata(force_refresh=refresh)
|
| 55 |
stocks = data.get("stocks", {})
|
| 56 |
rows = []
|
| 57 |
|
|
|
|
| 58 |
COUNTRY_NAMES = {
|
| 59 |
"arg": "Argentina",
|
| 60 |
"mex": "Mexico",
|
|
|
|
| 65 |
"swi": "Switzerland",
|
| 66 |
"uae": "United Arab Emirates",
|
| 67 |
"chi": "China",
|
| 68 |
+
"haw": "Hawaii",
|
| 69 |
}
|
| 70 |
|
| 71 |
for country_code, cdata in stocks.items():
|
| 72 |
cname = COUNTRY_NAMES.get(country_code, country_code.upper())
|
|
|
|
|
|
|
| 73 |
update_ts = cdata.get("update")
|
| 74 |
update_str = (
|
| 75 |
time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(update_ts))
|
|
|
|
| 78 |
|
| 79 |
for item in cdata.get("stocks", []):
|
| 80 |
iname = item.get("name", "")
|
| 81 |
+
itype = ITEM_TO_TYPE.get(iname, "").lower()
|
| 82 |
+
|
| 83 |
+
# Match item/category filters
|
| 84 |
match_country = country_name.lower() in cname.lower() if country_name else True
|
| 85 |
+
|
| 86 |
+
if item_term:
|
| 87 |
+
match_item = item_term.lower() in iname.lower()
|
| 88 |
+
elif category:
|
| 89 |
+
match_item = itype == category.lower()
|
| 90 |
+
else:
|
| 91 |
+
match_item = True
|
| 92 |
+
|
| 93 |
if match_item and match_country:
|
| 94 |
rows.append({
|
| 95 |
"Country": cname,
|
| 96 |
"Item": iname,
|
| 97 |
+
"Category": itype.title() if itype else "",
|
| 98 |
"Quantity": item.get("quantity", 0),
|
| 99 |
"Cost": item.get("cost", 0),
|
| 100 |
"Updated": update_str
|
| 101 |
})
|
| 102 |
|
| 103 |
if not rows:
|
| 104 |
+
return pd.DataFrame([{"Result": "No inventory found for that query."}]), last_update
|
| 105 |
|
| 106 |
df = pd.DataFrame(rows)
|
| 107 |
df = df.sort_values(by=["Country", "Item"])
|
| 108 |
total_quantity = df["Quantity"].sum()
|
| 109 |
+
df.loc[len(df)] = {"Country": "—", "Item": "TOTAL", "Category": "", "Quantity": total_quantity, "Cost": "", "Updated": ""}
|
| 110 |
+
df = df[["Country", "Item", "Category", "Quantity", "Cost", "Updated"]]
|
|
|
|
|
|
|
| 111 |
|
| 112 |
+
return df, f"Last update: {last_update}"
|
| 113 |
|
| 114 |
+
def run_query(item, category, country, refresh):
|
| 115 |
+
df, timestamp = query_inventory(item, category, country, refresh)
|
| 116 |
return df, timestamp
|
| 117 |
|
| 118 |
iface = gr.Interface(
|
| 119 |
fn=run_query,
|
| 120 |
inputs=[
|
| 121 |
+
gr.Textbox(label="Item name (e.g. Plushie, Zip Ties, Vodka)", placeholder="Leave blank if using category"),
|
| 122 |
+
gr.Dropdown(label="Category (from items.json)", choices=[""] + ALL_CATEGORIES, value=""),
|
| 123 |
+
gr.Textbox(label="Country (e.g. UK, Argentina, Japan)", placeholder="Optional"),
|
| 124 |
gr.Checkbox(label="Force refresh (ignore cache)", value=False)
|
| 125 |
],
|
| 126 |
outputs=[
|
| 127 |
gr.Dataframe(label="Results"),
|
| 128 |
gr.Textbox(label="Metadata / Last Update")
|
| 129 |
],
|
| 130 |
+
title="🧳 Torn Inventory Viewer (YATA + Item Categories)",
|
| 131 |
description=(
|
| 132 |
+
"Fetches live YATA travel stock data and links it to Torn item categories from `items.json`.\n"
|
| 133 |
+
"You can search by item name or select a category (e.g. 'flower', 'plushie', 'alcohol')."
|
| 134 |
),
|
| 135 |
)
|
| 136 |
|