Skip to content

Commit b3c86d6

Browse files
committed
feat: add describe() to standalone parse_tigertag.py — natural-language LLM-ready output
1 parent 212cac2 commit b3c86d6

1 file changed

Lines changed: 117 additions & 0 deletions

File tree

parse_tigertag.py

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1505,6 +1505,123 @@ def verify(self, db: TigerTagDB = None) -> SignatureResult:
15051505

15061506
# ── Output ────────────────────────────────────────────────────────────────
15071507

1508+
def describe(self, db: TigerTagDB = None) -> str:
1509+
"""
1510+
Return a concise natural-language description of the tag.
1511+
1512+
Designed for injection into LLM prompts. Contains all material data
1513+
in plain English, without protocol jargon.
1514+
1515+
Args:
1516+
db : Optional pre-loaded TigerTagDB. Uses self.db by default.
1517+
1518+
Returns:
1519+
A single paragraph (no newlines) describing the tag content.
1520+
1521+
Example:
1522+
prompt = f"Given this material: {tag.describe()}\\nWhat nozzle temp should I use?"
1523+
"""
1524+
_db = db or self.db
1525+
mat = _db.material(self.id_material) or {}
1526+
rec = mat.get("recommended", {})
1527+
1528+
material = TigerTagDB.label(_db.material(self.id_material))
1529+
type_ = TigerTagDB.label(_db.type_(self.id_type))
1530+
diameter = TigerTagDB.label(_db.diameter(self.id_diameter))
1531+
brand = TigerTagDB.label(_db.brand(self.id_brand))
1532+
unit = TigerTagDB.label(_db.unit(self.id_unit))
1533+
density = mat.get("density")
1534+
stock = self.stock_percent
1535+
1536+
# Check aspect_2 first for multi-color mode (Bicolor/Tricolor/Rainbow),
1537+
# then fall back to aspect_1. color_count drives how many colors are active.
1538+
asp2_entry = _db.aspect(self.id_aspect_2)
1539+
asp1_entry = _db.aspect(self.id_aspect_1)
1540+
color_count = 1
1541+
if asp2_entry and asp2_entry.get("color_count", 1) > 1:
1542+
color_count = asp2_entry["color_count"]
1543+
elif asp1_entry and asp1_entry.get("color_count", 1) > 1:
1544+
color_count = asp1_entry["color_count"]
1545+
1546+
aspect1_label = TigerTagDB.label(asp1_entry)
1547+
aspect2_label = TigerTagDB.label(asp2_entry)
1548+
1549+
parts: List[str] = []
1550+
1551+
# Identity
1552+
parts.append(
1553+
f"TigerTag RFID chip read successfully."
1554+
f" Material: {material} {type_}"
1555+
+ (f" ({diameter}mm diameter)" if diameter not in ("Unknown", "-") else "")
1556+
+ (f", density {density} g/cm³" if density else "")
1557+
+ (f", by {brand}" if brand not in ("Unknown", "-") else "")
1558+
+ "."
1559+
)
1560+
1561+
# Aspect / finish
1562+
finish_parts = [l for l in (aspect1_label, aspect2_label) if l not in ("Unknown", "-", "None")]
1563+
if finish_parts:
1564+
parts.append(f"Finish: {' + '.join(finish_parts)}.")
1565+
1566+
# Color — respect color_count from aspect DB
1567+
color_parts = [f"primary {self.color1_hex}"]
1568+
if color_count >= 2:
1569+
color_parts.append(f"secondary {self.color2_hex}")
1570+
if color_count >= 3:
1571+
color_parts.append(f"tertiary {self.color3_hex}")
1572+
parts.append("Color: " + ", ".join(color_parts) + ".")
1573+
1574+
# Temperatures from chip
1575+
parts.append(
1576+
f"Print settings (on chip): nozzle {self.nozzle_temp_min}{self.nozzle_temp_max}°C,"
1577+
f" bed {self.bed_temp_min}{self.bed_temp_max}°C,"
1578+
f" drying {self.dry_temp}°C for {self.dry_time}h."
1579+
)
1580+
1581+
# DB-recommended temps (if available)
1582+
if rec.get("nozzleTempMin") is not None:
1583+
parts.append(
1584+
f"Database recommended settings: nozzle {rec['nozzleTempMin']}{rec['nozzleTempMax']}°C,"
1585+
f" bed {rec.get('bedTempMin', '?')}{rec.get('bedTempMax', '?')}°C,"
1586+
f" drying {rec.get('dryTemp', '?')}°C for {rec.get('dryTime', '?')}h."
1587+
)
1588+
1589+
# Quantity
1590+
if self.measure > 0:
1591+
parts.append(
1592+
f"Quantity: {self.measure_available} {unit} remaining"
1593+
f" out of {self.measure} {unit} initial"
1594+
+ (f" ({stock}%)." if stock is not None else ".")
1595+
)
1596+
1597+
# HueForge
1598+
if self.td_raw != 0:
1599+
parts.append(f"HueForge TD: {self.td_value:.1f}.")
1600+
1601+
# Traceability
1602+
parts.append(f"Manufactured: {self.manufacturing_date.strftime('%Y-%m-%d')}.")
1603+
if self.custom_message:
1604+
parts.append(f"Custom message on chip: \"{self.custom_message}\".")
1605+
if self.uid_hex:
1606+
parts.append(f"Chip UID: {self.uid_hex}.")
1607+
1608+
# TigerTag+ links
1609+
if self.product_page_url:
1610+
parts.append(
1611+
f"Product page: {self.product_page_url} — "
1612+
f"API JSON: {self.api_url}"
1613+
)
1614+
1615+
# Authentication
1616+
if self.is_signed:
1617+
parts.append(
1618+
"Tag carries an ECDSA-P256 signature — call tag.verify() to confirm authenticity."
1619+
)
1620+
else:
1621+
parts.append("Tag is not ECDSA-signed.")
1622+
1623+
return " ".join(parts)
1624+
15081625
def to_raw_dict(self) -> Dict[str, Any]:
15091626
"""
15101627
Return protocol fields exactly as stored on the chip — no label resolution,

0 commit comments

Comments
 (0)