abandekar-dev commited on
Commit
44ce0b7
·
verified ·
1 Parent(s): 6a8efd2

Upload 4 files

Browse files
Files changed (4) hide show
  1. README.md +13 -6
  2. app.py +178 -0
  3. corpus.csv +0 -0
  4. requirements.txt +4 -0
README.md CHANGED
@@ -1,13 +1,20 @@
1
  ---
2
- title: Onet Capability Classifier
3
- emoji: 🦀
4
  colorFrom: gray
5
- colorTo: blue
6
  sdk: gradio
7
- sdk_version: 6.19.0
8
- python_version: '3.13'
9
  app_file: app.py
10
  pinned: false
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: Task to AI Capability Classifier
3
+ emoji: 🔶
4
  colorFrom: gray
5
+ colorTo: gray
6
  sdk: gradio
7
+ sdk_version: 4.44.0
 
8
  app_file: app.py
9
  pinned: false
10
  ---
11
 
12
+ # Task AI Capability Classifier
13
+
14
+ A fine-tuned DistilBERT model that maps work tasks to a 9-category AI capability taxonomy
15
+ (INPUT, EXTRACT, CLASSIFY, MATCH, DETECT, GENERATE, ORCHESTRATE, PREDICT, CONVERSE).
16
+
17
+ Trained on 18,796 labeled O*NET task statements. The app classifies novel tasks, compares the
18
+ model's predictions against the authored labels, and lets you browse the full corpus.
19
+
20
+ Model: [abandekar-dev/onet-capability-classifier](https://huggingface.co/abandekar-dev/onet-capability-classifier)
app.py ADDED
@@ -0,0 +1,178 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ O*NET Task -> AI Capability Classifier
3
+ A fine-tuned DistilBERT model that maps work tasks to a 9-category AI capability taxonomy.
4
+
5
+ Three modes:
6
+ 1. Classify - type any task, get the model's predicted capability + confidence across all 9
7
+ 2. Authored vs Model - for tasks already in the corpus, compare the human-authored label to the model
8
+ 3. Browse - search/filter the full 18,796-task corpus
9
+ """
10
+
11
+ import gradio as gr
12
+ import pandas as pd
13
+ import torch
14
+ from transformers import AutoTokenizer, AutoModelForSequenceClassification
15
+ import torch.nn.functional as F
16
+
17
+ # ----------------------------------------------------------------------------
18
+ # Load model (from the Hub) and corpus (shipped with the Space)
19
+ # ----------------------------------------------------------------------------
20
+ MODEL_ID = "abandekar-dev/onet-capability-classifier"
21
+
22
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
23
+ model = AutoModelForSequenceClassification.from_pretrained(MODEL_ID)
24
+ model.eval()
25
+
26
+ id2label = model.config.id2label
27
+ LABELS = [id2label[i] for i in range(len(id2label))]
28
+
29
+ # Short gloss for each capability (shown under predictions for context)
30
+ GLOSS = {
31
+ "INPUT": "Enter/update data into systems",
32
+ "EXTRACT": "Pull structured data from unstructured sources",
33
+ "CLASSIFY": "Categorize inputs into predefined groups",
34
+ "MATCH": "Find correspondences across datasets",
35
+ "DETECT": "Identify anomalies/exceptions from expected patterns",
36
+ "GENERATE": "Create new content from context",
37
+ "ORCHESTRATE": "Chain multi-step workflows with conditional logic",
38
+ "PREDICT": "Forecast outcomes from historical patterns",
39
+ "CONVERSE": "Natural language interaction for resolution",
40
+ }
41
+
42
+ corpus = pd.read_csv("corpus.csv")
43
+ corpus["text_lower"] = corpus["text"].str.lower()
44
+ FUNCTIONS = ["All"] + sorted(corpus["function"].dropna().unique().tolist())
45
+
46
+ # ----------------------------------------------------------------------------
47
+ # Inference
48
+ # ----------------------------------------------------------------------------
49
+ def classify(text):
50
+ """Return dict of label -> probability for a single task description."""
51
+ if not text or not text.strip():
52
+ return {}
53
+ enc = tokenizer(text, truncation=True, max_length=128, return_tensors="pt")
54
+ with torch.no_grad():
55
+ logits = model(**enc).logits
56
+ probs = F.softmax(logits, dim=-1)[0].tolist()
57
+ return {LABELS[i]: probs[i] for i in range(len(LABELS))}
58
+
59
+
60
+ def predict_mode(text):
61
+ scores = classify(text)
62
+ if not scores:
63
+ return "Enter a task description above.", {}
64
+ top = max(scores, key=scores.get)
65
+ summary = f"### {top}\n**{GLOSS[top]}**\n\nConfidence: {scores[top]*100:.1f}%"
66
+ return summary, scores
67
+
68
+
69
+ def lookup_mode(text):
70
+ """Find an exact/near corpus match; compare authored label to model prediction."""
71
+ if not text or not text.strip():
72
+ return "Enter or select a task.", {}, ""
73
+ q = text.strip().lower()
74
+ hit = corpus[corpus["text_lower"] == q]
75
+ if hit.empty:
76
+ hit = corpus[corpus["text_lower"].str.contains(q[:60], regex=False, na=False)]
77
+
78
+ scores = classify(text)
79
+ top = max(scores, key=scores.get)
80
+
81
+ if hit.empty:
82
+ note = (
83
+ "**Not found in corpus** — this is a novel task, so only the model can answer.\n\n"
84
+ f"Model predicts: **{top}** ({scores[top]*100:.1f}%)"
85
+ )
86
+ return note, scores, ""
87
+
88
+ row = hit.iloc[0]
89
+ authored = row["label"]
90
+ agree = "match" if authored == top else "differ"
91
+ icon = "✓" if authored == top else "✗"
92
+ note = (
93
+ f"**Authored label:** {authored} \n"
94
+ f"**Model prediction:** {top} ({scores[top]*100:.1f}%) \n\n"
95
+ f"{icon} They **{agree}**."
96
+ )
97
+ meta = f"Occupation: {row['occupation']} · Function: {row['function']} · SOC: {row['soc']}"
98
+ return note, scores, meta
99
+
100
+
101
+ def browse(query, function, limit):
102
+ df = corpus
103
+ if function and function != "All":
104
+ df = df[df["function"] == function]
105
+ if query and query.strip():
106
+ q = query.strip().lower()
107
+ df = df[df["text_lower"].str.contains(q, regex=False, na=False)]
108
+ df = df.head(int(limit))
109
+ return df[["text", "label", "occupation", "function"]].rename(
110
+ columns={"text": "Task", "label": "Capability", "occupation": "Occupation", "function": "Function"}
111
+ )
112
+
113
+ # ----------------------------------------------------------------------------
114
+ # Theme — dark, Root accent (#C4782A), zero radius, mono labels
115
+ # ----------------------------------------------------------------------------
116
+ CSS = """
117
+ :root { --root:#C4782A; --root-light:#E8974A; --ink:#0E0F0C; --soil:#1C1D18;
118
+ --bark:#2A2B24; --ash:#A8AB9C; --parchment:#F0EDE4; }
119
+ .gradio-container { background:var(--ink) !important; color:var(--parchment) !important;
120
+ font-family:'Instrument Sans',system-ui,sans-serif !important; }
121
+ * { border-radius:0 !important; }
122
+ h1,h2,h3 { color:var(--parchment) !important; font-family:Georgia,'DM Serif Display',serif !important; }
123
+ .tab-nav button { font-family:'IBM Plex Mono',monospace !important; text-transform:uppercase;
124
+ letter-spacing:0.05em; font-size:12px !important; color:var(--ash) !important; }
125
+ .tab-nav button.selected { color:var(--root) !important; border-bottom:2px solid var(--root) !important; }
126
+ button.primary { background:var(--root) !important; color:var(--ink) !important;
127
+ font-family:'IBM Plex Mono',monospace !important; text-transform:uppercase;
128
+ letter-spacing:0.05em; border:none !important; }
129
+ button.primary:hover { background:var(--root-light) !important; }
130
+ label span, .label-wrap span { font-family:'IBM Plex Mono',monospace !important;
131
+ text-transform:uppercase; letter-spacing:0.04em; font-size:11px !important; color:var(--ash) !important; }
132
+ input,textarea,.dropdown { background:var(--soil) !important; color:var(--parchment) !important;
133
+ border:1px solid var(--bark) !important; }
134
+ table { font-size:13px !important; }
135
+ thead { background:var(--soil) !important; }
136
+ """
137
+
138
+ INTRO = """
139
+ # Task → AI Capability Classifier
140
+ A fine-tuned **DistilBERT** model mapping work tasks to a 9-category AI capability taxonomy,
141
+ trained on 18,796 labeled O*NET tasks. Type a task to classify it, compare the model against
142
+ the authored labels, or browse the corpus.
143
+ """
144
+
145
+ with gr.Blocks(css=CSS, title="Task → Capability Classifier") as demo:
146
+ gr.Markdown(INTRO)
147
+
148
+ with gr.Tab("Classify"):
149
+ gr.Markdown("Enter any task description. The model returns its predicted capability and confidence across all nine.")
150
+ inp = gr.Textbox(label="Task description", lines=3,
151
+ placeholder="e.g. Reconcile vendor invoices against purchase orders and flag discrepancies")
152
+ btn = gr.Button("Classify", variant="primary")
153
+ out_md = gr.Markdown()
154
+ out_lbl = gr.Label(num_top_classes=9, label="All capabilities")
155
+ btn.click(predict_mode, inp, [out_md, out_lbl])
156
+
157
+ with gr.Tab("Authored vs Model"):
158
+ gr.Markdown("Paste a task that exists in the corpus to see the human-authored label beside the model's prediction. Novel tasks fall back to the model alone.")
159
+ inp2 = gr.Textbox(label="Task description", lines=3)
160
+ btn2 = gr.Button("Compare", variant="primary")
161
+ out_md2 = gr.Markdown()
162
+ out_meta = gr.Markdown()
163
+ out_lbl2 = gr.Label(num_top_classes=9, label="Model scores")
164
+ btn2.click(lookup_mode, inp2, [out_md2, out_lbl2, out_meta])
165
+
166
+ with gr.Tab("Browse corpus"):
167
+ gr.Markdown("Search and filter all 18,796 authored task→capability mappings.")
168
+ with gr.Row():
169
+ q = gr.Textbox(label="Search task text", scale=3)
170
+ fn = gr.Dropdown(FUNCTIONS, value="All", label="Function", scale=1)
171
+ lim = gr.Slider(10, 200, value=50, step=10, label="Max rows", scale=1)
172
+ tbl = gr.Dataframe(headers=["Task", "Capability", "Occupation", "Function"], wrap=True)
173
+ for c in (q, fn, lim):
174
+ c.change(browse, [q, fn, lim], tbl)
175
+ demo.load(browse, [q, fn, lim], tbl)
176
+
177
+ if __name__ == "__main__":
178
+ demo.launch()
corpus.csv ADDED
The diff for this file is too large to render. See raw diff
 
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ gradio==4.44.0
2
+ transformers==4.44.2
3
+ torch==2.4.0
4
+ pandas==2.2.2