Spaces:
Running
Running
| import json | |
| import gradio as gr | |
| from engine import walk, rationale | |
| import ai_layer as A | |
| INTRO = ("Describe your footwear product in your own words. " | |
| "Include the materials, the type, who it is for, and the approximate value per pair. " | |
| "I read your description, then ask only for what the schedule still needs.") | |
| def fmt_result(res, facts): | |
| lines = [] | |
| lines.append(f"Suggested HTS code {res['code']}") | |
| lines.append(f"General duty rate {res['general'] or 'see schedule'}") | |
| lines.append("") | |
| lines.append("Why this code") | |
| for i, step in enumerate(res["path"], 1): | |
| num = step["htsno"] or "grouping" | |
| lines.append(f" {i}. {num} {step['desc']}") | |
| lines.append("") | |
| lines.append("Basis. HTS Chapter 64, 2026 revision, walked per the chapter notes.") | |
| lines.append("Decision support only. The importer or a licensed broker makes the final decision.") | |
| lines.append("") | |
| lines.append("Describe another product to classify it.") | |
| return "\n".join(lines) | |
| def fmt_review(reason, at=None): | |
| lines = ["This case is routed to expert review."] | |
| lines.append(f"Reason. {reason}.") | |
| if at: | |
| lines.append(f"The unresolved condition. {at}") | |
| lines.append("A licensed broker should make this call. " | |
| "Describe another product to classify it.") | |
| return "\n".join(lines) | |
| def advance(client, state): | |
| """Walk with current facts. Returns the assistant message and whether done.""" | |
| r = walk(state["facts"]) | |
| if r["status"] == "code": | |
| msg = fmt_result(r, state["facts"]) | |
| return msg, True | |
| if r["status"] == "need_fact": | |
| try: | |
| q = A.ask_gap(client, r["fact"]) | |
| except Exception: | |
| q = f"Please tell me {A.FACT_KEYS[r['fact']]}." | |
| state["pending"] = ("fact", r["fact"]) | |
| return q, False | |
| if r["status"] == "review" and r.get("at"): | |
| try: | |
| q = A.ask_branch(client, r["at"]) | |
| except Exception: | |
| q = f"Does this condition apply to your product. {r['at']}" | |
| state["pending"] = ("branch", r["at"]) | |
| return q, False | |
| return fmt_review(r.get("reason", "unresolved")), True | |
| def respond(message, history, state): | |
| state = dict(state or {"facts": {}, "pending": None, "retried": False}) | |
| history = history + [{"role": "user", "content": message}] | |
| try: | |
| client = A.get_client() | |
| except Exception: | |
| history.append({"role": "assistant", | |
| "content": "The model is not configured. The Space owner must set the GROQ_API_KEY secret."}) | |
| return history, state, "" | |
| try: | |
| if state["pending"] is None: | |
| state["facts"] = A.extract_facts(client, message) | |
| state["facts"]["_desc"] = message | |
| msg, done = advance(client, state) | |
| else: | |
| kind, key = state["pending"] | |
| if kind == "fact": | |
| got = A.read_answer(client, key, message) | |
| if got: | |
| state["facts"].update(got) | |
| state["pending"], state["retried"] = None, False | |
| msg, done = advance(client, state) | |
| elif not state["retried"]: | |
| state["retried"] = True | |
| msg, done = "Please answer that directly so the classification stays accurate.", False | |
| else: | |
| msg, done = fmt_review(f"the fact could not be established, {A.FACT_KEYS[key]}"), True | |
| else: | |
| holds = A.read_branch_answer(client, key, message) | |
| if holds is None: | |
| msg, done = fmt_review("a schedule condition needs expert judgment", key), True | |
| else: | |
| state["facts"].setdefault("_overrides", {})[key] = holds | |
| state["pending"] = None | |
| msg, done = advance(client, state) | |
| if done: | |
| state = {"facts": {}, "pending": None, "retried": False} | |
| except Exception as e: | |
| msg = f"The model call failed. Reason {e}. Send your message again in a moment." | |
| history.append({"role": "assistant", "content": msg}) | |
| return history, state, "" | |
| with gr.Blocks(title="TariffWise") as demo: | |
| gr.Markdown("# TariffWise") | |
| gr.Markdown("AI tariff classification for footwear. A model reads your description and runs the interview. " | |
| "A deterministic engine walks the real 2026 HTS Chapter 64 and assigns the code. " | |
| "Every result carries its full derivation.") | |
| chatbot = gr.Chatbot(height=460, value=[{"role": "assistant", "content": INTRO}]) | |
| st = gr.State(None) | |
| box = gr.Textbox(placeholder="Describe your product, or answer the question", show_label=False) | |
| box.submit(respond, [box, chatbot, st], [chatbot, st, box]) | |
| gr.Markdown("Decision support only. Not legal advice.") | |
| if __name__ == "__main__": | |
| demo.launch() | |