File size: 4,939 Bytes
f4dcb85
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
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()