Pro-Coder commited on
Commit
f0fae3f
·
verified ·
1 Parent(s): 72ce666

Upload 28 files

Browse files
.gitignore ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ __pycache__/
2
+ *.pyc
3
+ .ipynb_checkpoints/
4
+ .DS_Store
5
+ .env
6
+ venv/
7
+ .venv/
DEPLOY.md ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Deploying to Hugging Face Spaces
2
+
3
+ ## A note on hardware / ZeroGPU
4
+
5
+ This app is **CPU-only by design** — all local ML (intent classifier,
6
+ anomaly detector, TF-IDF retrieval) runs on scikit-learn, and the LLM
7
+ call goes to the remote HF Inference API rather than running locally.
8
+
9
+ If your account only offers the **ZeroGPU** hardware tier (some free/new
10
+ accounts can't select CPU-basic for new Spaces), that's fine: `app.py`
11
+ includes a small `@spaces.GPU`-decorated health-check function purely so
12
+ the platform's ZeroGPU compatibility check passes at startup. It's never
13
+ called on the actual request path, so it adds no latency or GPU cost —
14
+ you can safely select ZeroGPU hardware when creating the Space.
15
+
16
+ Two ways to deploy: the web UI (easiest, no git needed) or the CLI/git route.
17
+
18
+ ## Option A — Web UI upload (fastest)
19
+
20
+ 1. Go to https://huggingface.co/new-space
21
+ 2. Fill in:
22
+ - **Space name:** e.g. `daifuku-warehouse-ai`
23
+ - **License:** MIT (or your choice)
24
+ - **Select the Space SDK:** **Gradio**
25
+ - **Space hardware:** CPU basic (free tier is enough for this app)
26
+ - Visibility: **Public** (so you can share the link with Daifuku)
27
+ 3. Click **Create Space**.
28
+ 4. On the new Space page, click **Files → Add file → Upload files**, and
29
+ upload the *entire project folder contents* (keep the folder structure:
30
+ `app.py`, `requirements.txt`, `README.md`, `src/`, `models/`, `data/`,
31
+ `assets/`). Drag-and-drop the whole folder works in most browsers.
32
+ 5. Wait for the Space to build (check the **Logs** tab if it fails — almost
33
+ always a missing/incompatible package version).
34
+ 6. Once it shows "Running", your demo is live at:
35
+ `https://huggingface.co/spaces/<your-username>/daifuku-warehouse-ai`
36
+
37
+ ## Option B — git (recommended if you'll keep iterating)
38
+
39
+ ```bash
40
+ # 1. Install the CLI and log in (needs a token with "write" scope)
41
+ pip install huggingface_hub
42
+ huggingface-cli login
43
+
44
+ # 2. Create the Space (or create it via the web UI first, then just clone it)
45
+ huggingface-cli repo create daifuku-warehouse-ai --type space --space_sdk gradio
46
+
47
+ # 3. Clone it, copy in the project files, and push
48
+ git clone https://huggingface.co/spaces/<your-username>/daifuku-warehouse-ai
49
+ cd daifuku-warehouse-ai
50
+ cp -r /path/to/this/project/* .
51
+ git add .
52
+ git commit -m "Initial commit: Smart Warehouse AI Assistant"
53
+ git push
54
+ ```
55
+
56
+ The Space will automatically build from `requirements.txt` and launch
57
+ `app.py` (as declared in the README's YAML front matter: `sdk: gradio`,
58
+ `app_file: app.py`).
59
+
60
+ ## Enabling the LLM (recommended before sharing with Daifuku)
61
+
62
+ By default the Space runs in **retrieval-only fallback mode** — it still
63
+ works, but answers are extractive rather than LLM-generated. To turn on
64
+ real LLM responses:
65
+
66
+ 1. Create an access token at https://huggingface.co/settings/tokens
67
+ (a "Read" token is sufficient for Inference API calls).
68
+ 2. In your Space, go to **Settings → Variables and secrets → New secret**.
69
+ - Name: `HF_TOKEN`
70
+ - Value: your token
71
+ 3. (Optional) Add another secret/variable `LLM_MODEL_ID` if you want a
72
+ different hosted model than the default `Qwen/Qwen2.5-7B-Instruct`
73
+ (any chat-capable model available via HF Inference Providers works).
74
+ 4. Restart the Space (**Settings → Factory reboot**, or just wait — it
75
+ picks up new secrets on the next restart).
76
+
77
+ ## Re-training / updating the models
78
+
79
+ The Space **loads pre-built artifacts** from `models/` and `data/` — it
80
+ does not retrain on startup, so boot time stays fast. If you change
81
+ `src/data_generation.py`, `src/intent_model.py`, or `src/anomaly_model.py`,
82
+ regenerate everything locally before pushing:
83
+
84
+ ```bash
85
+ python build_artifacts.py
86
+ git add models/ data/ assets/
87
+ git commit -m "Retrain models"
88
+ git push
89
+ ```
90
+
91
+ ## Sharing with Daifuku
92
+
93
+ Once it's live, share the Space URL directly:
94
+
95
+ ```
96
+ https://huggingface.co/spaces/<your-username>/daifuku-warehouse-ai
97
+ ```
98
+
99
+ Consider also linking the **Model Evaluation** tab specifically in your
100
+ application/cover letter, since it's the clearest evidence of rigorous,
101
+ reproducible ML work rather than just a UI demo.
README.md CHANGED
@@ -1,14 +1,117 @@
1
  ---
2
- title: SmartWareHouseAI
3
- emoji: 😻
4
- colorFrom: gray
5
- colorTo: yellow
6
  sdk: gradio
7
- sdk_version: 6.22.0
8
- python_version: '3.12'
9
  app_file: app.py
10
  pinned: false
11
  license: mit
 
12
  ---
13
 
14
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: Smart Warehouse AI Assistant
3
+ emoji: 🏭
4
+ colorFrom: blue
5
+ colorTo: indigo
6
  sdk: gradio
7
+ sdk_version: 5.9.1
 
8
  app_file: app.py
9
  pinned: false
10
  license: mit
11
+ short_description: LLM warehouse copilot with predictive maintenance
12
  ---
13
 
14
+ # 🏭 Smart Warehouse AI Assistant
15
+
16
+ An LLM-powered, retrieval-grounded AI copilot for automated warehouse
17
+ operations -- built as a portfolio / application project. Combines an
18
+ **LLM assistant (RAG)**, an **intent classifier**, an **inventory/order
19
+ query layer**, and an **Isolation-Forest predictive-maintenance model**,
20
+ with a full **Model Evaluation** tab reporting real accuracy/F1/ROC-AUC
21
+ metrics on held-out test data.
22
+
23
+ 👉 **Live demo:** add your Space URL here once deployed, e.g.
24
+ `https://huggingface.co/spaces/<your-username>/daifuku-warehouse-ai`
25
+
26
+ ## Tabs
27
+
28
+ 1. **💬 AI Assistant** — ask free-text warehouse-ops questions; answers are
29
+ grounded via TF-IDF retrieval over a small knowledge base and generated
30
+ by a hosted LLM (Hugging Face Inference API), with a transparent
31
+ retrieval-only fallback if no API key is configured.
32
+ 2. **📦 Inventory & Order Query** — natural-language queries over synthetic
33
+ inventory / order tables (SKU, zone, order-id extraction).
34
+ 3. **⚠️ Predictive Maintenance** — Isolation Forest anomaly detector over
35
+ conveyor/crane motor sensor readings (temperature, vibration, current,
36
+ belt speed).
37
+ 4. **📊 Model Evaluation** — accuracy, macro-F1, confusion matrices,
38
+ ROC-AUC, retrieval hit-rate, and latency benchmarks, all computed on
39
+ held-out data by `build_artifacts.py`.
40
+ 5. **ℹ️ About** — project write-up, architecture diagram, tech stack.
41
+
42
+ ## Quick start (local)
43
+
44
+ ```bash
45
+ git clone <this-repo>
46
+ cd daifuku-warehouse-ai
47
+ pip install -r requirements.txt
48
+
49
+ # (re)generate datasets, train models, produce evaluation plots/metrics
50
+ python build_artifacts.py
51
+
52
+ # run the app
53
+ python app.py
54
+ ```
55
+
56
+ Open the printed local URL (usually `http://127.0.0.1:7860`).
57
+
58
+ ## Enabling full LLM responses
59
+
60
+ The app works out of the box in **retrieval-only fallback mode** (no
61
+ external API calls). To enable real LLM-generated answers:
62
+
63
+ 1. Create a Hugging Face access token: https://huggingface.co/settings/tokens
64
+ 2. Set it as an environment variable / Space secret named `HF_TOKEN`.
65
+ 3. (Optional) Set `LLM_MODEL_ID` to override the default model
66
+ (`Qwen/Qwen2.5-7B-Instruct`) with any chat-capable model available via
67
+ HF Inference Providers.
68
+
69
+ ```bash
70
+ export HF_TOKEN=hf_xxxxxxxxxxxxxxxxxxxx
71
+ python app.py
72
+ ```
73
+
74
+ ## Deploying to Hugging Face Spaces
75
+
76
+ See [`DEPLOY.md`](./DEPLOY.md) for full step-by-step instructions.
77
+
78
+ ## Project structure
79
+
80
+ ```
81
+ daifuku-warehouse-ai/
82
+ ├── app.py # Gradio app (5 tabs)
83
+ ├── build_artifacts.py # generates data, trains models, evaluates, saves plots
84
+ ├── requirements.txt
85
+ ├── src/
86
+ │ ├── data_generation.py # synthetic intent / inventory / sensor datasets
87
+ │ ├── knowledge_base.py # warehouse-ops knowledge base (RAG source docs)
88
+ │ ├── retriever.py # TF-IDF retriever
89
+ │ ├── intent_model.py # intent classifier (train/predict)
90
+ │ ├── anomaly_model.py # Isolation Forest anomaly detector
91
+ │ ├── llm_client.py # HF Inference API client + fallback
92
+ │ └── inventory_db.py # NL -> structured query helpers
93
+ ├── models/ # trained model artifacts (.joblib)
94
+ ├── data/ # generated datasets + evaluation JSON
95
+ └── assets/ # evaluation plots (confusion matrices, ROC curve)
96
+ ```
97
+
98
+ ## Evaluation summary
99
+
100
+ See the in-app **Model Evaluation** tab for full details (confusion
101
+ matrices, per-class precision/recall, retrieval hit-rate table, latency
102
+ benchmark). Headline numbers from the included run:
103
+
104
+ | Component | Metric | Score |
105
+ |---|---|---|
106
+ | Intent classifier | Accuracy | ~99% |
107
+ | Intent classifier | Macro F1 | ~99% |
108
+ | Anomaly detector | F1 | ~97% |
109
+ | Anomaly detector | ROC-AUC | ~1.00 |
110
+ | RAG retriever | Hit-rate@2 | 100% |
111
+
112
+ *(Computed on synthetic, held-out test data — see the Evaluation tab for
113
+ methodology notes.)*
114
+
115
+ ## License
116
+
117
+ MIT — feel free to fork and adapt.
app.py ADDED
@@ -0,0 +1,494 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Smart Warehouse AI Assistant
3
+ =============================
4
+ A Daifuku-style intralogistics AI copilot demo, built for a Hugging Face
5
+ Space. Combines:
6
+
7
+ 1. An LLM-powered assistant (RAG: TF-IDF retrieval + hosted LLM via the
8
+ HF Inference API) for natural-language warehouse operations Q&A.
9
+ 2. A TF-IDF + Logistic Regression intent classifier that routes queries
10
+ into 8 operational categories.
11
+ 3. A lightweight NL -> structured query layer over synthetic inventory /
12
+ order tables.
13
+ 4. An Isolation Forest anomaly detector for conveyor/crane sensor
14
+ streams (predictive maintenance).
15
+ 5. A Model Evaluation tab reporting real accuracy/F1/ROC-AUC metrics
16
+ computed by build_artifacts.py.
17
+
18
+ Author: (your name here) -- built as an application project for Daifuku Co., Ltd.
19
+ """
20
+
21
+ import json
22
+ import os
23
+
24
+ import gradio as gr
25
+ import pandas as pd
26
+
27
+ from src.anomaly_model import FEATURES as SENSOR_FEATURES
28
+ from src.anomaly_model import load_artifacts as load_anomaly_artifacts
29
+ from src.anomaly_model import score_reading
30
+ from src.data_generation import generate_inventory_db, generate_orders_db
31
+ from src.intent_model import INTENT_DESCRIPTIONS, load_pipeline, predict as intent_predict
32
+ from src.inventory_db import query_inventory, query_orders
33
+ from src.llm_client import answer_query
34
+ from src.retriever import KBRetriever
35
+
36
+ ROOT = os.path.dirname(os.path.abspath(__file__))
37
+ MODELS_DIR = os.path.join(ROOT, "models")
38
+ DATA_DIR = os.path.join(ROOT, "data")
39
+ ASSETS_DIR = os.path.join(ROOT, "assets")
40
+
41
+ # --------------------------------------------------------------------------
42
+ # Load pre-trained artifacts (fast: no training happens at Space startup)
43
+ # --------------------------------------------------------------------------
44
+ intent_pipeline = load_pipeline(os.path.join(MODELS_DIR, "intent_pipeline.joblib"))
45
+ anomaly_model, anomaly_scaler = load_anomaly_artifacts(
46
+ os.path.join(MODELS_DIR, "anomaly_iforest.joblib"),
47
+ os.path.join(MODELS_DIR, "anomaly_scaler.joblib"),
48
+ )
49
+ retriever = KBRetriever()
50
+
51
+ # Prefer the pre-generated CSVs (so demo state matches the eval run); fall back to
52
+ # regenerating in-memory if they're missing for some reason.
53
+ try:
54
+ inventory_df = pd.read_csv(os.path.join(DATA_DIR, "inventory.csv"))
55
+ orders_df = pd.read_csv(os.path.join(DATA_DIR, "orders.csv"))
56
+ except FileNotFoundError:
57
+ inventory_df = generate_inventory_db()
58
+ orders_df = generate_orders_db()
59
+
60
+
61
+ def _load_json(name):
62
+ path = os.path.join(DATA_DIR, name)
63
+ if os.path.exists(path):
64
+ with open(path) as f:
65
+ return json.load(f)
66
+ return {}
67
+
68
+
69
+ intent_eval = _load_json("intent_eval.json")
70
+ anomaly_eval = _load_json("anomaly_eval.json")
71
+ retrieval_eval = _load_json("retrieval_eval.json")
72
+ latency_eval = _load_json("latency_eval.json")
73
+
74
+ HF_TOKEN_SET = bool(os.environ.get("HF_TOKEN"))
75
+
76
+ # --------------------------------------------------------------------------
77
+ # ZeroGPU compatibility shim
78
+ # --------------------------------------------------------------------------
79
+ # This app is CPU-only by design (scikit-learn locally, LLM calls go to the
80
+ # remote HF Inference API). Some Spaces accounts, however, only offer the
81
+ # free "ZeroGPU" hardware tier, which requires at least one function
82
+ # decorated with `@spaces.GPU` to be present or the platform's startup
83
+ # check fails with "No @spaces.GPU function detected". This is a harmless,
84
+ # unused health-check function that satisfies that requirement without
85
+ # changing any real behaviour -- it is never called on the request path.
86
+ try:
87
+ import spaces
88
+
89
+ @spaces.GPU(duration=5)
90
+ def _zerogpu_healthcheck():
91
+ return True
92
+
93
+ except ImportError:
94
+ # Running locally / on CPU-basic hardware where `spaces` isn't installed.
95
+ def _zerogpu_healthcheck():
96
+ return True
97
+
98
+
99
+ # ==========================================================================
100
+ # TAB 1 -- AI Assistant (LLM + RAG + intent routing)
101
+ # ==========================================================================
102
+
103
+ def chat_fn(message, history):
104
+ intent = intent_predict(intent_pipeline, message)
105
+ response = answer_query(message, retriever)
106
+
107
+ intent_label = INTENT_DESCRIPTIONS.get(intent.intent, intent.intent)
108
+ meta_lines = [f"**Detected intent:** {intent_label} ({intent.confidence:.0%} confidence)"]
109
+ if response.sources:
110
+ src_str = ", ".join(f"{s.title} ({s.score:.2f})" for s in response.sources)
111
+ meta_lines.append(f"**Retrieved context:** {src_str}")
112
+ meta_lines.append(
113
+ f"**Generation:** {'LLM (' + response.model_id + ')' if response.used_llm else 'retrieval-only fallback'}"
114
+ f" · {response.latency_s * 1000:.0f} ms"
115
+ )
116
+
117
+ full_reply = response.answer + "\n\n---\n" + "\n".join(meta_lines)
118
+ return full_reply
119
+
120
+
121
+ ASSISTANT_EXAMPLES = [
122
+ "The conveyor belt in Zone C is making noise",
123
+ "How many units of SKU-1042 are in Zone B?",
124
+ "What's the difference between an AGV and an AMR?",
125
+ "A forklift near-miss was reported in Zone A",
126
+ "What's the fastest picking route for a high volume order?",
127
+ "Is Crane-03 operational?",
128
+ ]
129
+
130
+
131
+ # ==========================================================================
132
+ # TAB 2 -- Inventory & Order Query
133
+ # ==========================================================================
134
+
135
+ def inventory_query_fn(text):
136
+ intent = intent_predict(intent_pipeline, text)
137
+ if intent.intent == "order_status":
138
+ result = query_orders(orders_df, text)
139
+ note = "Interpreted as an **order status** query."
140
+ else:
141
+ result = query_inventory(inventory_df, text)
142
+ note = "Interpreted as an **inventory** query."
143
+ if result.empty:
144
+ result = pd.DataFrame({"message": ["No matching records found for this query."]})
145
+ return note, result
146
+
147
+
148
+ # ==========================================================================
149
+ # TAB 3 -- Predictive Maintenance / Anomaly Detection
150
+ # ==========================================================================
151
+
152
+ def anomaly_fn(motor_temp, vibration, current, belt_speed):
153
+ reading = {
154
+ "motor_temp_c": motor_temp,
155
+ "vibration_mm_s": vibration,
156
+ "current_amps": current,
157
+ "belt_speed_mps": belt_speed,
158
+ }
159
+ result = score_reading(anomaly_model, anomaly_scaler, reading)
160
+ verdict = "🔴 ANOMALY DETECTED" if result.is_anomaly else "🟢 Normal operating range"
161
+ detail = (
162
+ f"### {verdict}\n\n"
163
+ f"**Anomaly score:** {result.anomaly_score:.2f} / 1.00\n\n"
164
+ f"| Sensor | Value | Typical normal range |\n"
165
+ f"|---|---|---|\n"
166
+ f"| Motor temperature | {motor_temp:.1f} °C | 47–63 °C |\n"
167
+ f"| Vibration | {vibration:.2f} mm/s | 1.2–3.2 mm/s |\n"
168
+ f"| Motor current | {current:.1f} A | 9–15 A |\n"
169
+ f"| Belt speed | {belt_speed:.2f} m/s | 1.2–1.8 m/s |\n"
170
+ )
171
+ if result.is_anomaly:
172
+ detail += (
173
+ "\n**Recommended action:** Flag for inspection. Elevated temperature + "
174
+ "vibration + current with reduced belt speed typically indicates bearing "
175
+ "wear, belt misalignment, or motor overload -- schedule maintenance before "
176
+ "the next shift to avoid an unplanned stoppage."
177
+ )
178
+ return detail
179
+
180
+
181
+ ANOMALY_PRESETS = {
182
+ "Normal reading": (55.0, 2.2, 12.0, 1.5),
183
+ "Early bearing wear": (68.0, 3.8, 15.5, 1.3),
184
+ "Severe fault (imminent failure)": (85.0, 6.5, 21.0, 0.6),
185
+ }
186
+
187
+
188
+ def load_preset(name):
189
+ return ANOMALY_PRESETS[name]
190
+
191
+
192
+ # ==========================================================================
193
+ # TAB 4 -- Model Evaluation
194
+ # ==========================================================================
195
+
196
+ def build_evaluation_markdown():
197
+ cls_report = intent_eval.get("classification_report", {})
198
+ per_class_rows = []
199
+ for cls in intent_eval.get("classes", []):
200
+ stats = cls_report.get(cls, {})
201
+ per_class_rows.append(
202
+ f"| {cls} | {stats.get('precision', 0):.2f} | {stats.get('recall', 0):.2f} | "
203
+ f"{stats.get('f1-score', 0):.2f} | {int(stats.get('support', 0))} |"
204
+ )
205
+ per_class_table = "\n".join(per_class_rows)
206
+
207
+ retrieval_rows = "\n".join(
208
+ f"| {r['query']} | {r['expected']} | {r['retrieved_top1']} | "
209
+ f"{'✅' if r['hit@1'] else ('〰️' if r['hit@2'] else '❌')} | {r['top1_score']:.2f} |"
210
+ for r in retrieval_eval.get("rows", [])
211
+ )
212
+
213
+ md = f"""
214
+ ## 1. Intent Classifier (TF-IDF + Logistic Regression)
215
+
216
+ Trained on {intent_eval.get('n_train', '?')} examples, evaluated on a held-out
217
+ stratified test split of {intent_eval.get('n_test', '?')} examples across
218
+ {intent_eval.get('n_classes', '?')} intent classes.
219
+
220
+ | Metric | Score |
221
+ |---|---|
222
+ | **Accuracy** | **{intent_eval.get('accuracy', 0):.2%}** |
223
+ | **Macro F1** | **{intent_eval.get('macro_f1', 0):.2%}** |
224
+
225
+ **Per-class performance:**
226
+
227
+ | Intent | Precision | Recall | F1 | Support |
228
+ |---|---|---|---|---|
229
+ {per_class_table}
230
+
231
+ ![Confusion Matrix](assets/intent_confusion_matrix.png)
232
+
233
+ ---
234
+
235
+ ## 2. Predictive Maintenance Anomaly Detector (Isolation Forest)
236
+
237
+ Trained unsupervised on scaled sensor features ({', '.join(SENSOR_FEATURES)}),
238
+ evaluated against held-out ground-truth anomaly labels ({anomaly_eval.get('n_test', '?')} test readings,
239
+ {anomaly_eval.get('test_anomaly_rate', 0):.1%} true anomaly rate).
240
+
241
+ | Metric | Score |
242
+ |---|---|
243
+ | **Precision** | **{anomaly_eval.get('precision', 0):.2%}** |
244
+ | **Recall** | **{anomaly_eval.get('recall', 0):.2%}** |
245
+ | **F1 Score** | **{anomaly_eval.get('f1', 0):.2%}** |
246
+ | **ROC-AUC** | **{anomaly_eval.get('roc_auc', 0):.3f}** |
247
+ | Accuracy | {anomaly_eval.get('accuracy', 0):.2%} |
248
+
249
+ ![Anomaly Confusion Matrix](assets/anomaly_confusion_matrix.png)
250
+ ![ROC Curve](assets/anomaly_roc_curve.png)
251
+
252
+ ---
253
+
254
+ ## 3. Retrieval (RAG) Evaluation
255
+
256
+ Hit-rate of the TF-IDF retriever against a hand-labelled query -> expected-document
257
+ evaluation set (higher is better; hit@1 = correct doc ranked first, hit@2 = correct
258
+ doc within top 2).
259
+
260
+ | Metric | Score |
261
+ |---|---|
262
+ | **Hit Rate @ 1** | **{retrieval_eval.get('hit_rate_at_1', 0):.0%}** |
263
+ | **Hit Rate @ 2** | **{retrieval_eval.get('hit_rate_at_2', 0):.0%}** |
264
+
265
+ | Query | Expected Doc | Retrieved (top-1) | Hit | Score |
266
+ |---|---|---|---|---|
267
+ {retrieval_rows}
268
+
269
+ ---
270
+
271
+ ## 4. Latency Benchmark (per-request, CPU)
272
+
273
+ | Component | Avg. latency |
274
+ |---|---|
275
+ | Intent classification | {latency_eval.get('intent_classifier_ms', '?')} ms |
276
+ | Anomaly scoring | {latency_eval.get('anomaly_detector_ms', '?')} ms |
277
+ | KB retrieval (TF-IDF) | {latency_eval.get('kb_retrieval_ms', '?')} ms |
278
+ | LLM generation | Depends on hosted Inference API (measured live per-request in the Assistant tab) |
279
+
280
+ ---
281
+
282
+ ### Evaluation methodology notes
283
+
284
+ - All datasets are **synthetically generated** (see `src/data_generation.py`) using
285
+ templated-but-varied natural language and randomised sensor distributions with a
286
+ fixed seed, so results are fully reproducible via `python build_artifacts.py`.
287
+ - The intent classifier and anomaly detector are evaluated on a **held-out test
288
+ split** they never saw during training (stratified, 25% / 30% respectively).
289
+ - The anomaly detector itself is trained **unsupervised** (Isolation Forest never
290
+ sees the `label` column during `.fit()`); labels are used only to *evaluate* it,
291
+ mirroring how you'd validate an anomaly model against a small set of confirmed
292
+ historical incidents in production.
293
+ - In a production deployment, all three components would be continuously
294
+ re-evaluated against real WMS/WCS/sensor logs rather than synthetic data.
295
+ """
296
+ return md
297
+
298
+
299
+ # ==========================================================================
300
+ # TAB 5 -- About
301
+ # ==========================================================================
302
+
303
+ ABOUT_MD = f"""
304
+ # 🏭 Smart Warehouse AI Assistant
305
+
306
+ **A portfolio project demonstrating an applied-AI approach to intralogistics
307
+ operations, built as part of a job application to Daifuku Co., Ltd.**
308
+
309
+ ## What this demonstrates
310
+
311
+ Daifuku builds material handling and automation systems -- AS/RS, conveyors
312
+ and sortation, AGVs/AMRs, and the software (WMS/WCS) that orchestrates them.
313
+ This project is a compact but end-to-end example of how an AI layer can sit
314
+ on top of that kind of system:
315
+
316
+ | Capability | Where |
317
+ |---|---|
318
+ | **LLM-powered natural-language assistant**, grounded with retrieval (RAG) so it answers from real warehouse-ops knowledge rather than hallucinating | *AI Assistant* tab |
319
+ | **Intent classification** to route free-text requests (maintenance, safety, navigation, inventory, etc.) the way a real ops system would triage tickets | *AI Assistant* / *Inventory* tabs |
320
+ | **Predictive maintenance** via unsupervised anomaly detection on conveyor/crane sensor streams -- catching bearing wear or misalignment before an unplanned stoppage | *Predictive Maintenance* tab |
321
+ | **NL-to-structured-query** over inventory/order data, a lightweight stand-in for a WMS query tool | *Inventory & Order Query* tab |
322
+ | **Rigorous, reproducible evaluation** of every ML component (accuracy, F1, ROC-AUC, retrieval hit-rate, latency) rather than just a demo that "looks like it works" | *Model Evaluation* tab |
323
+
324
+ ## Tech stack
325
+
326
+ - **UI / deployment:** [Gradio](https://gradio.app) on Hugging Face Spaces
327
+ - **LLM:** Hosted instruct model via the Hugging Face **Inference API**
328
+ (`huggingface_hub.InferenceClient`), configurable via the `LLM_MODEL_ID`
329
+ env var. Falls back gracefully to a retrieval-only answer if no `HF_TOKEN`
330
+ is configured, so the public demo never breaks.
331
+ - **Retrieval:** TF-IDF + cosine similarity over a small hand-written
332
+ warehouse-operations knowledge base (simple, fast, fully local RAG).
333
+ - **Intent classification:** TF-IDF + Logistic Regression (scikit-learn) --
334
+ chosen deliberately over a heavier transformer classifier because it
335
+ trains in under a second and comfortably reaches **{intent_eval.get('accuracy', 0):.0%}
336
+ accuracy** on this task; right-sizing the model to the problem.
337
+ - **Anomaly detection:** Isolation Forest (scikit-learn), trained
338
+ unsupervised on scaled sensor features.
339
+ - **Evaluation:** scikit-learn metrics + matplotlib, all computed by
340
+ `build_artifacts.py` and saved as static artifacts the app loads at
341
+ startup (fast, reproducible Space boot).
342
+
343
+ ## Architecture
344
+
345
+ ```
346
+ ┌───────────────────────┐
347
+ User query ───► │ Intent Classifier │ (TF-IDF + LogisticRegression)
348
+ └──────────┬────────────┘
349
+ │ intent label
350
+
351
+ ┌───────────────────────┐
352
+ │ KB Retriever (RAG) │ (TF-IDF cosine similarity)
353
+ └──────────┬────────────┘
354
+ │ top-k passages
355
+
356
+ ┌──���────────────────────┐
357
+ │ Hosted LLM │ (HF Inference API)
358
+ │ (or extractive │
359
+ │ fallback if offline) │
360
+ └──────────┬────────────┘
361
+
362
+ Grounded answer
363
+
364
+ Sensor stream ───► StandardScaler ───► IsolationForest ───► anomaly / normal
365
+ ```
366
+
367
+ ## Why this matters for Daifuku
368
+
369
+ Modern intralogistics platforms generate huge volumes of operational data --
370
+ equipment telemetry, WMS transactions, safety logs. The value of AI here isn't
371
+ a flashy chatbot; it's **routing, grounding, and reliability**: correctly
372
+ triaging a request, answering from real operational context instead of
373
+ guessing, and flagging equipment problems before they cause downtime. This
374
+ project tries to demonstrate that mindset in miniature, with honest,
375
+ reproducible evaluation numbers rather than cherry-picked demo runs.
376
+
377
+ ## Limitations & next steps
378
+
379
+ - All data here is **synthetic**, for portfolio/demo purposes -- a production
380
+ version would connect to real WMS/WCS APIs and historical sensor logs.
381
+ - The intent set (8 classes) and knowledge base (10 articles) are intentionally
382
+ small to keep the demo fast and auditable; both are easy to extend.
383
+ - The anomaly detector uses 4 hand-picked features; a production system would
384
+ likely use a richer multivariate sensor set and a supervised or
385
+ semi-supervised model once labelled failure data is available.
386
+
387
+ ---
388
+ *Built as an application project. Source code available on request / in the
389
+ linked repository. Feedback welcome.*
390
+ """
391
+
392
+
393
+ # ==========================================================================
394
+ # GRADIO APP
395
+ # ==========================================================================
396
+
397
+ CUSTOM_CSS = """
398
+ #title-banner { text-align: center; margin-bottom: 0.5em; }
399
+ .gradio-container { max-width: 1150px !important; margin: auto; }
400
+ """
401
+
402
+ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue"), css=CUSTOM_CSS, title="Smart Warehouse AI Assistant") as demo:
403
+ gr.Markdown(
404
+ "<h1 id='title-banner'>🏭 Smart Warehouse AI Assistant</h1>"
405
+ "<p style='text-align:center; color:gray;'>LLM-powered intralogistics copilot · "
406
+ "intent routing · predictive maintenance · retrieval-grounded Q&A</p>"
407
+ )
408
+ if not HF_TOKEN_SET:
409
+ gr.Markdown(
410
+ "> ⚠️ **No `HF_TOKEN` secret detected.** The AI Assistant tab will run in "
411
+ "**retrieval-only fallback mode** (still functional, just not LLM-generated "
412
+ "prose). Add an `HF_TOKEN` secret in *Space settings → Variables and secrets* "
413
+ "to enable full LLM responses."
414
+ )
415
+
416
+ with gr.Tab("💬 AI Assistant"):
417
+ gr.Markdown(
418
+ "Ask about equipment status, maintenance, safety, inventory, order status, "
419
+ "AGV routing, picking strategy, or general warehouse-automation concepts. "
420
+ "Answers are grounded (RAG) in a small warehouse-operations knowledge base."
421
+ )
422
+ gr.ChatInterface(
423
+ fn=chat_fn,
424
+ type="messages",
425
+ examples=ASSISTANT_EXAMPLES,
426
+ chatbot=gr.Chatbot(height=430, label="Warehouse Assistant", type="messages"),
427
+ textbox=gr.Textbox(placeholder="e.g. The conveyor belt in Zone C is making noise"),
428
+ )
429
+
430
+ with gr.Tab("📦 Inventory & Order Query"):
431
+ gr.Markdown(
432
+ "Type a natural-language inventory or order question. The intent classifier "
433
+ "decides whether to query the inventory table or the orders table, then "
434
+ "extracts SKU / order-id / zone slots to filter the result."
435
+ )
436
+ with gr.Row():
437
+ inv_input = gr.Textbox(label="Query", placeholder="How many units of SKU-1042 are in Zone B?", scale=4)
438
+ inv_btn = gr.Button("Search", variant="primary", scale=1)
439
+ inv_note = gr.Markdown()
440
+ inv_result = gr.Dataframe(label="Results", wrap=True)
441
+ inv_btn.click(inventory_query_fn, inputs=inv_input, outputs=[inv_note, inv_result])
442
+ inv_input.submit(inventory_query_fn, inputs=inv_input, outputs=[inv_note, inv_result])
443
+
444
+ gr.Examples(
445
+ examples=[
446
+ "How many units of SKU-1042 are in Zone B?",
447
+ "What's the status of order #10007?",
448
+ "Show me low stock items",
449
+ "Any delayed orders?",
450
+ ],
451
+ inputs=inv_input,
452
+ )
453
+ with gr.Accordion("Browse full tables", open=False):
454
+ gr.Markdown("**Inventory** (synthetic)")
455
+ gr.Dataframe(inventory_df, wrap=True)
456
+ gr.Markdown("**Orders** (synthetic)")
457
+ gr.Dataframe(orders_df, wrap=True)
458
+
459
+ with gr.Tab("⚠️ Predictive Maintenance"):
460
+ gr.Markdown(
461
+ "Enter live (or hypothetical) conveyor/crane motor sensor readings to check "
462
+ "for anomalous behaviour using an Isolation Forest model trained on "
463
+ "historical sensor patterns."
464
+ )
465
+ preset_dropdown = gr.Dropdown(
466
+ choices=list(ANOMALY_PRESETS.keys()), label="Load a preset reading", value="Normal reading"
467
+ )
468
+ with gr.Row():
469
+ motor_temp_in = gr.Slider(30, 100, value=55, step=0.5, label="Motor temperature (°C)")
470
+ vibration_in = gr.Slider(0, 10, value=2.2, step=0.1, label="Vibration (mm/s)")
471
+ with gr.Row():
472
+ current_in = gr.Slider(5, 30, value=12, step=0.5, label="Motor current (A)")
473
+ belt_speed_in = gr.Slider(0.1, 2.5, value=1.5, step=0.05, label="Belt speed (m/s)")
474
+ check_btn = gr.Button("Check for anomaly", variant="primary")
475
+ anomaly_output = gr.Markdown()
476
+
477
+ preset_dropdown.change(
478
+ load_preset, inputs=preset_dropdown,
479
+ outputs=[motor_temp_in, vibration_in, current_in, belt_speed_in],
480
+ )
481
+ check_btn.click(
482
+ anomaly_fn,
483
+ inputs=[motor_temp_in, vibration_in, current_in, belt_speed_in],
484
+ outputs=anomaly_output,
485
+ )
486
+
487
+ with gr.Tab("📊 Model Evaluation"):
488
+ gr.Markdown(build_evaluation_markdown())
489
+
490
+ with gr.Tab("ℹ️ About"):
491
+ gr.Markdown(ABOUT_MD)
492
+
493
+ if __name__ == "__main__":
494
+ demo.launch(server_name="0.0.0.0", server_port=int(os.environ.get("PORT", 7860)))
assets/anomaly_confusion_matrix.png ADDED
assets/anomaly_roc_curve.png ADDED
assets/intent_confusion_matrix.png ADDED
build_artifacts.py ADDED
@@ -0,0 +1,297 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ build_artifacts.py
3
+ -------------------
4
+ One-shot build script: generates synthetic datasets, trains the intent
5
+ classifier and the anomaly detector, evaluates the retrieval pipeline, and
6
+ saves every model/plot/metric the app needs to `models/`, `data/`, and
7
+ `assets/`. Run this once locally (or in CI) before deploying -- the Gradio
8
+ app itself only *loads* these pre-built artifacts, so the Space starts up
9
+ in a couple of seconds instead of retraining on every boot.
10
+
11
+ Usage:
12
+ python build_artifacts.py
13
+ """
14
+
15
+ import json
16
+ import os
17
+
18
+ import matplotlib
19
+ matplotlib.use("Agg")
20
+ import matplotlib.pyplot as plt
21
+ import numpy as np
22
+ from sklearn.metrics import (
23
+ accuracy_score,
24
+ classification_report,
25
+ confusion_matrix,
26
+ f1_score,
27
+ precision_score,
28
+ recall_score,
29
+ roc_auc_score,
30
+ roc_curve,
31
+ )
32
+ from sklearn.model_selection import train_test_split
33
+ from sklearn.preprocessing import StandardScaler
34
+
35
+ from src.data_generation import (
36
+ RETRIEVAL_EVAL_SET,
37
+ generate_intent_dataset,
38
+ generate_inventory_db,
39
+ generate_orders_db,
40
+ generate_sensor_dataset,
41
+ )
42
+ from src.intent_model import build_pipeline, save_pipeline
43
+ from src.anomaly_model import FEATURES, build_model as build_anomaly_model, save_artifacts as save_anomaly_artifacts
44
+ from src.retriever import KBRetriever
45
+
46
+ ROOT = os.path.dirname(os.path.abspath(__file__))
47
+ MODELS_DIR = os.path.join(ROOT, "models")
48
+ DATA_DIR = os.path.join(ROOT, "data")
49
+ ASSETS_DIR = os.path.join(ROOT, "assets")
50
+ for d in (MODELS_DIR, DATA_DIR, ASSETS_DIR):
51
+ os.makedirs(d, exist_ok=True)
52
+
53
+ SEED = 42
54
+
55
+
56
+ def build_intent_classifier():
57
+ print("== Intent classifier ==")
58
+ df = generate_intent_dataset(n_per_intent=60, seed=SEED)
59
+ df.to_csv(os.path.join(DATA_DIR, "intent_dataset.csv"), index=False)
60
+
61
+ X_train, X_test, y_train, y_test = train_test_split(
62
+ df["text"], df["intent"], test_size=0.25, random_state=SEED, stratify=df["intent"]
63
+ )
64
+
65
+ pipeline = build_pipeline()
66
+ pipeline.fit(X_train, y_train)
67
+
68
+ y_pred = pipeline.predict(X_test)
69
+ acc = accuracy_score(y_test, y_pred)
70
+ macro_f1 = f1_score(y_test, y_pred, average="macro")
71
+ report = classification_report(y_test, y_pred, output_dict=True)
72
+ labels = sorted(df["intent"].unique())
73
+ cm = confusion_matrix(y_test, y_pred, labels=labels)
74
+
75
+ print(f"accuracy={acc:.4f} macro_f1={macro_f1:.4f}")
76
+
77
+ # Confusion matrix plot
78
+ fig, ax = plt.subplots(figsize=(7.5, 6.5))
79
+ im = ax.imshow(cm, cmap="Blues")
80
+ ax.set_xticks(range(len(labels)))
81
+ ax.set_yticks(range(len(labels)))
82
+ ax.set_xticklabels(labels, rotation=45, ha="right", fontsize=8)
83
+ ax.set_yticklabels(labels, fontsize=8)
84
+ ax.set_xlabel("Predicted intent")
85
+ ax.set_ylabel("True intent")
86
+ ax.set_title(f"Intent Classifier Confusion Matrix (acc={acc:.1%})")
87
+ for i in range(len(labels)):
88
+ for j in range(len(labels)):
89
+ ax.text(j, i, cm[i, j], ha="center", va="center",
90
+ color="white" if cm[i, j] > cm.max() / 2 else "black", fontsize=8)
91
+ fig.colorbar(im, ax=ax, fraction=0.046, pad=0.04)
92
+ fig.tight_layout()
93
+ fig.savefig(os.path.join(ASSETS_DIR, "intent_confusion_matrix.png"), dpi=150)
94
+ plt.close(fig)
95
+
96
+ # Retrain on FULL data for the deployed model (more data = better generalisation)
97
+ pipeline_full = build_pipeline()
98
+ pipeline_full.fit(df["text"], df["intent"])
99
+ save_pipeline(pipeline_full, os.path.join(MODELS_DIR, "intent_pipeline.joblib"))
100
+
101
+ metrics = {
102
+ "accuracy": acc,
103
+ "macro_f1": macro_f1,
104
+ "n_train": len(X_train),
105
+ "n_test": len(X_test),
106
+ "n_classes": len(labels),
107
+ "classes": labels,
108
+ "classification_report": report,
109
+ }
110
+ with open(os.path.join(DATA_DIR, "intent_eval.json"), "w") as f:
111
+ json.dump(metrics, f, indent=2)
112
+ return metrics
113
+
114
+
115
+ def build_anomaly_detector():
116
+ print("== Anomaly detector ==")
117
+ df = generate_sensor_dataset(n_normal=900, n_anomaly=100, seed=SEED)
118
+ df.to_csv(os.path.join(DATA_DIR, "sensor_dataset.csv"), index=False)
119
+
120
+ X = df[FEATURES].values
121
+ y = df["label"].values # ground truth, used only for evaluation (model itself is unsupervised)
122
+
123
+ X_train, X_test, y_train, y_test = train_test_split(
124
+ X, y, test_size=0.3, random_state=SEED, stratify=y
125
+ )
126
+
127
+ scaler = StandardScaler()
128
+ X_train_scaled = scaler.fit_transform(X_train)
129
+ X_test_scaled = scaler.transform(X_test)
130
+
131
+ # Contamination set close to the true training-set anomaly rate
132
+ contamination = float(np.clip(y_train.mean(), 0.01, 0.4))
133
+ model = build_anomaly_model(contamination=contamination, seed=SEED)
134
+ model.fit(X_train_scaled)
135
+
136
+ raw_scores = model.decision_function(X_test_scaled) # higher = more normal
137
+ anomaly_scores = 0.5 - raw_scores # higher = more anomalous
138
+ preds = model.predict(X_test_scaled)
139
+ preds_binary = (preds == -1).astype(int)
140
+
141
+ precision = precision_score(y_test, preds_binary, zero_division=0)
142
+ recall = recall_score(y_test, preds_binary, zero_division=0)
143
+ f1 = f1_score(y_test, preds_binary, zero_division=0)
144
+ try:
145
+ roc_auc = roc_auc_score(y_test, anomaly_scores)
146
+ except ValueError:
147
+ roc_auc = float("nan")
148
+ acc = accuracy_score(y_test, preds_binary)
149
+ cm = confusion_matrix(y_test, preds_binary)
150
+
151
+ print(f"precision={precision:.4f} recall={recall:.4f} f1={f1:.4f} roc_auc={roc_auc:.4f}")
152
+
153
+ # Confusion matrix plot
154
+ fig, ax = plt.subplots(figsize=(4.5, 4))
155
+ im = ax.imshow(cm, cmap="Oranges")
156
+ ax.set_xticks([0, 1]); ax.set_yticks([0, 1])
157
+ ax.set_xticklabels(["Normal", "Anomaly"])
158
+ ax.set_yticklabels(["Normal", "Anomaly"])
159
+ ax.set_xlabel("Predicted"); ax.set_ylabel("Actual")
160
+ ax.set_title(f"Anomaly Detector Confusion Matrix\n(F1={f1:.2f})")
161
+ for i in range(2):
162
+ for j in range(2):
163
+ ax.text(j, i, cm[i, j], ha="center", va="center",
164
+ color="white" if cm[i, j] > cm.max() / 2 else "black")
165
+ fig.colorbar(im, ax=ax, fraction=0.046, pad=0.04)
166
+ fig.tight_layout()
167
+ fig.savefig(os.path.join(ASSETS_DIR, "anomaly_confusion_matrix.png"), dpi=150)
168
+ plt.close(fig)
169
+
170
+ # ROC curve plot
171
+ fpr, tpr, _ = roc_curve(y_test, anomaly_scores)
172
+ fig, ax = plt.subplots(figsize=(5, 4.5))
173
+ ax.plot(fpr, tpr, label=f"ROC-AUC = {roc_auc:.3f}", color="#2563eb", linewidth=2)
174
+ ax.plot([0, 1], [0, 1], linestyle="--", color="gray", linewidth=1)
175
+ ax.set_xlabel("False Positive Rate")
176
+ ax.set_ylabel("True Positive Rate")
177
+ ax.set_title("Anomaly Detector ROC Curve")
178
+ ax.legend(loc="lower right")
179
+ fig.tight_layout()
180
+ fig.savefig(os.path.join(ASSETS_DIR, "anomaly_roc_curve.png"), dpi=150)
181
+ plt.close(fig)
182
+
183
+ # Retrain on full data for the deployed model
184
+ scaler_full = StandardScaler()
185
+ X_full_scaled = scaler_full.fit_transform(X)
186
+ contamination_full = float(np.clip(y.mean(), 0.01, 0.4))
187
+ model_full = build_anomaly_model(contamination=contamination_full, seed=SEED)
188
+ model_full.fit(X_full_scaled)
189
+ save_anomaly_artifacts(
190
+ model_full, scaler_full,
191
+ os.path.join(MODELS_DIR, "anomaly_iforest.joblib"),
192
+ os.path.join(MODELS_DIR, "anomaly_scaler.joblib"),
193
+ )
194
+
195
+ metrics = {
196
+ "precision": precision,
197
+ "recall": recall,
198
+ "f1": f1,
199
+ "roc_auc": roc_auc,
200
+ "accuracy": acc,
201
+ "n_test": len(y_test),
202
+ "test_anomaly_rate": float(y_test.mean()),
203
+ "contamination_used": contamination,
204
+ }
205
+ with open(os.path.join(DATA_DIR, "anomaly_eval.json"), "w") as f:
206
+ json.dump(metrics, f, indent=2)
207
+ return metrics
208
+
209
+
210
+ def build_retrieval_eval():
211
+ print("== Retrieval (RAG) evaluation ==")
212
+ retriever = KBRetriever()
213
+ hits_at_1, hits_at_2 = 0, 0
214
+ rows = []
215
+ for query, expected_id in RETRIEVAL_EVAL_SET:
216
+ results = retriever.retrieve(query, k=2)
217
+ top_ids = [r.id for r in results]
218
+ hit1 = top_ids[0] == expected_id
219
+ hit2 = expected_id in top_ids
220
+ hits_at_1 += int(hit1)
221
+ hits_at_2 += int(hit2)
222
+ rows.append({
223
+ "query": query,
224
+ "expected": expected_id,
225
+ "retrieved_top1": top_ids[0],
226
+ "hit@1": hit1,
227
+ "hit@2": hit2,
228
+ "top1_score": round(results[0].score, 4),
229
+ })
230
+
231
+ n = len(RETRIEVAL_EVAL_SET)
232
+ metrics = {
233
+ "hit_rate_at_1": hits_at_1 / n,
234
+ "hit_rate_at_2": hits_at_2 / n,
235
+ "n_queries": n,
236
+ "rows": rows,
237
+ }
238
+ print(f"hit@1={metrics['hit_rate_at_1']:.2f} hit@2={metrics['hit_rate_at_2']:.2f}")
239
+ with open(os.path.join(DATA_DIR, "retrieval_eval.json"), "w") as f:
240
+ json.dump(metrics, f, indent=2)
241
+ return metrics
242
+
243
+
244
+ def build_inventory_and_orders():
245
+ print("== Inventory & Orders synthetic DB ==")
246
+ inv = generate_inventory_db(seed=SEED)
247
+ orders = generate_orders_db(seed=SEED)
248
+ inv.to_csv(os.path.join(DATA_DIR, "inventory.csv"), index=False)
249
+ orders.to_csv(os.path.join(DATA_DIR, "orders.csv"), index=False)
250
+ print(f"inventory rows={len(inv)} orders rows={len(orders)}")
251
+
252
+
253
+ def build_latency_benchmark(intent_metrics, anomaly_metrics):
254
+ print("== Latency benchmark ==")
255
+ import time
256
+ from src.intent_model import load_pipeline, predict as intent_predict
257
+ from src.anomaly_model import load_artifacts, score_reading
258
+
259
+ pipeline = load_pipeline(os.path.join(MODELS_DIR, "intent_pipeline.joblib"))
260
+ model, scaler = load_artifacts(
261
+ os.path.join(MODELS_DIR, "anomaly_iforest.joblib"),
262
+ os.path.join(MODELS_DIR, "anomaly_scaler.joblib"),
263
+ )
264
+ retriever = KBRetriever()
265
+
266
+ sample_query = "The conveyor belt in Zone C is making noise"
267
+ sample_reading = {"motor_temp_c": 82.0, "vibration_mm_s": 6.1, "current_amps": 20.5, "belt_speed_mps": 0.7}
268
+
269
+ def timeit(fn, n=50):
270
+ start = time.perf_counter()
271
+ for _ in range(n):
272
+ fn()
273
+ return (time.perf_counter() - start) / n * 1000 # ms
274
+
275
+ intent_ms = timeit(lambda: intent_predict(pipeline, sample_query))
276
+ anomaly_ms = timeit(lambda: score_reading(model, scaler, sample_reading))
277
+ retrieval_ms = timeit(lambda: retriever.retrieve(sample_query, k=2))
278
+
279
+ latency = {
280
+ "intent_classifier_ms": round(intent_ms, 3),
281
+ "anomaly_detector_ms": round(anomaly_ms, 3),
282
+ "kb_retrieval_ms": round(retrieval_ms, 3),
283
+ "note": "LLM generation latency depends on the external Inference API "
284
+ "call and is measured live in the app, not benchmarked here.",
285
+ }
286
+ with open(os.path.join(DATA_DIR, "latency_eval.json"), "w") as f:
287
+ json.dump(latency, f, indent=2)
288
+ print(latency)
289
+
290
+
291
+ if __name__ == "__main__":
292
+ intent_metrics = build_intent_classifier()
293
+ anomaly_metrics = build_anomaly_detector()
294
+ build_retrieval_eval()
295
+ build_inventory_and_orders()
296
+ build_latency_benchmark(intent_metrics, anomaly_metrics)
297
+ print("\nAll artifacts built successfully.")
data/anomaly_eval.json ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "precision": 0.9375,
3
+ "recall": 1.0,
4
+ "f1": 0.967741935483871,
5
+ "roc_auc": 1.0,
6
+ "accuracy": 0.9933333333333333,
7
+ "n_test": 300,
8
+ "test_anomaly_rate": 0.1,
9
+ "contamination_used": 0.1
10
+ }
data/intent_dataset.csv ADDED
@@ -0,0 +1,481 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ text,intent
2
+ Is order #79471 delayed?,order_status
3
+ Is the sorter in Zone C running normally?,system_status
4
+ What is the uptime for Sorter-02 today?,system_status
5
+ Recommend a picking strategy for high-velocity SKUs,picking_optimization
6
+ Is the sorter in the receiving dock running normally?,system_status
7
+ The sorter in the mezzanine keeps jamming,equipment_maintenance
8
+ Optimize the pick path for Zone D,picking_optimization
9
+ Is Crane-03 operational?,system_status
10
+ Has order #25928 shipped yet?,order_status
11
+ What's the difference between AGV and AMR?,general_faq
12
+ What is the current stock level for SKU-1139?,inventory_check
13
+ Optimize the pick path for the receiving dock,picking_optimization
14
+ What's the difference between AGV and AMR?,general_faq
15
+ How can we reduce travel time for pickers in Zone C?,picking_optimization
16
+ What is the current stock level for SKU-9389?,inventory_check
17
+ What's the status of order #90477?,order_status
18
+ How much inventory is left for SKU-1882?,inventory_check
19
+ What is a WMS?,general_faq
20
+ Is SKU-8017 in stock at Zone A?,inventory_check
21
+ Send AGV AMR-21 to Zone B,agv_navigation
22
+ Redirect Sorter-02 around the blocked aisle in Zone B,agv_navigation
23
+ Explain how an AS/RS works,general_faq
24
+ When will order #90496 be delivered?,order_status
25
+ What's the fastest picking route for order #33531?,picking_optimization
26
+ Why hasn't order #61694 left the dock yet?,order_status
27
+ What KPIs matter most in warehouse automation?,general_faq
28
+ File an incident report for Zone D,safety_incident
29
+ "A worker slipped near AMR-21, please log it",safety_incident
30
+ "A worker slipped near Sorter-02, please log it",safety_incident
31
+ What is the current stock level for SKU-9444?,inventory_check
32
+ Is Crane-03 operational?,system_status
33
+ What is the current stock level for SKU-5638?,inventory_check
34
+ Are all cranes online in Zone D?,system_status
35
+ What is predictive maintenance?,general_faq
36
+ What is the uptime for AMR-21 today?,system_status
37
+ Track order #90980 for me,order_status
38
+ Log a safety incident involving Crane-05,safety_incident
39
+ "Belt AGV-12 stopped unexpectedly, please check",equipment_maintenance
40
+ What KPIs matter most in warehouse automation?,general_faq
41
+ Check inventory count for SKU-9594 in the mezzanine,inventory_check
42
+ A forklift near-miss was reported in the receiving dock,safety_incident
43
+ Why is AGV-12 stuck near Zone D?,agv_navigation
44
+ Has order #77844 shipped yet?,order_status
45
+ What is the current location of AGV-07?,agv_navigation
46
+ Do we have enough SKU-7730 to fulfill 200 units?,inventory_check
47
+ Report unsafe pallet stacking in Zone D,safety_incident
48
+ What's the difference between AGV and AMR?,general_faq
49
+ Track order #39863 for me,order_status
50
+ "Belt AGV-07 stopped unexpectedly, please check",equipment_maintenance
51
+ Is order #36387 delayed?,order_status
52
+ What is the uptime for Conveyor-14 today?,system_status
53
+ There was a near collision between AGV-12 and a pedestrian in Zone B,safety_incident
54
+ Is Sorter-02 operational?,system_status
55
+ How does goods-to-person picking work?,general_faq
56
+ Report unsafe pallet stacking in Zone A,safety_incident
57
+ Suggest a wave picking plan for Zone C,picking_optimization
58
+ Has order #81590 shipped yet?,order_status
59
+ Show the fulfillment status of #97907,order_status
60
+ What's the difference between AGV and AMR?,general_faq
61
+ Why hasn't order #64070 left the dock yet?,order_status
62
+ What's the difference between AGV and AMR?,general_faq
63
+ What's the fastest picking route for order #53089?,picking_optimization
64
+ Show the fulfillment status of #96188,order_status
65
+ Schedule maintenance for AMR-21,equipment_maintenance
66
+ Redirect Crane-03 around the blocked aisle in Zone D,agv_navigation
67
+ Report unsafe pallet stacking in the receiving dock,safety_incident
68
+ Report unsafe pallet stacking in Zone D,safety_incident
69
+ What's the status of order #77199?,order_status
70
+ What's the status of order #42868?,order_status
71
+ What is the current location of Sorter-02?,agv_navigation
72
+ "A worker slipped near Crane-03, please log it",safety_incident
73
+ Track order #80047 for me,order_status
74
+ Route Conveyor-14 to picking station 7,agv_navigation
75
+ "Belt AGV-12 stopped unexpectedly, please check",equipment_maintenance
76
+ AGV-12 motor temperature seems high,equipment_maintenance
77
+ Crane Crane-05 reported a fault code,equipment_maintenance
78
+ Suggest a wave picking plan for Zone A,picking_optimization
79
+ Explain how an AS/RS works,general_faq
80
+ A forklift near-miss was reported in Zone D,safety_incident
81
+ Is order #13773 delayed?,order_status
82
+ How do sortation systems decide where to route a parcel?,general_faq
83
+ Give me stock levels across all zones for SKU-9745,inventory_check
84
+ The sorter in Zone D keeps jamming,equipment_maintenance
85
+ Explain how an AS/RS works,general_faq
86
+ Check inventory count for SKU-4142 in Zone D,inventory_check
87
+ There was a near collision between Crane-05 and a pedestrian in Zone D,safety_incident
88
+ A forklift near-miss was reported in the mezzanine,safety_incident
89
+ How many units of SKU-5262 are in Zone D?,inventory_check
90
+ Report unsafe pallet stacking in the receiving dock,safety_incident
91
+ Reassign Sorter-02 to charging station,agv_navigation
92
+ What KPIs matter most in warehouse automation?,general_faq
93
+ Redirect AGV-12 around the blocked aisle in Zone A,agv_navigation
94
+ Route AGV-12 to picking station 3,agv_navigation
95
+ Check system health for the receiving dock,system_status
96
+ Show me the on-hand quantity of SKU-3984,inventory_check
97
+ Check system health for Zone A,system_status
98
+ Crane AMR-21 reported a fault code,equipment_maintenance
99
+ Redirect AMR-21 around the blocked aisle in the mezzanine,agv_navigation
100
+ What KPIs matter most in warehouse automation?,general_faq
101
+ Check inventory count for SKU-5358 in Zone C,inventory_check
102
+ Is the sorter in Zone A running normally?,system_status
103
+ What is the uptime for Conveyor-14 today?,system_status
104
+ Crane AGV-12 reported a fault code,equipment_maintenance
105
+ What is predictive maintenance?,general_faq
106
+ Redirect AMR-21 around the blocked aisle in Zone B,agv_navigation
107
+ Reassign Crane-05 to charging station,agv_navigation
108
+ How do sortation systems decide where to route a parcel?,general_faq
109
+ Give me stock levels across all zones for SKU-9349,inventory_check
110
+ What KPIs matter most in warehouse automation?,general_faq
111
+ Do we have enough SKU-1634 to fulfill 200 units?,inventory_check
112
+ Schedule maintenance for Conveyor-14,equipment_maintenance
113
+ Is AGV-07 operational?,system_status
114
+ Crane Conveyor-14 reported a fault code,equipment_maintenance
115
+ What is predictive maintenance?,general_faq
116
+ What's the difference between AGV and AMR?,general_faq
117
+ What is the current stock level for SKU-4153?,inventory_check
118
+ Report vibration issue on Sorter-02,equipment_maintenance
119
+ How can we reduce travel time for pickers in Zone B?,picking_optimization
120
+ Is Crane-05 operational?,system_status
121
+ Give me stock levels across all zones for SKU-2069,inventory_check
122
+ Show me the on-hand quantity of SKU-9500,inventory_check
123
+ Track order #76329 for me,order_status
124
+ Is Crane-05 operational?,system_status
125
+ Show the fulfillment status of #13780,order_status
126
+ Show me the on-hand quantity of SKU-3324,inventory_check
127
+ Why hasn't order #89759 left the dock yet?,order_status
128
+ Report vibration issue on AMR-21,equipment_maintenance
129
+ File an incident report for Zone B,safety_incident
130
+ How does goods-to-person picking work?,general_faq
131
+ What is predictive maintenance?,general_faq
132
+ Show the fulfillment status of #56924,order_status
133
+ Report unsafe pallet stacking in the receiving dock,safety_incident
134
+ Redirect AMR-21 around the blocked aisle in the mezzanine,agv_navigation
135
+ Is SKU-5796 in stock at Zone B?,inventory_check
136
+ Why is Conveyor-14 stuck near the receiving dock?,agv_navigation
137
+ How can we reduce travel time for pickers in Zone A?,picking_optimization
138
+ What is the uptime for Sorter-02 today?,system_status
139
+ Do we have enough SKU-6931 to fulfill 200 units?,inventory_check
140
+ What's the status of order #64054?,order_status
141
+ How much inventory is left for SKU-9186?,inventory_check
142
+ Check inventory count for SKU-6138 in Zone C,inventory_check
143
+ What KPIs matter most in warehouse automation?,general_faq
144
+ Is Crane-05 operational?,system_status
145
+ How many units of SKU-7673 are in Zone A?,inventory_check
146
+ What KPIs matter most in warehouse automation?,general_faq
147
+ Is order #42664 delayed?,order_status
148
+ Track order #32774 for me,order_status
149
+ Report unsafe pallet stacking in Zone B,safety_incident
150
+ How can we reduce travel time for pickers in Zone D?,picking_optimization
151
+ Check inventory count for SKU-5130 in the receiving dock,inventory_check
152
+ Report unsafe pallet stacking in Zone C,safety_incident
153
+ What is the current location of Crane-05?,agv_navigation
154
+ Give me stock levels across all zones for SKU-8391,inventory_check
155
+ Is SKU-1561 in stock at Zone C?,inventory_check
156
+ What is predictive maintenance?,general_faq
157
+ Is order #63615 delayed?,order_status
158
+ How many units of SKU-1334 are in the mezzanine?,inventory_check
159
+ Schedule maintenance for AGV-12,equipment_maintenance
160
+ What KPIs matter most in warehouse automation?,general_faq
161
+ Is order #48757 delayed?,order_status
162
+ Show the fulfillment status of #97109,order_status
163
+ Should we batch pick these orders together?,picking_optimization
164
+ How do sortation systems decide where to route a parcel?,general_faq
165
+ The sorter in the mezzanine keeps jamming,equipment_maintenance
166
+ File an incident report for the mezzanine,safety_incident
167
+ Give me the current status of the WMS integration,system_status
168
+ What's the fastest picking route for order #64066?,picking_optimization
169
+ How can we reduce travel time for pickers in Zone D?,picking_optimization
170
+ Why is Sorter-02 stuck near the receiving dock?,agv_navigation
171
+ What is predictive maintenance?,general_faq
172
+ Report vibration issue on Conveyor-14,equipment_maintenance
173
+ File an incident report for the receiving dock,safety_incident
174
+ Has order #45389 shipped yet?,order_status
175
+ Redirect AMR-21 around the blocked aisle in Zone D,agv_navigation
176
+ Schedule maintenance for AMR-21,equipment_maintenance
177
+ What is the uptime for Sorter-02 today?,system_status
178
+ Send AGV AMR-21 to Zone D,agv_navigation
179
+ Route AGV-12 to picking station 7,agv_navigation
180
+ Has order #47696 shipped yet?,order_status
181
+ Reassign Conveyor-14 to charging station,agv_navigation
182
+ The sorter in Zone D keeps jamming,equipment_maintenance
183
+ Should we batch pick these orders together?,picking_optimization
184
+ "Belt AGV-07 stopped unexpectedly, please check",equipment_maintenance
185
+ Give me the current status of the WMS integration,system_status
186
+ Are all cranes online in Zone C?,system_status
187
+ Track order #70623 for me,order_status
188
+ Check system health for the mezzanine,system_status
189
+ Report vibration issue on AMR-21,equipment_maintenance
190
+ "A worker slipped near Crane-03, please log it",safety_incident
191
+ Route Conveyor-14 to picking station 7,agv_navigation
192
+ When will order #30254 be delivered?,order_status
193
+ Suggest a wave picking plan for Zone A,picking_optimization
194
+ What is the uptime for Conveyor-14 today?,system_status
195
+ Route AGV-12 to picking station 7,agv_navigation
196
+ Is order #82154 delayed?,order_status
197
+ Suggest a wave picking plan for Zone A,picking_optimization
198
+ Check system health for the receiving dock,system_status
199
+ How do sortation systems decide where to route a parcel?,general_faq
200
+ Log a safety incident involving AMR-21,safety_incident
201
+ Should we batch pick these orders together?,picking_optimization
202
+ A forklift near-miss was reported in Zone A,safety_incident
203
+ What is the uptime for Sorter-02 today?,system_status
204
+ Is Conveyor-14 operational?,system_status
205
+ Are all cranes online in the mezzanine?,system_status
206
+ Do we have enough SKU-5966 to fulfill 200 units?,inventory_check
207
+ Why is Conveyor-14 stuck near the receiving dock?,agv_navigation
208
+ Log a breakdown for Conveyor-14 in Zone A,equipment_maintenance
209
+ File an incident report for Zone D,safety_incident
210
+ Why is AGV-12 stuck near Zone A?,agv_navigation
211
+ Recommend a picking strategy for high-velocity SKUs,picking_optimization
212
+ Should we batch pick these orders together?,picking_optimization
213
+ Show me the on-hand quantity of SKU-8952,inventory_check
214
+ Has order #57335 shipped yet?,order_status
215
+ Redirect Conveyor-14 around the blocked aisle in Zone C,agv_navigation
216
+ Is AMR-21 operational?,system_status
217
+ How many units of SKU-5103 are in Zone B?,inventory_check
218
+ "A worker slipped near AGV-07, please log it",safety_incident
219
+ A forklift near-miss was reported in Zone D,safety_incident
220
+ "Belt Conveyor-14 stopped unexpectedly, please check",equipment_maintenance
221
+ Log a breakdown for AGV-07 in Zone D,equipment_maintenance
222
+ Crane AMR-21 reported a fault code,equipment_maintenance
223
+ Is Conveyor-14 operational?,system_status
224
+ Why is Crane-05 stuck near Zone B?,agv_navigation
225
+ What's the fastest picking route for order #31767?,picking_optimization
226
+ Show me the on-hand quantity of SKU-4409,inventory_check
227
+ Is the sorter in Zone D running normally?,system_status
228
+ When will order #56214 be delivered?,order_status
229
+ When will order #45136 be delivered?,order_status
230
+ How many units of SKU-1334 are in Zone A?,inventory_check
231
+ What is the uptime for Crane-03 today?,system_status
232
+ The conveyor belt in the mezzanine is making noise,equipment_maintenance
233
+ What is predictive maintenance?,general_faq
234
+ Recommend a picking strategy for high-velocity SKUs,picking_optimization
235
+ Reassign Conveyor-14 to charging station,agv_navigation
236
+ Optimize the pick path for Zone B,picking_optimization
237
+ A forklift near-miss was reported in Zone C,safety_incident
238
+ How does goods-to-person picking work?,general_faq
239
+ Reassign AGV-07 to charging station,agv_navigation
240
+ Track order #71532 for me,order_status
241
+ Crane-03 motor temperature seems high,equipment_maintenance
242
+ The sorter in Zone D keeps jamming,equipment_maintenance
243
+ Should we batch pick these orders together?,picking_optimization
244
+ Crane AGV-12 reported a fault code,equipment_maintenance
245
+ What is the current stock level for SKU-5995?,inventory_check
246
+ What's the status of order #14451?,order_status
247
+ Check system health for the mezzanine,system_status
248
+ Show the fulfillment status of #98725,order_status
249
+ What's the difference between AGV and AMR?,general_faq
250
+ The sorter in the mezzanine keeps jamming,equipment_maintenance
251
+ File an incident report for the mezzanine,safety_incident
252
+ What's the status of order #57944?,order_status
253
+ Log a breakdown for Crane-05 in Zone C,equipment_maintenance
254
+ Send AGV Conveyor-14 to Zone D,agv_navigation
255
+ Is AMR-21 operational?,system_status
256
+ Are all cranes online in Zone A?,system_status
257
+ Should we batch pick these orders together?,picking_optimization
258
+ When will order #96195 be delivered?,order_status
259
+ What is the uptime for Crane-05 today?,system_status
260
+ Report vibration issue on Crane-03,equipment_maintenance
261
+ Reassign Crane-05 to charging station,agv_navigation
262
+ Redirect Crane-05 around the blocked aisle in the mezzanine,agv_navigation
263
+ Suggest a wave picking plan for Zone A,picking_optimization
264
+ What's the fastest picking route for order #40691?,picking_optimization
265
+ How can we reduce travel time for pickers in the receiving dock?,picking_optimization
266
+ "A worker slipped near Crane-05, please log it",safety_incident
267
+ How can we reduce travel time for pickers in the receiving dock?,picking_optimization
268
+ What is the uptime for Crane-03 today?,system_status
269
+ What is a WMS?,general_faq
270
+ Schedule maintenance for Sorter-02,equipment_maintenance
271
+ Recommend a picking strategy for high-velocity SKUs,picking_optimization
272
+ Send AGV AGV-07 to the mezzanine,agv_navigation
273
+ What is the uptime for Conveyor-14 today?,system_status
274
+ Why is Sorter-02 stuck near the mezzanine?,agv_navigation
275
+ Report vibration issue on Sorter-02,equipment_maintenance
276
+ Is the sorter in Zone C running normally?,system_status
277
+ Recommend a picking strategy for high-velocity SKUs,picking_optimization
278
+ File an incident report for Zone C,safety_incident
279
+ What's the difference between AGV and AMR?,general_faq
280
+ Optimize the pick path for the receiving dock,picking_optimization
281
+ Log a safety incident involving Crane-03,safety_incident
282
+ What KPIs matter most in warehouse automation?,general_faq
283
+ A forklift near-miss was reported in Zone C,safety_incident
284
+ What KPIs matter most in warehouse automation?,general_faq
285
+ Is order #50038 delayed?,order_status
286
+ Crane Crane-03 reported a fault code,equipment_maintenance
287
+ Suggest a wave picking plan for Zone C,picking_optimization
288
+ A forklift near-miss was reported in Zone B,safety_incident
289
+ "A worker slipped near Crane-05, please log it",safety_incident
290
+ How do sortation systems decide where to route a parcel?,general_faq
291
+ File an incident report for Zone D,safety_incident
292
+ Reassign Sorter-02 to charging station,agv_navigation
293
+ Are all cranes online in the mezzanine?,system_status
294
+ Log a breakdown for AMR-21 in Zone A,equipment_maintenance
295
+ "Belt Sorter-02 stopped unexpectedly, please check",equipment_maintenance
296
+ Reassign Conveyor-14 to charging station,agv_navigation
297
+ Suggest a wave picking plan for Zone D,picking_optimization
298
+ What is the current location of Crane-05?,agv_navigation
299
+ What's the status of order #64365?,order_status
300
+ The conveyor belt in the receiving dock is making noise,equipment_maintenance
301
+ A forklift near-miss was reported in Zone C,safety_incident
302
+ Route Sorter-02 to picking station 12,agv_navigation
303
+ Is the sorter in the receiving dock running normally?,system_status
304
+ A forklift near-miss was reported in Zone A,safety_incident
305
+ "Belt Crane-05 stopped unexpectedly, please check",equipment_maintenance
306
+ Should we batch pick these orders together?,picking_optimization
307
+ Are all cranes online in Zone A?,system_status
308
+ Track order #93256 for me,order_status
309
+ A forklift near-miss was reported in the receiving dock,safety_incident
310
+ Report unsafe pallet stacking in the receiving dock,safety_incident
311
+ AGV-12 motor temperature seems high,equipment_maintenance
312
+ Is Sorter-02 operational?,system_status
313
+ Show me the on-hand quantity of SKU-4925,inventory_check
314
+ What KPIs matter most in warehouse automation?,general_faq
315
+ Is order #93706 delayed?,order_status
316
+ Suggest a wave picking plan for Zone B,picking_optimization
317
+ When will order #46154 be delivered?,order_status
318
+ Should we batch pick these orders together?,picking_optimization
319
+ What is the current location of AMR-21?,agv_navigation
320
+ Crane Sorter-02 reported a fault code,equipment_maintenance
321
+ Is SKU-5535 in stock at the mezzanine?,inventory_check
322
+ Check inventory count for SKU-7601 in the mezzanine,inventory_check
323
+ What is the current stock level for SKU-9473?,inventory_check
324
+ Report vibration issue on Conveyor-14,equipment_maintenance
325
+ Log a breakdown for AMR-21 in Zone B,equipment_maintenance
326
+ Is the sorter in Zone A running normally?,system_status
327
+ What is a WMS?,general_faq
328
+ Send AGV AGV-12 to the receiving dock,agv_navigation
329
+ When will order #51499 be delivered?,order_status
330
+ How much inventory is left for SKU-5685?,inventory_check
331
+ Should we batch pick these orders together?,picking_optimization
332
+ Give me the current status of the WMS integration,system_status
333
+ What is the uptime for AGV-07 today?,system_status
334
+ The conveyor belt in Zone D is making noise,equipment_maintenance
335
+ Check inventory count for SKU-6560 in Zone B,inventory_check
336
+ Give me the current status of the WMS integration,system_status
337
+ Why is Crane-03 stuck near Zone B?,agv_navigation
338
+ What's the fastest picking route for order #50161?,picking_optimization
339
+ Recommend a picking strategy for high-velocity SKUs,picking_optimization
340
+ Check system health for the mezzanine,system_status
341
+ How many units of SKU-7260 are in the mezzanine?,inventory_check
342
+ What's the fastest picking route for order #20834?,picking_optimization
343
+ What KPIs matter most in warehouse automation?,general_faq
344
+ Why hasn't order #23806 left the dock yet?,order_status
345
+ Redirect AMR-21 around the blocked aisle in Zone C,agv_navigation
346
+ Is the sorter in Zone A running normally?,system_status
347
+ Route Sorter-02 to picking station 12,agv_navigation
348
+ Schedule maintenance for AGV-07,equipment_maintenance
349
+ When will order #41787 be delivered?,order_status
350
+ Recommend a picking strategy for high-velocity SKUs,picking_optimization
351
+ Send AGV Crane-05 to Zone B,agv_navigation
352
+ Show the fulfillment status of #24126,order_status
353
+ How many units of SKU-4902 are in the mezzanine?,inventory_check
354
+ What is the current stock level for SKU-9081?,inventory_check
355
+ Recommend a picking strategy for high-velocity SKUs,picking_optimization
356
+ "A worker slipped near AMR-21, please log it",safety_incident
357
+ Why is AGV-12 stuck near Zone C?,agv_navigation
358
+ What KPIs matter most in warehouse automation?,general_faq
359
+ Do we have enough SKU-4509 to fulfill 200 units?,inventory_check
360
+ Check system health for Zone C,system_status
361
+ Redirect Crane-03 around the blocked aisle in Zone B,agv_navigation
362
+ Optimize the pick path for the mezzanine,picking_optimization
363
+ Optimize the pick path for Zone B,picking_optimization
364
+ Report vibration issue on Crane-05,equipment_maintenance
365
+ What is the uptime for AGV-12 today?,system_status
366
+ Crane AGV-12 reported a fault code,equipment_maintenance
367
+ What's the status of order #61814?,order_status
368
+ Log a breakdown for AMR-21 in Zone D,equipment_maintenance
369
+ The sorter in Zone C keeps jamming,equipment_maintenance
370
+ What is predictive maintenance?,general_faq
371
+ Is SKU-6807 in stock at Zone A?,inventory_check
372
+ File an incident report for Zone D,safety_incident
373
+ What is cycle counting?,general_faq
374
+ What's the status of order #96570?,order_status
375
+ There was a near collision between Conveyor-14 and a pedestrian in Zone A,safety_incident
376
+ What is the current stock level for SKU-4089?,inventory_check
377
+ Report vibration issue on AMR-21,equipment_maintenance
378
+ What is the current stock level for SKU-6220?,inventory_check
379
+ Explain how an AS/RS works,general_faq
380
+ Give me the current status of the WMS integration,system_status
381
+ Route AGV-07 to picking station 12,agv_navigation
382
+ How can we reduce travel time for pickers in Zone A?,picking_optimization
383
+ Give me the current status of the WMS integration,system_status
384
+ What KPIs matter most in warehouse automation?,general_faq
385
+ "A worker slipped near AGV-07, please log it",safety_incident
386
+ Reassign Crane-03 to charging station,agv_navigation
387
+ Redirect AGV-12 around the blocked aisle in the mezzanine,agv_navigation
388
+ Send AGV Crane-03 to Zone A,agv_navigation
389
+ Recommend a picking strategy for high-velocity SKUs,picking_optimization
390
+ What KPIs matter most in warehouse automation?,general_faq
391
+ What's the fastest picking route for order #13894?,picking_optimization
392
+ What's the difference between AGV and AMR?,general_faq
393
+ What's the difference between AGV and AMR?,general_faq
394
+ Log a safety incident involving AGV-12,safety_incident
395
+ File an incident report for the receiving dock,safety_incident
396
+ Recommend a picking strategy for high-velocity SKUs,picking_optimization
397
+ Redirect Crane-03 around the blocked aisle in Zone B,agv_navigation
398
+ "Belt AGV-12 stopped unexpectedly, please check",equipment_maintenance
399
+ Do we have enough SKU-9027 to fulfill 200 units?,inventory_check
400
+ What is the current location of Crane-05?,agv_navigation
401
+ What is the current location of Conveyor-14?,agv_navigation
402
+ Log a safety incident involving Crane-05,safety_incident
403
+ Suggest a wave picking plan for the mezzanine,picking_optimization
404
+ Is order #53968 delayed?,order_status
405
+ Give me stock levels across all zones for SKU-2884,inventory_check
406
+ Give me the current status of the WMS integration,system_status
407
+ Do we have enough SKU-2736 to fulfill 200 units?,inventory_check
408
+ Explain how an AS/RS works,general_faq
409
+ Explain how an AS/RS works,general_faq
410
+ Do we have enough SKU-1311 to fulfill 200 units?,inventory_check
411
+ When will order #64734 be delivered?,order_status
412
+ Route Crane-03 to picking station 5,agv_navigation
413
+ Check inventory count for SKU-3109 in Zone D,inventory_check
414
+ Should we batch pick these orders together?,picking_optimization
415
+ Is the sorter in Zone A running normally?,system_status
416
+ When will order #30168 be delivered?,order_status
417
+ There was a near collision between Crane-05 and a pedestrian in Zone B,safety_incident
418
+ How does goods-to-person picking work?,general_faq
419
+ How much inventory is left for SKU-6985?,inventory_check
420
+ "A worker slipped near AMR-21, please log it",safety_incident
421
+ Optimize the pick path for Zone D,picking_optimization
422
+ Recommend a picking strategy for high-velocity SKUs,picking_optimization
423
+ How many units of SKU-7468 are in the receiving dock?,inventory_check
424
+ "A worker slipped near AGV-07, please log it",safety_incident
425
+ Show the fulfillment status of #41997,order_status
426
+ Check system health for Zone D,system_status
427
+ What's the fastest picking route for order #44568?,picking_optimization
428
+ The conveyor belt in Zone A is making noise,equipment_maintenance
429
+ File an incident report for the receiving dock,safety_incident
430
+ What is predictive maintenance?,general_faq
431
+ The conveyor belt in Zone B is making noise,equipment_maintenance
432
+ There was a near collision between AGV-07 and a pedestrian in Zone D,safety_incident
433
+ How do sortation systems decide where to route a parcel?,general_faq
434
+ A forklift near-miss was reported in the receiving dock,safety_incident
435
+ Recommend a picking strategy for high-velocity SKUs,picking_optimization
436
+ Give me stock levels across all zones for SKU-4496,inventory_check
437
+ Is AGV-07 operational?,system_status
438
+ What is the current stock level for SKU-7977?,inventory_check
439
+ AMR-21 motor temperature seems high,equipment_maintenance
440
+ Why is Crane-03 stuck near Zone C?,agv_navigation
441
+ What's the difference between AGV and AMR?,general_faq
442
+ Why is Sorter-02 stuck near Zone A?,agv_navigation
443
+ AMR-21 motor temperature seems high,equipment_maintenance
444
+ How much inventory is left for SKU-3540?,inventory_check
445
+ Do we have enough SKU-9249 to fulfill 200 units?,inventory_check
446
+ There was a near collision between AGV-12 and a pedestrian in Zone A,safety_incident
447
+ Reassign Conveyor-14 to charging station,agv_navigation
448
+ Should we batch pick these orders together?,picking_optimization
449
+ Do we have enough SKU-8501 to fulfill 200 units?,inventory_check
450
+ File an incident report for Zone A,safety_incident
451
+ Log a breakdown for AGV-07 in Zone B,equipment_maintenance
452
+ Recommend a picking strategy for high-velocity SKUs,picking_optimization
453
+ How do sortation systems decide where to route a parcel?,general_faq
454
+ Route AMR-21 to picking station 12,agv_navigation
455
+ Is the sorter in Zone D running normally?,system_status
456
+ Should we batch pick these orders together?,picking_optimization
457
+ Is the sorter in the mezzanine running normally?,system_status
458
+ "A worker slipped near AGV-07, please log it",safety_incident
459
+ Suggest a wave picking plan for the receiving dock,picking_optimization
460
+ There was a near collision between Sorter-02 and a pedestrian in the receiving dock,safety_incident
461
+ Crane Sorter-02 reported a fault code,equipment_maintenance
462
+ Sorter-02 motor temperature seems high,equipment_maintenance
463
+ "Belt Crane-05 stopped unexpectedly, please check",equipment_maintenance
464
+ There was a near collision between Sorter-02 and a pedestrian in Zone D,safety_incident
465
+ Has order #94021 shipped yet?,order_status
466
+ Is Conveyor-14 operational?,system_status
467
+ Has order #91192 shipped yet?,order_status
468
+ What is a WMS?,general_faq
469
+ Report unsafe pallet stacking in Zone C,safety_incident
470
+ Route AMR-21 to picking station 3,agv_navigation
471
+ How do sortation systems decide where to route a parcel?,general_faq
472
+ Sorter-02 motor temperature seems high,equipment_maintenance
473
+ What is a WMS?,general_faq
474
+ Do we have enough SKU-1853 to fulfill 200 units?,inventory_check
475
+ Send AGV AGV-12 to Zone D,agv_navigation
476
+ What's the status of order #75717?,order_status
477
+ Why hasn't order #64929 left the dock yet?,order_status
478
+ Suggest a wave picking plan for the receiving dock,picking_optimization
479
+ "A worker slipped near Conveyor-14, please log it",safety_incident
480
+ What's the difference between AGV and AMR?,general_faq
481
+ Track order #86085 for me,order_status
data/intent_eval.json ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "accuracy": 0.9916666666666667,
3
+ "macro_f1": 0.9916573971078977,
4
+ "n_train": 360,
5
+ "n_test": 120,
6
+ "n_classes": 8,
7
+ "classes": [
8
+ "agv_navigation",
9
+ "equipment_maintenance",
10
+ "general_faq",
11
+ "inventory_check",
12
+ "order_status",
13
+ "picking_optimization",
14
+ "safety_incident",
15
+ "system_status"
16
+ ],
17
+ "classification_report": {
18
+ "agv_navigation": {
19
+ "precision": 1.0,
20
+ "recall": 1.0,
21
+ "f1-score": 1.0,
22
+ "support": 15.0
23
+ },
24
+ "equipment_maintenance": {
25
+ "precision": 1.0,
26
+ "recall": 1.0,
27
+ "f1-score": 1.0,
28
+ "support": 15.0
29
+ },
30
+ "general_faq": {
31
+ "precision": 1.0,
32
+ "recall": 0.9333333333333333,
33
+ "f1-score": 0.9655172413793104,
34
+ "support": 15.0
35
+ },
36
+ "inventory_check": {
37
+ "precision": 1.0,
38
+ "recall": 1.0,
39
+ "f1-score": 1.0,
40
+ "support": 15.0
41
+ },
42
+ "order_status": {
43
+ "precision": 0.9375,
44
+ "recall": 1.0,
45
+ "f1-score": 0.967741935483871,
46
+ "support": 15.0
47
+ },
48
+ "picking_optimization": {
49
+ "precision": 1.0,
50
+ "recall": 1.0,
51
+ "f1-score": 1.0,
52
+ "support": 15.0
53
+ },
54
+ "safety_incident": {
55
+ "precision": 1.0,
56
+ "recall": 1.0,
57
+ "f1-score": 1.0,
58
+ "support": 15.0
59
+ },
60
+ "system_status": {
61
+ "precision": 1.0,
62
+ "recall": 1.0,
63
+ "f1-score": 1.0,
64
+ "support": 15.0
65
+ },
66
+ "accuracy": 0.9916666666666667,
67
+ "macro avg": {
68
+ "precision": 0.9921875,
69
+ "recall": 0.9916666666666667,
70
+ "f1-score": 0.9916573971078977,
71
+ "support": 120.0
72
+ },
73
+ "weighted avg": {
74
+ "precision": 0.9921875,
75
+ "recall": 0.9916666666666667,
76
+ "f1-score": 0.9916573971078978,
77
+ "support": 120.0
78
+ }
79
+ }
80
+ }
data/inventory.csv ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ sku,description,category,zone,on_hand_units,reorder_point,unit_cost_jpy
2
+ SKU-1000,Electronics item 1000,Food & Beverage,Zone C,877,158,12907
3
+ SKU-1001,Electronics item 1001,Food & Beverage,Zone A,188,181,14639
4
+ SKU-1002,Food & Beverage item 1002,Food & Beverage,Zone C,1572,178,2096
5
+ SKU-1003,Household item 1003,Automotive Parts,Zone C,741,95,13916
6
+ SKU-1004,Food & Beverage item 1004,Food & Beverage,Zone B,1645,186,6762
7
+ SKU-1005,Automotive Parts item 1005,Apparel,Zone A,1109,271,1144
8
+ SKU-1006,Household item 1006,Household,Zone B,1263,91,11419
9
+ SKU-1007,Food & Beverage item 1007,Apparel,Zone A,1941,161,13418
10
+ SKU-1008,Food & Beverage item 1008,Food & Beverage,Zone D,389,140,7107
11
+ SKU-1009,Automotive Parts item 1009,Electronics,Zone C,308,235,10309
12
+ SKU-1010,Household item 1010,Food & Beverage,Zone B,1935,152,5022
13
+ SKU-1011,Household item 1011,Apparel,Zone A,939,248,3004
14
+ SKU-1012,Automotive Parts item 1012,Electronics,Zone C,951,132,3558
15
+ SKU-1013,Automotive Parts item 1013,Food & Beverage,Zone D,874,90,12523
16
+ SKU-1014,Food & Beverage item 1014,Food & Beverage,Zone A,624,241,12517
17
+ SKU-1015,Automotive Parts item 1015,Household,Zone D,774,274,4467
18
+ SKU-1016,Apparel item 1016,Food & Beverage,Zone C,279,258,3158
19
+ SKU-1017,Household item 1017,Electronics,Zone D,1573,245,10039
20
+ SKU-1018,Automotive Parts item 1018,Food & Beverage,Zone B,1561,188,6991
21
+ SKU-1019,Automotive Parts item 1019,Automotive Parts,Zone A,279,111,1895
22
+ SKU-1020,Automotive Parts item 1020,Food & Beverage,Zone C,942,263,8565
23
+ SKU-1021,Electronics item 1021,Food & Beverage,Zone C,1269,191,8392
24
+ SKU-1022,Electronics item 1022,Automotive Parts,Zone D,607,200,656
25
+ SKU-1023,Apparel item 1023,Automotive Parts,Zone D,429,119,6246
26
+ SKU-1024,Household item 1024,Household,Zone A,467,255,1062
27
+ SKU-1025,Household item 1025,Apparel,Zone D,587,158,9996
28
+ SKU-1026,Electronics item 1026,Automotive Parts,Zone C,1567,299,10031
29
+ SKU-1027,Automotive Parts item 1027,Automotive Parts,Zone B,1628,130,2671
30
+ SKU-1028,Apparel item 1028,Electronics,Zone A,180,242,10890
31
+ SKU-1029,Food & Beverage item 1029,Automotive Parts,Zone C,322,275,7615
32
+ SKU-1030,Household item 1030,Electronics,Zone B,1392,173,6803
33
+ SKU-1031,Electronics item 1031,Apparel,Zone A,603,220,9528
34
+ SKU-1032,Food & Beverage item 1032,Apparel,Zone D,175,135,1946
35
+ SKU-1033,Apparel item 1033,Household,Zone B,1817,173,10555
36
+ SKU-1034,Automotive Parts item 1034,Apparel,Zone D,1938,115,11725
37
+ SKU-1035,Apparel item 1035,Food & Beverage,Zone D,898,234,4229
38
+ SKU-1036,Electronics item 1036,Electronics,Zone B,1805,81,6945
39
+ SKU-1037,Food & Beverage item 1037,Apparel,Zone C,611,252,8772
40
+ SKU-1038,Automotive Parts item 1038,Electronics,Zone B,1713,54,11426
41
+ SKU-1039,Automotive Parts item 1039,Food & Beverage,Zone C,864,127,9484
42
+ SKU-1040,Electronics item 1040,Automotive Parts,Zone A,1299,207,1449
43
+ SKU-1041,Food & Beverage item 1041,Automotive Parts,Zone D,83,94,7511
44
+ SKU-1042,Electronics item 1042,Apparel,Zone C,289,219,1730
45
+ SKU-1043,Electronics item 1043,Automotive Parts,Zone D,341,124,13891
46
+ SKU-1044,Household item 1044,Automotive Parts,Zone B,693,203,8945
47
+ SKU-1045,Apparel item 1045,Electronics,Zone A,1917,154,7338
48
+ SKU-1046,Automotive Parts item 1046,Food & Beverage,Zone A,165,118,7402
49
+ SKU-1047,Food & Beverage item 1047,Automotive Parts,Zone B,1875,90,8661
50
+ SKU-1048,Automotive Parts item 1048,Automotive Parts,Zone D,533,288,5107
51
+ SKU-1049,Automotive Parts item 1049,Automotive Parts,Zone D,877,121,519
52
+ SKU-1050,Apparel item 1050,Household,Zone A,1792,185,2275
53
+ SKU-1051,Apparel item 1051,Automotive Parts,Zone B,217,216,10149
54
+ SKU-1052,Electronics item 1052,Apparel,Zone A,1318,232,10959
55
+ SKU-1053,Household item 1053,Food & Beverage,Zone B,215,203,13756
56
+ SKU-1054,Household item 1054,Apparel,Zone A,74,85,8411
57
+ SKU-1055,Automotive Parts item 1055,Apparel,Zone B,1659,165,12162
58
+ SKU-1056,Household item 1056,Apparel,Zone A,1905,208,4505
59
+ SKU-1057,Food & Beverage item 1057,Automotive Parts,Zone D,511,297,14053
60
+ SKU-1058,Electronics item 1058,Electronics,Zone C,89,124,6639
61
+ SKU-1059,Household item 1059,Household,Zone A,1783,72,11279
data/latency_eval.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {
2
+ "intent_classifier_ms": 0.398,
3
+ "anomaly_detector_ms": 22.722,
4
+ "kb_retrieval_ms": 0.561,
5
+ "note": "LLM generation latency depends on the external Inference API call and is measured live in the app, not benchmarked here."
6
+ }
data/orders.csv ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ order_id,status,num_lines,priority,zone
2
+ #10000,Shipped,16,Express,Zone B
3
+ #10001,Shipped,5,Same-Day,Zone A
4
+ #10002,Shipped,18,Standard,Zone D
5
+ #10003,Packed,13,Same-Day,Zone B
6
+ #10004,Shipped,10,Standard,Zone D
7
+ #10005,Picking,3,Standard,Zone C
8
+ #10006,Shipped,7,Express,Zone C
9
+ #10007,Picking,2,Express,Zone D
10
+ #10008,Shipped,19,Standard,Zone A
11
+ #10009,Received,14,Express,Zone A
12
+ #10010,Shipped,9,Standard,Zone D
13
+ #10011,Picking,2,Standard,Zone B
14
+ #10012,Received,17,Standard,Zone B
15
+ #10013,Shipped,23,Express,Zone B
16
+ #10014,Shipped,3,Express,Zone B
17
+ #10015,Shipped,21,Standard,Zone B
18
+ #10016,Shipped,16,Standard,Zone A
19
+ #10017,Received,20,Express,Zone D
20
+ #10018,Shipped,7,Standard,Zone D
21
+ #10019,Packed,1,Standard,Zone A
22
+ #10020,Shipped,16,Standard,Zone B
23
+ #10021,Shipped,14,Standard,Zone C
24
+ #10022,Packed,20,Standard,Zone B
25
+ #10023,Packed,24,Standard,Zone A
26
+ #10024,Shipped,1,Standard,Zone A
27
+ #10025,Picking,23,Express,Zone B
28
+ #10026,Packed,13,Express,Zone D
29
+ #10027,Packed,11,Standard,Zone D
30
+ #10028,Received,3,Express,Zone A
31
+ #10029,Packed,18,Standard,Zone A
32
+ #10030,Picking,12,Standard,Zone C
33
+ #10031,Picking,6,Express,Zone B
34
+ #10032,Picking,24,Standard,Zone A
35
+ #10033,Delayed,9,Express,Zone D
36
+ #10034,Picking,19,Express,Zone D
37
+ #10035,Shipped,19,Standard,Zone B
38
+ #10036,Received,11,Standard,Zone D
39
+ #10037,Picking,18,Standard,Zone B
40
+ #10038,Picking,12,Express,Zone D
41
+ #10039,Shipped,16,Express,Zone B
42
+ #10040,Packed,3,Standard,Zone C
43
+ #10041,Packed,19,Standard,Zone A
44
+ #10042,Picking,16,Standard,Zone A
45
+ #10043,Packed,20,Same-Day,Zone A
46
+ #10044,Packed,11,Standard,Zone B
47
+ #10045,Received,4,Standard,Zone D
48
+ #10046,Shipped,2,Standard,Zone A
49
+ #10047,Packed,11,Standard,Zone D
50
+ #10048,Packed,20,Standard,Zone B
51
+ #10049,Packed,21,Standard,Zone B
52
+ #10050,Shipped,1,Standard,Zone D
53
+ #10051,Packed,8,Express,Zone A
54
+ #10052,Picking,6,Express,Zone C
55
+ #10053,Shipped,8,Same-Day,Zone A
56
+ #10054,Picking,6,Standard,Zone A
57
+ #10055,Picking,8,Express,Zone D
58
+ #10056,Picking,5,Standard,Zone D
59
+ #10057,Packed,22,Same-Day,Zone B
60
+ #10058,Picking,13,Standard,Zone A
61
+ #10059,Delayed,4,Express,Zone D
62
+ #10060,Shipped,6,Standard,Zone D
63
+ #10061,Picking,1,Express,Zone D
64
+ #10062,Picking,22,Express,Zone A
65
+ #10063,Picking,1,Standard,Zone D
66
+ #10064,Received,2,Standard,Zone D
67
+ #10065,Picking,9,Express,Zone C
68
+ #10066,Picking,7,Express,Zone B
69
+ #10067,Delayed,12,Standard,Zone C
70
+ #10068,Received,5,Standard,Zone A
71
+ #10069,Shipped,24,Standard,Zone A
72
+ #10070,Shipped,19,Standard,Zone C
73
+ #10071,Shipped,1,Express,Zone C
74
+ #10072,Received,11,Same-Day,Zone A
75
+ #10073,Picking,24,Standard,Zone B
76
+ #10074,Shipped,8,Standard,Zone D
77
+ #10075,Delayed,12,Standard,Zone A
78
+ #10076,Shipped,21,Standard,Zone A
79
+ #10077,Packed,1,Standard,Zone D
80
+ #10078,Delayed,18,Standard,Zone D
81
+ #10079,Shipped,21,Standard,Zone A
data/retrieval_eval.json ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "hit_rate_at_1": 0.8,
3
+ "hit_rate_at_2": 1.0,
4
+ "n_queries": 10,
5
+ "rows": [
6
+ {
7
+ "query": "How does an AS/RS crane retrieve a pallet?",
8
+ "expected": "asrs_overview",
9
+ "retrieved_top1": "asrs_overview",
10
+ "hit@1": true,
11
+ "hit@2": true,
12
+ "top1_score": 0.2435
13
+ },
14
+ {
15
+ "query": "What's the difference between an AGV and an AMR?",
16
+ "expected": "agv_amr_overview",
17
+ "retrieved_top1": "safety_protocol",
18
+ "hit@1": false,
19
+ "hit@2": true,
20
+ "top1_score": 0.1499
21
+ },
22
+ {
23
+ "query": "What does a WMS integrate with?",
24
+ "expected": "wms_overview",
25
+ "retrieved_top1": "wms_overview",
26
+ "hit@1": true,
27
+ "hit@2": true,
28
+ "top1_score": 0.2741
29
+ },
30
+ {
31
+ "query": "Why would a sorter jam?",
32
+ "expected": "conveyor_sorting",
33
+ "retrieved_top1": "conveyor_sorting",
34
+ "hit@1": true,
35
+ "hit@2": true,
36
+ "top1_score": 0.0959
37
+ },
38
+ {
39
+ "query": "What is batch picking?",
40
+ "expected": "picking_strategies",
41
+ "retrieved_top1": "picking_strategies",
42
+ "hit@1": true,
43
+ "hit@2": true,
44
+ "top1_score": 0.3279
45
+ },
46
+ {
47
+ "query": "How can we predict a motor failure before it happens?",
48
+ "expected": "predictive_maintenance",
49
+ "retrieved_top1": "conveyor_sorting",
50
+ "hit@1": false,
51
+ "hit@2": true,
52
+ "top1_score": 0.1426
53
+ },
54
+ {
55
+ "query": "What should I do after a near-miss with a forklift?",
56
+ "expected": "safety_protocol",
57
+ "retrieved_top1": "safety_protocol",
58
+ "hit@1": true,
59
+ "hit@2": true,
60
+ "top1_score": 0.3443
61
+ },
62
+ {
63
+ "query": "How do we keep inventory counts accurate?",
64
+ "expected": "inventory_accuracy",
65
+ "retrieved_top1": "inventory_accuracy",
66
+ "hit@1": true,
67
+ "hit@2": true,
68
+ "top1_score": 0.2345
69
+ },
70
+ {
71
+ "query": "What KPIs should a warehouse manager track?",
72
+ "expected": "kpi_overview",
73
+ "retrieved_top1": "kpi_overview",
74
+ "hit@1": true,
75
+ "hit@2": true,
76
+ "top1_score": 0.2838
77
+ },
78
+ {
79
+ "query": "How can automated warehouses save energy?",
80
+ "expected": "energy_efficiency",
81
+ "retrieved_top1": "energy_efficiency",
82
+ "hit@1": true,
83
+ "hit@2": true,
84
+ "top1_score": 0.4366
85
+ }
86
+ ]
87
+ }
data/sensor_dataset.csv ADDED
@@ -0,0 +1,1001 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ motor_temp_c,vibration_mm_s,current_amps,belt_speed_mps,label
2
+ 51.449217377141764,2.095295586480196,13.886668426304164,1.5128057072403882,0
3
+ 58.228033127777884,2.6869095358586548,9.567112309754686,1.515025445699021,0
4
+ 59.00698159060603,1.464442382807555,12.72036172876765,1.7973390450218385,0
5
+ 48.232149403320946,2.0039801020646344,10.1108803999408,1.4916081851932097,0
6
+ 45.66553552060678,2.6022851507924183,13.46937801173396,1.682322362474654,0
7
+ 56.55081256504806,1.0929063144784987,13.14322386293803,1.3552480912830736,0
8
+ 53.35344671113516,2.799259918258347,15.160327099917218,1.5877871297038284,0
9
+ 54.655597392715805,2.8304686617814925,12.0839090251986,1.3462231208333737,0
10
+ 57.66629067443814,2.2352095636636444,12.674722989834802,1.3760485234756639,0
11
+ 56.25405538980078,2.693068158480384,11.950057890724594,1.5831495006948586,0
12
+ 52.68842356768938,1.062131798139124,13.235581390565688,1.290924727194806,0
13
+ 53.290989414653865,2.7523396077012654,13.094743183523294,1.5833868046949164,0
14
+ 54.240304635910974,2.5746114636004274,10.525347108512587,1.4629764306732622,0
15
+ 66.40446587435633,6.1553070769977145,15.970225700046807,1.410237827528495,1
16
+ 79.42402862276309,4.692434778727042,18.20331727355799,0.9204302890313156,1
17
+ 48.85743172029552,1.9784939233792664,10.707026467029937,1.7094137353867116,0
18
+ 56.92057361356645,1.5397555079214815,12.610895840603202,1.4865403845132572,0
19
+ 50.31211362839682,1.7082920106704849,10.964826688272082,1.4907502021190189,0
20
+ 57.54148457144511,1.6499322231378473,12.069087207865673,1.2881038466098167,0
21
+ 50.286785507540536,2.8624778396908157,13.158809711374142,1.1932907605492769,0
22
+ 57.65066388154194,1.9033899075648206,13.124185523109846,1.5278751866278373,0
23
+ 49.888249702721524,1.7435610066405864,9.989465687968194,1.5175470351035831,0
24
+ 60.315842361747954,2.924672400618152,10.383625128594431,1.5311625896421186,0
25
+ 55.525943267221805,2.6605753731973962,14.204905846411847,1.4905879974046987,0
26
+ 58.663610169424054,2.9436991448429315,10.103187012078129,1.4272515413607414,0
27
+ 52.383414239728815,2.8442221246591264,13.105254796380077,1.0890700316565782,0
28
+ 60.19691319114426,1.8353565318131695,13.606956808394424,1.6454706731087618,0
29
+ 70.72368720574445,5.104730155104767,16.547282104709303,0.5628084712711698,1
30
+ 69.66285988669125,4.610777704265326,18.448359816896794,0.4433057308175821,1
31
+ 75.64168237448382,6.5799995973156795,25.848760332770766,0.30899549040852725,1
32
+ 52.63558629923558,1.9939253107715165,10.585980128202989,1.5727954924594711,0
33
+ 66.65544986402932,2.5387006843461513,10.797571738847324,1.5113099314719094,0
34
+ 55.128430695883736,0.8251619901847125,11.578899898723932,1.453026909163758,0
35
+ 49.01975667909118,1.495090285526095,11.54082142731007,1.4372597414454287,0
36
+ 55.045704222242634,2.9684828269588226,10.72377056642596,1.6288569087266604,0
37
+ 54.97951253311972,2.686831755672045,11.203767257805529,1.3705799970640096,0
38
+ 60.99349776118693,2.6713829006126377,13.27193811519555,1.424907278101702,0
39
+ 57.85758593052263,2.588804765139268,13.026056869676072,1.388922626924832,0
40
+ 92.50683321669868,4.430164654393557,17.128125940047706,1.0987578389343842,1
41
+ 58.873113418365925,2.4040180884406337,9.904556913373302,1.630796324957851,0
42
+ 50.31197122962074,2.4797701853080834,12.63343352868804,1.3738576291994313,0
43
+ 49.70920155058239,2.583411435892122,9.673470881477918,1.5840493767348385,0
44
+ 61.975738104671166,2.107021661406976,13.36685706685342,1.4368270526014266,0
45
+ 69.83389843255519,6.808566389366279,15.803225080557821,0.6994984894935893,1
46
+ 56.31198193485644,1.6708594745811816,14.31523928402183,1.4498818899929538,0
47
+ 50.55035411206633,2.2743135476514156,12.080628844485753,1.4812433376210175,0
48
+ 77.61677648925304,5.379066500864816,18.17736581987946,0.9037541278264591,1
49
+ 52.6898444505774,1.8876982958924107,13.470286307507733,1.8092698729097412,0
50
+ 56.71156176277967,2.0930977209547548,11.54254017193035,1.795829392791572,0
51
+ 60.70994113473802,2.1052222442303608,11.679070284208782,1.4497601944089589,0
52
+ 49.20749096233981,2.254742679723544,10.34900810364846,1.6622175704442799,0
53
+ 54.88807017387913,2.9311776317366807,12.680993447170438,1.299368446006066,0
54
+ 53.934450039964176,2.018369676215597,14.583539912993473,1.4958849968724415,0
55
+ 53.98993066278814,2.0046611987004024,12.063946536656621,1.3850526975576443,0
56
+ 54.38188207172479,1.9142753904016314,12.96683761797597,1.526947002117008,0
57
+ 63.56659040348185,2.203008340218036,13.120908076715182,1.3245584996281758,0
58
+ 55.966578086707,2.8560126311099574,11.051871265786634,1.3995007354682667,0
59
+ 58.51759189945131,1.82412207609325,9.070776704927628,1.4924057830414514,0
60
+ 55.96998716508489,2.2015542750928185,10.815020469198595,1.5336434099125387,0
61
+ 53.07503550453835,2.7236576430368795,10.973165963730299,1.3908948389011302,0
62
+ 56.1839759587484,1.5860000595887516,13.306234155549959,1.318492072546645,0
63
+ 53.11850938282882,1.8439489790605308,12.712692101022013,1.661851445885417,0
64
+ 55.990663604435774,1.504657285012372,8.91785803848706,1.5389312648357307,0
65
+ 53.66350623719675,2.6201100813470988,12.93851335739423,1.581581550616827,0
66
+ 52.45353886759106,2.094133098727803,10.701090174251572,1.9632768292290426,0
67
+ 58.80821461255956,2.113081149952692,13.148933179089349,1.380648173749412,0
68
+ 51.39030762082995,1.7917124462722127,11.768083862070137,1.5323261953952634,0
69
+ 49.63129933451637,1.5916407908067967,11.400676587617358,1.6076022686413016,0
70
+ 49.89725470664831,2.0586021254262152,13.307901549779176,1.645158808016921,0
71
+ 54.283093498200984,2.919352741179616,11.717120800490985,1.538736928049584,0
72
+ 53.64386769639775,2.012579268551195,12.220983495729707,1.2126652253296508,0
73
+ 56.81586231723478,2.4311062445053127,11.36009252541135,1.3229108490369765,0
74
+ 50.110502749840386,1.8918534559039462,9.058731602295701,1.4674284580385528,0
75
+ 59.75090037304775,2.4515243341884325,12.611592554427059,1.506976975532211,0
76
+ 60.885967891972626,2.0716729418001236,12.197810719681728,1.4911436674042418,0
77
+ 54.586046927736156,2.129506051277791,12.701729674364486,1.70755805417895,0
78
+ 61.67155044447808,1.9091393253988769,12.81169625732706,1.6238506429955488,0
79
+ 57.602371151298804,2.632984319208577,10.648961724430984,1.7088106381461383,0
80
+ 61.44446459399848,2.289370481643164,11.93250718853549,1.3457243638588094,0
81
+ 60.20017837879583,1.760245185670529,10.429069280424285,1.659049080716954,0
82
+ 54.33228827956574,2.37286328990079,11.579897059678688,1.4582855560518135,0
83
+ 53.60509971100625,2.0720839643295883,11.68645161595887,1.2267974487113043,0
84
+ 56.543386210226004,1.3998970754782616,10.070804944936814,1.547699804162107,0
85
+ 53.15059282934173,1.8289039530012818,13.017785927100043,1.7628971331826409,0
86
+ 58.95833573837941,1.6023205128509488,12.322647203728554,1.5567958985757053,0
87
+ 57.827398563596205,2.046717189356471,14.253043877764696,1.6308523019942653,0
88
+ 71.62772244692067,6.5070416261827155,17.408759875379364,0.7051188871215508,1
89
+ 54.15723994254737,1.8609642357532505,12.185610021617086,1.3341247226771824,0
90
+ 63.19502260345315,2.0071850092384196,8.872457554980183,1.608183805919969,0
91
+ 54.7321873084072,1.9116763538831538,11.214340832188148,1.2962604907711817,0
92
+ 48.5909618357643,1.1929487025673553,9.206272871062808,1.5344190546687644,0
93
+ 56.39510357618518,2.481136435957247,11.87322017773279,1.3636503458229423,0
94
+ 60.34313734528093,2.395265298159759,13.71037992141642,1.2507742620392235,0
95
+ 54.381977283000396,2.3760172359014624,12.872775658960618,1.3470359721927805,0
96
+ 54.18834406081781,2.3239737804259377,14.115242992952904,1.5398292973674708,0
97
+ 52.86439904650578,2.4342763892531014,11.94135161817517,1.6898662387749832,0
98
+ 56.363165632008425,2.7956948201457075,13.700353054313437,1.5737178884909386,0
99
+ 56.92298663562364,2.048690120264777,9.658195616716679,1.4134952266608747,0
100
+ 57.344889325437116,2.145136274152855,13.536148259761537,1.6333690976290511,0
101
+ 55.1236691121308,1.7297348922493918,14.02961036631309,1.557708497187785,0
102
+ 48.746088208525244,3.6571223242077098,12.016474338873602,1.5172697051261714,0
103
+ 58.386335943373616,2.9583963285696244,13.097238611911402,1.359864140377806,0
104
+ 76.41845909905054,4.914376118125679,20.445387292161303,1.259918934103251,1
105
+ 56.73906429786648,2.2006699233772435,11.26071034665666,1.5796834842888872,0
106
+ 53.855108200637325,1.7202861234290663,10.562982598948157,1.4577945012141449,0
107
+ 53.650699351725976,2.881925162466345,13.22901464558962,1.2797604360196728,0
108
+ 54.65162331578996,2.933590625354521,10.222223129201524,1.444444408550834,0
109
+ 78.02584585405896,3.5,19.987028177865227,0.6513374511599186,1
110
+ 54.37344840936764,2.922562978463267,11.354312499807063,1.5096884485414832,0
111
+ 73.79193510141695,6.0339304750535465,19.458355534996052,0.7046111620919566,1
112
+ 56.03291529329078,2.527329764223893,12.25421080678989,1.5923377931791933,0
113
+ 46.53338220411788,3.161473097033289,12.317190228545876,1.2621594938099616,0
114
+ 79.60664518495507,4.041212357833646,19.14035835061042,0.7133977428294936,1
115
+ 53.39202967948318,1.9081598215969096,11.988649055053274,1.5669691531867782,0
116
+ 53.122390639189106,1.4978654509546256,10.404660405847924,1.5016203127284022,0
117
+ 54.4756533972491,2.63827180204076,10.069638839195438,1.507774814848927,0
118
+ 56.715025753846454,2.2551978628061096,10.821035088102967,1.4997122399986418,0
119
+ 73.87837427000493,5.414599613376296,15.745443119447255,1.1233000766249028,1
120
+ 48.736963711277944,2.318474305772975,11.262688760764252,1.4272903857676509,0
121
+ 54.052598941961264,3.1668967425940937,12.14188879943655,1.4271905695628815,0
122
+ 53.36644549098109,2.3369211991542285,11.90502021043356,1.7701485901033105,0
123
+ 53.567933247702285,2.6837331364625054,12.351447540565346,1.583492499851633,0
124
+ 54.95166139684693,2.2392993530575187,13.207320848793568,1.4462905995643238,0
125
+ 54.04730502410134,1.6064647868128152,9.829493135377476,1.3096365577710283,0
126
+ 54.34933631782037,2.2186139182107887,13.494832326747606,1.7132440467123313,0
127
+ 51.444810747076325,2.3786597113553136,14.357003724123551,1.4493855368840738,0
128
+ 50.71146791429256,2.3649717693286325,11.22447866256846,1.6956770545673328,0
129
+ 49.092568732617075,3.3549222110450394,11.069222069027008,1.5558488340090457,0
130
+ 53.372225004909765,2.6210634795688166,11.592935260602413,1.3214484767747445,0
131
+ 51.619818688123395,1.6360234882471656,11.184325793470915,1.4634707937412708,0
132
+ 47.90015176143149,1.60926046603559,12.883054917322726,1.5227311193647899,0
133
+ 58.87599148110343,2.6464279081614777,15.589015084527363,1.585266645839192,0
134
+ 59.05086327127931,1.769579160738215,11.740693376334846,1.2600075998873483,0
135
+ 73.26146351925132,5.294520707089209,15.003753669966793,0.6963635478473466,1
136
+ 61.25887208667962,2.5727494532624915,13.499511029807984,1.282086367985678,0
137
+ 52.444488607026635,2.885270494307066,10.962099455738086,1.3203617566448764,0
138
+ 50.906010029512544,2.369937680596352,10.359394407424993,1.2688898255603878,0
139
+ 59.011031301218416,2.239494358170005,12.238946675744462,1.7916896688390342,0
140
+ 53.59146579804708,3.141087440102025,13.010691590501636,1.4443934423290343,0
141
+ 51.322190855993554,2.3115610092030834,11.075710890013958,1.4633506717230707,0
142
+ 55.46674323656291,2.344679578478556,10.03455487535184,1.6529266376496945,0
143
+ 62.34765411328526,2.007877043559715,12.746884401404067,1.563370113635584,0
144
+ 59.512075429397214,2.223278736663931,14.673440689057069,1.4826997507788995,0
145
+ 48.02165605210323,2.627342865067781,12.580588094093615,1.7317848227544839,0
146
+ 55.15432449192367,2.049617707576633,11.451424821530686,1.5672213216940059,0
147
+ 66.88363282985833,4.5618517243200065,21.871855874556857,0.22892235038219366,1
148
+ 54.19166701844238,1.9095199057342587,9.497948100166354,1.5766061923820271,0
149
+ 63.516988448113196,2.2072639409687844,9.931276122977119,1.4801848180780313,0
150
+ 50.35168194906285,1.8686492958223684,14.306036327846703,1.453159770809002,0
151
+ 54.237395769979365,2.845281881160587,12.066325504350274,1.7251853795740815,0
152
+ 55.68784132974824,2.147520921999914,13.109538762619385,1.617319235864211,0
153
+ 53.00281760584339,2.2591739566941023,11.570450796202236,1.4490592461590146,0
154
+ 81.66504618682013,6.0518803195693245,19.798885016808402,0.8238487316623401,1
155
+ 56.571309873039674,2.5710144514897455,12.415934296816271,1.5554558888458696,0
156
+ 87.98865635248963,4.590865930549303,18.780181476450256,0.8086978185246235,1
157
+ 48.64173002676412,1.3333954483955086,12.20730769402992,1.583219478258797,0
158
+ 61.929246421639775,2.348755535592778,12.3170797125724,1.6109446807479844,0
159
+ 51.14544622252478,2.319300395464222,8.711184763788888,1.4609657054155318,0
160
+ 48.26852091353678,3.008437199249304,12.983427091757074,1.395830213711197,0
161
+ 50.62670456845047,2.5438805657999364,9.77169126071659,1.546350353412855,0
162
+ 53.30557357415665,1.6480056823141696,10.260241071349553,1.5930558590897037,0
163
+ 52.7752321646035,2.200999678207544,12.659274216437144,1.2156022201280905,0
164
+ 53.43814420214876,2.397754553181254,13.228656253368207,1.362442658030886,0
165
+ 62.39130005182418,1.4164708748822812,11.197369269934931,1.5097414631326114,0
166
+ 58.3241274306719,2.1278578107398727,12.178194809854352,1.7514892197368543,0
167
+ 52.90912521532128,2.5648578368918544,12.992921384145776,1.5454652827425495,0
168
+ 47.97311287008567,2.9424593933669256,9.28778392969388,1.6229171358926846,0
169
+ 53.30090508882763,1.972236077498285,11.996624633243764,1.4233748161420476,0
170
+ 58.31195270718823,0.8741458325403992,12.734075908407613,1.6480871029475115,0
171
+ 59.70964755591078,2.6433795272023692,12.585682398080824,1.8539657901494417,0
172
+ 56.53357545741398,2.2487067064788913,10.584069712916996,1.5298857061873858,0
173
+ 65.39069490638333,2.936805696126548,9.023785165306506,1.557003494857292,0
174
+ 56.73769457418343,1.5825934565442608,10.829349818033323,1.4048503509711683,0
175
+ 86.10102030757207,4.908557262610718,17.18535444828215,0.627581270301255,1
176
+ 51.88207041309832,2.8243788862052535,13.0462324678815,1.3528350948797678,0
177
+ 50.76585567208636,1.9764211713350268,12.950132311541024,1.5255762279029474,0
178
+ 54.018888616231564,2.5489084195000027,12.549676719857326,1.1807745687021283,0
179
+ 49.500416766520075,1.4911579149202154,10.360657138351876,1.7926415224030037,0
180
+ 56.37841961900143,2.2707097366702724,11.86824648209445,1.59537650073989,0
181
+ 56.68075439489975,2.714390459872755,12.317570676255896,1.4581168621182474,0
182
+ 53.76530777781435,1.2643909419695065,13.747416667782192,1.4826294735042351,0
183
+ 58.13937614643254,2.212564355608017,11.308460579128743,1.461725373746782,0
184
+ 46.985910831733946,3.0100351545680257,12.76159267745738,1.2411968606988446,0
185
+ 60.820182305082845,2.61221353119249,8.67078861206542,1.3628135582508973,0
186
+ 56.461897890571336,1.8126740718689687,11.765367781285052,1.402641037043808,0
187
+ 58.352506271577525,1.9211143270052884,10.257098390429869,1.5346008453570938,0
188
+ 55.93151208054867,1.8857576349316054,12.901438927049846,1.3292509909558585,0
189
+ 60.92582219063589,2.142250560350533,13.870817131713675,1.5006199323982299,0
190
+ 77.45808593846922,3.5,19.740082692606542,0.6486530223667051,1
191
+ 51.42747751366055,1.8529307194271674,12.749682156443699,1.4943367448327205,0
192
+ 86.20440916643054,4.627690049283812,21.1659155874626,0.8833639875576256,1
193
+ 44.30866226758825,2.2187616161697994,11.936349284881338,1.4831754149834124,0
194
+ 51.52381100854087,1.8356947573702365,13.493908027233386,1.4067807048633338,0
195
+ 54.34622840590195,2.820979998406906,15.321228923687867,1.6212821624403027,0
196
+ 53.063322266665686,2.0797814014648286,11.98470582656243,1.1647446753152,0
197
+ 47.027758515783376,0.811002859635714,12.91626737461628,1.3059742710992437,0
198
+ 52.204278285685014,1.607935834050864,11.432941062402785,1.3155738903960603,0
199
+ 51.487390532285,2.8517825339040437,13.783176171530812,1.3201324310782154,0
200
+ 56.78528859017226,1.2012666535550705,9.83797380039892,1.5207335138211455,0
201
+ 57.502361575869344,1.4915789537015631,14.137993415205457,1.569824516124942,0
202
+ 56.72328401203153,2.237856643978417,11.660318123183792,1.310335445823418,0
203
+ 57.54988361060449,2.1582756083867034,12.126991921099146,1.5818690639774928,0
204
+ 51.870334664154214,2.426269209489796,15.31596131608986,1.590163775612144,0
205
+ 50.870949317688655,2.2453712818760865,12.485985384408217,1.7466452565350536,0
206
+ 53.69495197990784,1.5158328512244414,11.506185902461487,1.6406284382624636,0
207
+ 52.91764634857836,2.361398732046624,11.337134974380465,1.5663333093054899,0
208
+ 51.388291287651896,2.1698740767993567,12.727640802745668,1.3113926287527944,0
209
+ 80.08921809566891,6.046358126099891,22.900877324686146,0.9664125761928686,1
210
+ 58.742188501860596,3.13115878069744,13.391613599326808,1.6587829224212722,0
211
+ 47.55261938702996,2.7636773808212114,11.171962906482635,1.361931636562605,0
212
+ 58.173388940799704,1.5176291738992176,12.23584926515429,1.3958935014213538,0
213
+ 51.04184751987254,2.6869470641087005,12.142240289595563,1.664409634958577,0
214
+ 90.13265370512086,7.164391275890606,18.360442164393543,1.166507257450395,1
215
+ 54.52955657829952,1.9353638466500536,14.199304229438523,1.3014617547897915,0
216
+ 56.277601055164915,1.8858144459402608,12.134389151052652,1.094427347988999,0
217
+ 57.55013524359079,1.6386157838645028,15.506767678758248,1.5857788773955064,0
218
+ 54.67364892125951,1.7298893955371417,10.945867560268194,1.5728533438785772,0
219
+ 50.31373348469863,2.7150977015763655,10.315564426339305,1.6753905163605256,0
220
+ 86.80849093599178,6.21633507677066,19.397740605472514,0.5856479343390539,1
221
+ 54.113855537076795,2.091157653282672,13.357889102240932,1.5740147982275543,0
222
+ 50.7884059571842,1.8628937691377456,11.23190787102131,1.4306217924085762,0
223
+ 56.112574905818505,2.341534294004995,11.737547944928734,1.30811190417371,0
224
+ 89.84112862088202,4.376414469945647,20.004372298299366,0.9888301768869812,1
225
+ 55.270316277955565,0.3757935873926084,12.992067284837562,1.6124648330487186,0
226
+ 52.29593077727453,2.0363472848724884,12.742909419102897,1.435866827800572,0
227
+ 58.00180478322583,2.1262787550409166,11.543359855715,1.6253065490853347,0
228
+ 53.98648972420794,2.127986169972662,13.217603564994754,1.5727683838304372,0
229
+ 56.473426450802634,2.6836496179213865,11.904736988342597,1.649378808655854,0
230
+ 78.42081311019676,6.126832256601363,21.457290516154405,0.4145318191444824,1
231
+ 52.84491472952903,1.9800061477351458,16.15115383804839,1.66459912608043,0
232
+ 61.46483872660483,2.7224364062272137,10.92077768103218,1.5301275445913896,0
233
+ 85.69675713661628,3.7274284418650874,20.568734741679613,1.0805686945819324,1
234
+ 60.732858026424694,0.7664725231086285,12.02003338731551,1.275294033691343,0
235
+ 49.18071005896884,2.1186005016836966,8.341125542141077,1.330202033988456,0
236
+ 51.74490908700849,3.0236969988016646,12.621924427540055,1.430649044171807,0
237
+ 53.37433993446154,2.42416203298658,12.086115107157237,1.3047098144754743,0
238
+ 52.637171944146054,2.0684632877718236,11.259797686269186,1.6304513635041737,0
239
+ 79.88847783353752,6.208384687583669,23.106835754844074,0.7634647997883999,1
240
+ 53.467250715456046,2.597466126457814,12.347490666354776,1.4858977238872266,0
241
+ 50.9451305342384,2.2432527709607313,12.486133833480071,1.5535693014406982,0
242
+ 58.76225886556485,2.9941380535746314,11.385526607447996,1.6779213753178246,0
243
+ 46.799311595875906,1.6513311627264784,9.892812678584509,1.4386651364686815,0
244
+ 58.16322448676032,2.8839537253604854,12.744181062133178,1.6525465572356783,0
245
+ 55.15565282760584,2.301816589354901,13.557434893475728,1.5892035317055275,0
246
+ 53.662175310576494,1.8438314677936458,14.10132279046945,1.2039475985387098,0
247
+ 48.0907183072306,2.389421301729197,12.653187503936127,1.2935935002640278,0
248
+ 50.837824243369866,1.2610056170170463,12.727622650596194,1.6002626527929014,0
249
+ 55.634158764306854,1.993831563897635,14.713371813124155,1.4304299337972848,0
250
+ 50.21664141764384,2.3871932258531317,8.988160423792994,1.557715281630749,0
251
+ 56.054868817426076,2.0419011477094062,11.857071319479099,1.531580200618387,0
252
+ 53.547784613739715,2.3147408577318034,11.314785028892004,1.5751628148933698,0
253
+ 77.48635621355311,7.358470670155434,15.466206690868368,0.589766658141087,1
254
+ 54.39579248957228,2.636528300046372,12.936276408704298,1.4644110421353898,0
255
+ 53.75301467671021,1.2739190722993994,14.098704572544131,1.443510791546477,0
256
+ 57.120258822405866,1.6212676838832891,11.677276251343306,1.80198696821919,0
257
+ 58.00347595492504,2.59127941285758,12.101506887094065,1.3856706103444127,0
258
+ 61.515747790495965,2.2140110935129385,11.594404586856838,1.6502750954324112,0
259
+ 85.14956168509539,6.422977002360169,18.84298319214011,0.8050903730515668,1
260
+ 72.69944906347419,6.62213051322734,18.84061433752338,0.5695134511277214,1
261
+ 49.79128197255073,3.230149085262039,9.118626111157228,1.4735680411557037,0
262
+ 55.23309732374179,1.7846150591973324,12.813292928586383,1.7105205577151257,0
263
+ 53.165298860242665,2.3884738928476863,13.184049833504558,1.5510660665252318,0
264
+ 51.011012689594075,2.260588974649731,12.679528134468258,1.4613718201635313,0
265
+ 55.621717310673866,3.428712046037946,13.446826023359,1.7114859325912541,0
266
+ 56.0813729571269,2.180730869078294,10.785819406354008,1.428823059957144,0
267
+ 52.660503460267996,1.741123231291243,11.970147493640122,1.5735910353683833,0
268
+ 59.103347371540956,1.3311427024314342,9.129330397756611,1.4652829803466814,0
269
+ 55.43152177737213,2.796809285928189,15.181715103950502,1.4300375240988847,0
270
+ 65.197311810428,2.354695785078473,13.541371605830733,1.4947981124972116,0
271
+ 60.23820273944211,1.1146922951022944,12.351646674723147,1.333679553759294,0
272
+ 59.34114801778364,1.8640439881601618,12.669992272918355,1.2866922350789802,0
273
+ 61.40711556528366,2.031584016179704,11.52406991212134,1.612930825072332,0
274
+ 83.80947355422776,5.439431112662294,18.202235648617563,1.0926951439501484,1
275
+ 53.527004172847874,2.292028915635783,13.150300939993592,1.324548599846337,0
276
+ 54.23462405321976,2.9005931375169483,12.017574626579048,1.2233819323248714,0
277
+ 51.58782428970568,1.6618773998406162,13.441101461391696,1.4829969003240289,0
278
+ 57.57330717875618,2.9895927514908163,12.455756138456344,1.6468262011855799,0
279
+ 52.48964985425232,2.365144972808296,10.953664190105538,1.6463984924723762,0
280
+ 52.3522962357334,1.434642371371647,14.133159524885334,1.400839635628929,0
281
+ 58.576853314053636,2.814210406140076,12.509712861735647,1.6965059539300424,0
282
+ 51.65014638365923,1.5134984915572307,13.002833014885104,1.6609886747683735,0
283
+ 59.236894955585285,3.387303275013216,12.430336677438907,1.661897348464818,0
284
+ 52.88224229053571,2.2018981258107297,12.441889263837568,1.387391307260233,0
285
+ 53.99209048717246,2.9658894453005265,12.292655959714333,1.596109366530438,0
286
+ 49.694429129041744,2.064162808156354,14.665774260386586,1.78318859572942,0
287
+ 57.742996141098644,1.3115066803369626,14.153991026651571,1.6416623802810408,0
288
+ 54.40988527903859,1.9588837606485396,10.884208609356548,1.452631577076749,0
289
+ 56.53350845272988,2.1454274242193327,13.748508134825729,1.535872392695019,0
290
+ 62.50737844512668,2.1507769988460606,8.097167527422467,1.5415229593996231,0
291
+ 86.57719184741063,5.161565142652067,20.477766286076392,0.681901688277796,1
292
+ 86.53857089706972,3.5,18.765036418038445,1.2923746871339516,1
293
+ 58.982805543599696,1.9671159175709612,13.856825531878096,1.6505214436316495,0
294
+ 58.580739927886746,2.038007612251785,10.664968875354596,1.674524372145971,0
295
+ 50.53046354804157,2.0101567374287197,12.716416094635155,1.4032709540044006,0
296
+ 58.99929698764118,2.597889004872117,13.951737522978046,1.8707713614083203,0
297
+ 59.42397347962919,2.822817480085937,9.23049448331928,1.3623436538249611,0
298
+ 70.2555207785063,4.9645536827832855,19.70452137170888,0.9625948745620108,1
299
+ 49.47127393849184,2.1380953528351703,15.278795649626439,1.391078339597046,0
300
+ 53.73502963062567,1.561491777514886,11.999155354315562,1.070772244484899,0
301
+ 62.07171965431953,2.936007283245067,10.463206630630491,1.736306497415331,0
302
+ 51.69508213454419,2.3802958388284208,11.714892490648882,1.372096032804777,0
303
+ 54.24302263625438,1.8010586181907526,13.844063576475156,1.4716131455147412,0
304
+ 55.366080712692835,2.0412807225811593,13.657410733436588,1.3931918750725556,0
305
+ 52.62239859120506,2.188876102575395,12.128990221121438,1.603147872676352,0
306
+ 55.241543713697666,1.8369924511495117,13.899456835754048,1.6706935154100073,0
307
+ 78.30991028668389,7.059216316664248,16.97277764047853,0.8879715263686692,1
308
+ 55.13112837150504,2.3635049343946575,10.801791382660527,1.6637375429066208,0
309
+ 60.34474440004868,3.2479993751127196,12.756666971493702,1.6441640229180323,0
310
+ 76.97130101107324,5.5851936585099375,22.577747913973244,1.0189460452232755,1
311
+ 52.388335421341154,1.5198708168553368,11.418318066676065,1.494160619927274,0
312
+ 49.875723172616674,2.023192629193178,10.668804262886761,1.4125509174503899,0
313
+ 53.552918090223315,2.0645359349210963,10.646833292728424,1.4326683569579424,0
314
+ 50.37460935893867,2.4816565367582126,13.185510872677057,1.6152905648244553,0
315
+ 57.23419583709689,2.2976315157398863,12.538194125859382,1.7506681842844871,0
316
+ 59.45836977830951,2.6579651511397993,11.917943344726092,1.766507977067643,0
317
+ 63.30792211621501,2.376313601958586,8.42809898981712,1.4798959168785952,0
318
+ 51.58702659776472,2.0780519449113313,12.30811579044189,1.297436787291692,0
319
+ 52.71622535391282,1.801544505351655,10.72988386067397,1.3644698330135592,0
320
+ 50.439356323495076,2.3875310759461703,13.623527894687603,1.7815704712997462,0
321
+ 55.12252597037767,1.6238755793616164,12.98819605254929,1.4998320417003164,0
322
+ 53.76261384111905,2.4219063546915525,9.560873267060225,1.3483696623215524,0
323
+ 59.26392092315057,1.7221874162993012,10.693175891961278,1.617929890297937,0
324
+ 58.455312054792756,2.410113354737293,10.929270754171933,1.7949191207063384,0
325
+ 50.83765578995027,1.1326531662615722,11.97474491439986,1.3989222467729159,0
326
+ 56.58796521799536,2.3822625189964013,10.554337219148417,1.4665766736364183,0
327
+ 64.68166004898961,2.3279534250521117,14.903071775293665,1.5719535795896296,0
328
+ 55.28813429293031,3.0417931047690114,16.05597766091908,1.3665294015977385,0
329
+ 54.318369675343185,2.2470915291161564,12.544513871571775,1.2948086583927205,0
330
+ 57.80665459235827,2.0738129375077583,14.560151460628461,1.196632941593478,0
331
+ 54.111109211604905,2.442580556272869,13.940264952689056,1.350646465973729,0
332
+ 54.77218183514589,1.4891181753277136,12.726680158872632,1.6577782290791279,0
333
+ 56.75634671571831,1.9554612659405384,12.744514551511097,1.4470134462258588,0
334
+ 45.877048618512305,2.580927387021232,11.679304707225066,1.6596468279370773,0
335
+ 45.34887867628204,2.5086407902461296,14.733082832014263,1.4608103413438118,0
336
+ 56.21886831901772,2.3948458526600014,11.940440576479533,1.628581553033492,0
337
+ 55.26618326343682,1.294690660009803,12.09404745485507,1.4053557604301805,0
338
+ 51.357700464314206,2.4540395525995327,14.282550679105437,1.6064492798456815,0
339
+ 50.96585583222757,2.958220050294702,10.96234538549653,1.2975198881556427,0
340
+ 57.897130709824914,1.5523294077669827,11.303429411706826,1.5544894618871297,0
341
+ 53.20574316788658,1.7659032846796103,12.39113157621175,1.3387067429667938,0
342
+ 50.432247095430384,2.288630683474428,14.829283737834123,1.5265679745007545,0
343
+ 57.08466902292845,2.0744487059815437,13.621284307426308,1.4893926612413306,0
344
+ 53.18006607863688,2.085353673223846,12.157035044832188,1.3389576406293648,0
345
+ 56.42748423659804,2.0177808738677694,10.21140700433635,1.4825600032034452,0
346
+ 57.80781450488508,2.3288202104605804,12.259510709478338,1.77393140203602,0
347
+ 55.36850663373644,1.8197455759643177,12.139019169043506,1.5500323517454306,0
348
+ 56.185672003234636,2.1473879328745644,11.94412612117181,1.289225345898456,0
349
+ 86.74902484487465,4.562570768623593,19.752782917751734,0.830682096030153,1
350
+ 57.66154043589115,2.6352778047098635,13.536769013140034,1.7219385560476403,0
351
+ 69.92363203293007,4.931103431960366,18.576034068756773,1.3441359101792056,1
352
+ 55.87753000545543,2.124376176626812,11.159325796795386,1.6340698118903185,0
353
+ 61.29341960990097,2.1575747341689953,12.08474503798985,1.5178685894049417,0
354
+ 59.19735844217363,2.0371509449631358,13.431522493637546,1.8739108299957778,0
355
+ 54.23478270047354,2.217305937092628,12.35335480595984,1.6154843971912147,0
356
+ 55.610250048409874,2.7037553854932797,12.9441060091533,1.744110200919703,0
357
+ 49.49325540977476,2.301387524126184,11.394611822220998,1.647100994149114,0
358
+ 61.90940085665674,1.5387294333541606,12.384988096068392,1.6873534045310243,0
359
+ 51.44746458506539,2.3143850144644693,10.350512481233487,1.5363966406985794,0
360
+ 48.71183897738704,2.564357117037173,15.309787960710603,1.6103600040420245,0
361
+ 51.7482356187587,1.8188382709861741,11.43048529372774,1.4003119991612105,0
362
+ 49.07785394973993,1.4185578273300754,10.80893468745172,1.5819167746338672,0
363
+ 45.3603121368005,2.4249891706732742,11.589444006273348,1.7615432800937347,0
364
+ 50.937683675169836,2.1993036742783256,14.40634365702752,1.4838699383600904,0
365
+ 54.47544987918662,2.0735592768410847,10.445127037695514,1.54057280791653,0
366
+ 58.35395681494538,1.8778164398934887,10.898418363913049,1.3370889626081282,0
367
+ 56.65093044638395,2.0838653350378826,10.685835113658063,1.7761883421640356,0
368
+ 60.40250048381063,2.4250103367109164,12.274372095193058,1.5825650266402178,0
369
+ 60.84577716896881,2.2901819715131992,13.447755739093,1.4005239374044853,0
370
+ 56.10509671731422,3.2017547052006714,15.01638916860077,1.5231119988223303,0
371
+ 58.63440543956845,1.8718145532259458,13.92988519693085,1.6550714162098465,0
372
+ 54.83694989545826,2.161321910089573,13.194816045779996,1.5858363630280912,0
373
+ 51.096164735540384,2.8790605479336304,13.379135514970478,1.3128558301284312,0
374
+ 56.65763773310398,1.7226040914345895,10.088072396976742,1.4748188895860532,0
375
+ 50.097576944931006,1.4036028701392365,14.544880024456276,1.215743122507818,0
376
+ 55.51136161266914,2.0872842753859504,12.715552690839687,1.560046486246451,0
377
+ 58.723352905402116,2.226728956308737,11.269329658777233,1.4506620194499935,0
378
+ 55.025356249449075,2.34561570842369,11.180193310457433,1.5940664400223747,0
379
+ 56.988642976215054,2.50840709984489,10.208451778913311,1.4754353843816697,0
380
+ 81.87067612596672,6.064540426684205,19.668850715316385,1.3057781729269635,1
381
+ 52.984169034357556,2.1434157951355517,11.411660980619576,1.6613584451241288,0
382
+ 50.750342352561745,2.1556017761437496,10.509453184340275,1.4398117591020263,0
383
+ 53.338570959281256,1.7703969907122152,9.295715705373176,1.343210582790229,0
384
+ 57.04488725819014,1.5090254843181838,12.70473738480745,1.4576978277097186,0
385
+ 52.083664649025565,2.117531112301891,12.170622230229215,1.386717087087447,0
386
+ 54.104564732478,2.4251586390219066,12.022020209834567,1.3917008190394933,0
387
+ 84.31244931614245,6.593473606228777,18.473202552308095,1.0997499293420148,1
388
+ 60.45544891925564,2.791265370876329,11.264666774941837,1.4139495463712373,0
389
+ 57.540603787257616,1.9498194613015503,10.705221506483584,1.6455746971295597,0
390
+ 82.31008732136497,4.9277391723600665,15.961242852885762,0.9850324307233912,1
391
+ 55.0482127224073,2.0862902936780583,11.890172514024268,1.3036357421418021,0
392
+ 61.143023967983964,1.9958334185866655,11.565186576787696,1.5455200351225005,0
393
+ 57.17261707322078,2.6431969797839763,12.01647827029129,1.597136115459253,0
394
+ 45.71857595045542,2.3604248231623037,11.816874168042911,1.3644181065628689,0
395
+ 58.36123254982958,2.578124081814903,11.29524523725191,1.5417499409355757,0
396
+ 55.94179347323972,2.364183986415769,13.684641945662309,1.4390799531793521,0
397
+ 53.89943099509326,1.9579849342136622,11.747022369899321,1.5958139072513966,0
398
+ 53.93664483233849,0.9596457450077294,11.558478414709125,1.50669874214452,0
399
+ 56.44768741571537,2.4194955146944475,9.909491273450742,1.465870587695517,0
400
+ 58.42007729718912,1.3200921461522674,13.259352136161379,1.3585260113445916,0
401
+ 77.00609714589586,4.233479462853155,23.47724642808229,0.8262837679013403,1
402
+ 53.28668871134757,2.116921079025134,10.68053635894874,1.4121932247040434,0
403
+ 62.74892464971807,2.864315533424718,11.678587586168302,1.4070535525478982,0
404
+ 51.853736899583325,2.760420325701584,13.265905337330032,1.3272609699888065,0
405
+ 51.235511616300165,1.7355054164347103,9.67123879004992,1.7264806024680472,0
406
+ 52.54409279442841,2.0424128050573884,12.92435309482997,1.6702912097479783,0
407
+ 51.693179812332424,2.3889854989973496,13.635989904132199,1.5875679817939423,0
408
+ 78.27785978876484,5.774152818078785,21.13559965144208,1.1370226648416695,1
409
+ 59.62124814442679,2.5090953573326504,12.478642251035362,1.3747723270842747,0
410
+ 57.52515290335416,2.4258843004704924,12.346923034115047,1.4409543793054433,0
411
+ 56.73953708585459,2.52587407070152,12.020063719073795,1.5480674270769057,0
412
+ 57.67330407243199,3.3146368052779867,11.567571812809021,1.302461238955058,0
413
+ 79.96964377248618,5.555443930977944,21.397016640027402,0.9969249773813702,1
414
+ 54.681081744572765,1.6872949361110479,13.451998206830797,1.6334019380658524,0
415
+ 56.886154090180554,1.707420983844587,11.536466452205627,1.5042490117624412,0
416
+ 55.97641755591341,1.9357869344422374,13.395566786434339,1.4909861628367302,0
417
+ 54.94541283281881,2.344109531545162,11.097808782661492,1.1707224380216688,0
418
+ 60.00690003426078,2.4751012480132206,12.326160622954891,1.7817568697989694,0
419
+ 50.488876940433144,2.0928124451474432,11.91647242102501,1.6960499330106025,0
420
+ 58.59126163364219,2.6855695034114557,15.351579369296523,1.8351139621196597,0
421
+ 53.674047311610984,1.8338573092989623,10.883064965342156,1.4829125410420374,0
422
+ 58.51380120522909,2.8817143560428495,12.72597344092729,1.655905356737783,0
423
+ 50.13643630358348,2.4660646869407192,11.120226523620053,1.5098298871245075,0
424
+ 57.32310838131919,2.1176744862280246,12.415438012829048,1.5847375921909368,0
425
+ 57.1937116833192,1.4864317989068796,10.675200553267313,1.4530436571110692,0
426
+ 47.67637669660988,2.3350477170986434,14.37424417016,1.406459623555596,0
427
+ 51.71099993083872,2.5310407672908766,9.436160844134767,1.5652880935756595,0
428
+ 53.473048424006684,2.567791546214187,12.152171145975075,1.6598966444614702,0
429
+ 53.6604598800569,2.26551355809671,10.373084066345642,1.257456089975258,0
430
+ 57.31824456990591,1.7348676563649748,13.493308992244023,1.338156421942705,0
431
+ 54.61085360634604,2.141559906795738,9.033376406449307,1.4953884251609206,0
432
+ 53.1139007702002,1.5118062504610261,13.165609438486348,1.4329391112198202,0
433
+ 54.389909870190564,2.699668166237245,11.217692032820425,1.6767676275477497,0
434
+ 59.273886223956154,1.8373042389960124,12.33644596077239,1.4323236964140877,0
435
+ 59.30496062986554,2.011893948108268,12.497993240185401,1.9007645069635029,0
436
+ 59.76457181235546,2.383104798891969,8.765987990910931,1.408485170091433,0
437
+ 55.26412279024486,2.4777910443250626,12.410705767985279,1.488784661765291,0
438
+ 53.35629107666505,2.4162972258630764,12.046570800732832,1.6128575599069017,0
439
+ 55.80922476732477,2.525124502789182,10.892435128684337,1.8115066988788535,0
440
+ 58.7905984393932,2.2477195192438684,11.667605745002845,1.8081817641931166,0
441
+ 49.86946139895791,2.3051456455430737,14.035144736195946,1.6294726108056208,0
442
+ 50.662447711066534,2.082085318912574,11.895301821356794,1.4033316352675926,0
443
+ 56.04814324829752,2.1932921065375957,11.827833076497116,1.4733783769359619,0
444
+ 80.9273000521174,4.972643783983732,19.043842254182646,0.43088846443705536,1
445
+ 50.585037208871974,2.0172652029428875,10.758623638898008,1.3791422750080813,0
446
+ 54.363260514479755,2.3450201982417678,10.54529940732739,1.5505435014090285,0
447
+ 53.82488431939148,2.2572922185119393,9.70070268247094,1.4164244209420351,0
448
+ 47.25264783751926,1.6175859517694802,12.153708550654734,1.4403774997605854,0
449
+ 61.31636502564174,2.8595065988706985,9.160243258142842,1.3016706050868827,0
450
+ 48.17739113593793,1.8825934180142718,10.838871172526925,1.3077223128407003,0
451
+ 49.73267915576703,2.193530615948206,12.876253610028435,1.412416959136167,0
452
+ 62.989186122991974,1.7952568405536171,11.078872836983448,1.6513649705601008,0
453
+ 55.2520094733388,3.05304587906382,12.72779734721656,1.4891381491754185,0
454
+ 56.83754308686645,1.1354010553999914,12.055208248645432,1.3823786559794387,0
455
+ 51.71445328310246,2.766117286089624,11.645804862333021,1.9589296843495236,0
456
+ 66.62026867696163,2.7095218466208815,12.153384989471125,1.6089043549558713,0
457
+ 53.75806409521623,3.2043776930925696,11.636071428899589,1.5084308479633728,0
458
+ 56.155666668674826,2.806441845861578,12.21175352824896,1.8048505537065507,0
459
+ 44.74102263271773,1.4064508496008794,12.024194122914006,1.518704591647702,0
460
+ 64.31061240138433,2.211677658057278,12.077547482142922,1.3714235394333856,0
461
+ 52.28694223937929,1.8624430239282694,13.93752969848801,1.742397363624307,0
462
+ 55.56970294428226,1.7001438856653095,10.403290880810742,1.4358653453111814,0
463
+ 49.21576858244618,1.3724523284074084,7.624260178954401,1.4199306090511188,0
464
+ 55.96663887928335,2.555988511495526,11.033687624420327,1.4337926531451075,0
465
+ 80.41464452006113,6.4112622505968915,20.785284371383252,1.3020763202855488,1
466
+ 45.75958625346942,2.2848532725714064,13.089147542169501,1.6857240452234774,0
467
+ 51.26552927996049,2.201496645599978,12.928657527697279,1.3716710320637135,0
468
+ 55.28851803085548,1.677478145206849,13.785458555265176,1.5010810590564556,0
469
+ 60.31074452907077,2.3880221848113057,11.852889647201238,1.477015355961268,0
470
+ 53.229857152431265,1.744278188431355,12.7750542279727,1.411203178840503,0
471
+ 51.61735586893061,1.9464473597858791,12.370024724416115,1.4604784124731447,0
472
+ 49.81411068770095,2.0262382939032406,11.348699350111671,1.3780538963039728,0
473
+ 53.30680675182339,3.0971850273001795,10.294616127884348,1.3821305595925841,0
474
+ 82.36123718217854,4.6170976116996165,16.581274806561915,0.5831203775127997,1
475
+ 56.78612470411978,1.9586049206376779,12.814287336716394,1.4325774855345443,0
476
+ 52.315438890413674,2.2132926706630496,12.373400865594986,1.5208667609642388,0
477
+ 93.7589094542214,7.637472313097882,18.344739443138426,1.258988360696103,1
478
+ 74.23453655273383,6.335694268987323,22.079948508162555,0.8051625384094538,1
479
+ 77.23648014608827,5.0502459102519,17.0630700110541,1.2297551981355932,1
480
+ 57.16452644321812,2.449359720534862,9.528755551428842,1.5773937715151767,0
481
+ 48.392963407282934,1.664149336569128,12.46319891527225,1.5830930258992986,0
482
+ 55.94110444635305,2.474064189821098,14.363516388255992,1.5971420965829342,0
483
+ 48.25066226416788,2.1451329091849085,11.600379698887235,1.6650556021045835,0
484
+ 58.111167741715796,2.3985166500077457,9.039249195211553,1.605979876934674,0
485
+ 58.040532341503415,1.4121903364146926,11.729539465725699,1.6992718216187597,0
486
+ 56.809335802572555,1.3822683757710712,11.949594840065787,1.6304641780747435,0
487
+ 55.92864529226688,2.800153129129661,9.753940244858196,1.233544854173067,0
488
+ 52.337961170845226,2.4453833544969097,13.318431041551339,1.3752715841000436,0
489
+ 52.9268806305349,2.4830938792874164,13.602693100866446,1.5409433632295084,0
490
+ 56.539803864423455,2.42751186017376,11.867079082120249,1.7293970218450943,0
491
+ 53.657570527525415,2.1087500786748694,10.874997395627233,1.469033136238419,0
492
+ 54.95072282828276,1.5265987256102174,14.348669296804882,1.5509462650070027,0
493
+ 58.250405151014576,1.6249572529238185,11.72505366535911,1.4908615417938098,0
494
+ 51.31659840876349,2.3942371004257708,8.851190486158135,1.5354486423042302,0
495
+ 53.48734978384244,2.170358676987034,11.16814139153933,1.461057895298134,0
496
+ 58.21434007751441,2.346466911748646,12.226382290209743,1.4935975355658786,0
497
+ 54.52544669556047,1.9067074574645497,14.362624241413096,1.3753071246073385,0
498
+ 53.628855396542484,1.6838014902225764,12.738445367907055,1.4403333129089688,0
499
+ 59.35686998684317,2.0985290281623152,12.01691654492799,1.3999873724689718,0
500
+ 56.11545713858896,1.9743077745178026,13.036593848800315,1.6088561974978084,0
501
+ 50.555580396329766,0.981812168376339,13.493452209176748,1.5117675196166867,0
502
+ 58.267103468803164,2.7948110026438218,14.724790494210158,1.5338789754474829,0
503
+ 55.639966454293756,3.6046054306147517,12.325909737342936,1.4194209308979873,0
504
+ 55.552965728234724,2.6227415542409274,9.215532649328313,1.3299343461870408,0
505
+ 73.4070281937465,6.301837412269157,18.23783034251648,1.6,1
506
+ 56.56505863973294,1.9340612530286214,13.069496138017648,1.5362178239403643,0
507
+ 78.08931525124557,4.967054254761382,15.963329181728596,1.2928576909543201,1
508
+ 53.25837010822415,2.1403169003615616,11.849553498834888,1.48897820076144,0
509
+ 49.99341114357544,2.5979193276098873,10.496436381350673,1.4216381352853464,0
510
+ 76.60289570330649,5.2614020764253535,16.12710177365341,0.6720396223965255,1
511
+ 53.80294118445897,2.836441384377332,11.83764999251554,1.605628551768475,0
512
+ 53.495375715079604,2.9364767860947874,9.284680018369777,1.5170699348010446,0
513
+ 45.42295878039811,1.5763412651529158,13.574247908794979,1.6363739403320814,0
514
+ 50.13375940247549,1.803737084771043,11.47271289728506,1.5730227820723925,0
515
+ 51.56283014846705,2.778753879010567,11.306809387241332,1.5101333226121236,0
516
+ 62.28258463058721,1.7495515023477126,11.957973322656384,1.4744385514147527,0
517
+ 57.55850563799161,2.5758982329177282,14.152509266983403,1.4658351681627986,0
518
+ 55.70629343381484,1.8250933308577415,12.194894781249111,1.3090571356890401,0
519
+ 56.14330455841017,2.91765007832272,12.733002786700961,1.5594612753310602,0
520
+ 75.3102613581346,7.122017647432129,22.089457232485355,0.48967383036088225,1
521
+ 59.89016535469612,2.259612930563696,13.832592999326389,1.2398082754594206,0
522
+ 55.937603570794785,2.5872473519326857,12.498798469646461,1.433746230874051,0
523
+ 48.53736664271729,1.6182631001038645,11.339238208728009,1.504500980779641,0
524
+ 49.230803457762356,1.8111970361258667,10.949873955531167,1.5170055807037834,0
525
+ 45.8348419656076,2.838490416099022,11.857552034110993,1.6889558779320608,0
526
+ 56.89878835385281,1.6626169930911432,10.383658006699012,1.3995477857891696,0
527
+ 57.22613377100505,2.454949124238268,12.932401969681457,1.4932900598718197,0
528
+ 53.48077395284042,1.4790106321799938,12.00798429067755,1.5527896156227987,0
529
+ 57.57575517310743,2.4598302866732515,12.377781622942507,1.419435451565083,0
530
+ 61.443747980047576,2.477680114254288,9.716701087212858,1.5028486779960162,0
531
+ 54.6811271563744,2.8574039357529526,8.765965436175028,1.4225553604707737,0
532
+ 50.0221128495957,3.092659197112364,13.813896852638067,1.3685152763725204,0
533
+ 58.431903525028616,2.6621788785937173,11.443832745806908,1.6238570462137965,0
534
+ 56.075653790714405,2.0829372313585437,14.32483584919369,1.5248273193025144,0
535
+ 50.55827726234209,2.194680661690904,13.533610838040708,1.3017953892532097,0
536
+ 55.524231304184575,2.5356140058068495,14.170588044046653,1.4600404387211237,0
537
+ 58.713187966273935,2.4059857910633773,10.614780330100045,1.4210239955225827,0
538
+ 53.05476836370668,3.4225650725294585,11.019055299544616,1.536509837460081,0
539
+ 57.76194141627107,1.6792061836893644,9.257407032837747,1.89521111316225,0
540
+ 56.79125486689084,1.5900621275792393,13.722384636773983,1.2592416031494116,0
541
+ 59.26888966628793,2.3634217351940117,9.626749475809623,1.6253422391829366,0
542
+ 49.52736320301734,2.5266224416406136,10.790577268972974,1.440420853512439,0
543
+ 56.26597704669323,1.2459347933873668,9.889628751597208,1.4920045696513269,0
544
+ 46.41084388104538,2.2308523170251844,11.30616642551313,1.234955715280492,0
545
+ 56.721205435830214,1.656716070204705,15.416145672834148,1.3915146471088742,0
546
+ 55.08740858209377,2.0630747472268816,13.538022051386633,1.6169804418784164,0
547
+ 74.11553876579029,6.258165639054314,23.626158084609386,1.1109076377136233,1
548
+ 55.397909892062955,1.416034791784751,14.053176947855345,1.6056222212459677,0
549
+ 55.11643978630668,2.24880199624772,11.76730030322911,1.7352309670595747,0
550
+ 55.99614448922777,2.188657362337177,13.058954620048224,1.5416016269580322,0
551
+ 60.85321156487825,1.1098949677552632,11.125327391545964,1.7763225987852396,0
552
+ 55.930704845418816,2.2260866593287667,11.075926461665812,1.280631392271877,0
553
+ 55.74130259766153,1.3973643764337162,13.362589945900957,1.5058969599036445,0
554
+ 45.99289083752382,1.8352114029321769,10.857012714259515,1.342936241885032,0
555
+ 60.97976524493758,3.3214601562014927,13.565615096580741,1.5497312542700539,0
556
+ 55.33592401325782,1.671422562930863,9.856776848660584,1.4745188274630392,0
557
+ 74.5233594865098,5.323511800589675,17.68286701003206,0.7572752642062148,1
558
+ 58.37754076194128,2.4967773474527837,11.075737373738214,1.3732019302533647,0
559
+ 55.21262139031147,1.9941252911576755,12.7960409070371,1.8047100247167753,0
560
+ 58.48571511179276,2.367920628466512,12.049042837879906,1.6569078376571849,0
561
+ 60.90379619221404,1.4203083823471956,12.191043713484728,1.7135339208397549,0
562
+ 51.42109192417669,2.813146477824475,12.588016406048634,1.3184401908325818,0
563
+ 70.63938759269018,5.440113530695945,19.80261502291209,0.5240084212964511,1
564
+ 51.98843233108552,1.9417446289195839,13.710314218405104,1.570687568676884,0
565
+ 58.1110695563397,1.3173898423485757,10.701985751847248,1.4022938564898673,0
566
+ 52.778691124723935,1.4463371761134765,12.569531370920975,1.3895590325192497,0
567
+ 60.282646622112665,1.936642304026896,13.413890431349689,1.5382790027634026,0
568
+ 56.39740249024172,1.5688053505714175,12.054721133421348,1.4087628079201324,0
569
+ 54.75470261668461,1.874718189797204,11.580484753300661,1.4601959837528617,0
570
+ 56.21746691612104,1.6993542836217281,11.501747205241491,1.4821457240099811,0
571
+ 78.05731371754108,6.609639036123751,20.043427007579574,0.6015680642914065,1
572
+ 55.62819426978138,2.418756124309935,15.001444652385231,1.6463976075441078,0
573
+ 58.340444983658315,1.1460233291112787,11.917346851436566,1.5013759872273194,0
574
+ 55.176849512416794,1.9308418985692102,12.124077302794783,1.6099362836156301,0
575
+ 56.156477594759934,1.3382682962972912,11.03768591882573,1.558724405602216,0
576
+ 58.25505475986484,2.3509853712596356,10.386641570785477,1.4886342785310263,0
577
+ 72.44353175789705,6.258851431078958,19.577524943138783,0.47347137928586536,1
578
+ 46.47181487707476,2.5492831726857528,10.158126673962235,1.5870593947287905,0
579
+ 56.39083380980383,1.4426226121032304,12.624552222208433,1.6596314233287013,0
580
+ 52.18130694852047,1.7173244025956185,10.779914381479985,1.5886981093278727,0
581
+ 52.8661906113411,2.7394395195148693,13.700683908846019,1.542585900176321,0
582
+ 58.129401369670646,2.177781916147823,12.832718522917247,1.316191230079634,0
583
+ 54.800296356054986,1.2596007860129714,11.608757312393125,1.337094817044878,0
584
+ 55.8689247792421,2.1180232499865017,10.003684121079765,1.3445065651253099,0
585
+ 52.01560697338995,1.9325943308907212,10.75010611269413,1.318144756041041,0
586
+ 53.72357361195641,2.7124608465627,13.240759199431833,1.5818818256608718,0
587
+ 58.31807616809629,2.8164509670513485,12.65648351030146,1.519769764051623,0
588
+ 59.591250642934256,0.7221905878274653,13.251788321053587,1.6111922650477533,0
589
+ 53.23739031372103,1.5659930415780017,9.208209473241666,1.2590614772556927,0
590
+ 51.70207513723504,2.670144732441795,14.21741840357409,1.868736540860484,0
591
+ 55.690351670888475,2.313393023054568,13.154785339583032,1.1635758567584351,0
592
+ 49.850309674903876,2.5450522123820063,10.508497337257321,1.53407441975812,0
593
+ 59.85675931571401,2.2366376572928486,10.774810231094616,1.2689468436227385,0
594
+ 56.9282673421021,2.2810297795314374,13.983756497284684,1.457525500667024,0
595
+ 62.14067360828852,2.0817767900177433,12.583556385650645,1.7192698751320958,0
596
+ 47.25213226917834,1.6846414840338304,11.73008986817504,1.587179821799138,0
597
+ 54.78486979672672,1.5113421722398166,12.322953944912268,1.376716234268544,0
598
+ 55.20986719342498,2.382681871031884,11.29803553001356,1.73790057464398,0
599
+ 60.097788867764955,2.8625733644374196,12.421759748465218,1.640913063269727,0
600
+ 55.751894349944415,1.3161889435303098,13.18336182507486,1.3772253596384423,0
601
+ 47.56065837381749,2.5241970056193566,13.181224056578287,1.4439835550475728,0
602
+ 51.16446959668401,2.4647067035628614,13.39895826448668,1.5242879050927602,0
603
+ 50.24494778270859,2.218029963398898,10.474163488347537,1.788674405551886,0
604
+ 59.684988373869274,2.405491288450438,10.78631102258844,1.5602892424618218,0
605
+ 58.10935030424697,2.255306561289339,12.874662203486615,1.3472823582721971,0
606
+ 55.70958445854776,2.58576662988096,11.09310207573069,1.4213377660543436,0
607
+ 76.9869444887822,5.421945192737429,14.710604289054208,0.828158680465103,1
608
+ 61.894662883133186,1.901955550171917,12.586087539133343,1.3773662402505051,0
609
+ 52.88202916374479,1.689477419660839,7.4285511519708685,1.4197116650054133,0
610
+ 57.855280545929595,1.8425617190512453,10.882525591911538,1.475741849543813,0
611
+ 58.05170592934775,1.1464038263351561,12.436099766800234,1.5726965266967554,0
612
+ 60.2240069668273,2.321876240200824,12.255937617809689,1.545837028785372,0
613
+ 48.86455438033545,1.9569029346504767,9.428271156755818,1.6031538277676673,0
614
+ 56.77018249681621,2.264310796245633,14.235186513444859,1.6158317216028757,0
615
+ 50.85968754383744,2.178710689477778,12.324307014484033,1.5194114305343804,0
616
+ 49.013445240386694,2.78775328825439,9.29928196239873,1.3532338679937848,0
617
+ 53.08358731635208,1.3895432408459243,11.828516747992879,1.563918592022914,0
618
+ 78.47803643560539,3.5,19.74095755029189,1.1325687560552145,1
619
+ 52.246510871076964,2.697745141472659,12.607473478387016,1.6812394238220751,0
620
+ 71.69896728191574,7.689854821368538,17.110883208937018,0.6582246664146926,1
621
+ 55.87475438691605,2.022150842214483,8.943407238397924,1.6740139269965326,0
622
+ 77.7665397912827,5.166095477851393,20.008440606316814,0.45100185698313594,1
623
+ 58.93095804409223,2.4055859590079818,10.195955121148454,1.518924779464646,0
624
+ 53.04099926839516,1.8905267237043186,9.153278250150336,1.3222973034506513,0
625
+ 56.78428880592832,1.642691518466037,11.539954068261094,1.398373268146235,0
626
+ 56.475003136329995,2.9181508782816454,12.996530511359897,1.5172400867371518,0
627
+ 53.810706549209456,3.3148659207047744,12.418862330900343,1.4907726480593044,0
628
+ 57.71565425228758,2.391442868192525,11.423174834973125,1.474983639899702,0
629
+ 81.16018825262746,3.8873213059703997,16.434003864712018,0.9658208009261717,1
630
+ 68.6649635300104,3.5950086115224384,15.543154574253434,0.934554264945837,1
631
+ 56.37858090494421,1.7739205970172032,12.549499400475066,1.5699493158255624,0
632
+ 83.11939597721445,5.2864509331051766,15.615481201132855,0.8801422101933717,1
633
+ 55.8923189705011,2.81301695495534,13.852871082465409,1.351941726819467,0
634
+ 56.81768135285745,2.5164289573036536,12.237672075749602,1.5388931462302362,0
635
+ 53.59619047112809,2.36200626209499,12.832860111419135,1.5204903424519052,0
636
+ 54.116130728854586,2.30533343886231,12.762989314527148,1.5279079265478284,0
637
+ 55.91291332055562,2.064922435331452,9.792281473013722,1.6347832920213925,0
638
+ 57.12923674221339,2.115140101789811,13.290794561942167,1.3642788745178367,0
639
+ 81.73974639751182,5.2270952430932125,19.228816098097152,0.9077886340300515,1
640
+ 50.72099035484124,2.52894400521659,11.864711379933917,1.659852776208007,0
641
+ 79.54016699425851,4.741821173100663,17.14496643777565,1.6,1
642
+ 54.49996387872169,2.1752205812242087,12.90749006351831,1.4564901339094123,0
643
+ 53.850466553803294,1.1512745211949293,11.282875413369263,1.453254084907542,0
644
+ 51.639374092149886,2.15606162879219,11.611941147471406,1.4647274030078348,0
645
+ 68.50828489537261,6.90369541718262,16.26861432404147,0.6587550115275124,1
646
+ 57.216466005296375,1.8881996553708937,12.50256355130612,1.6901435341205857,0
647
+ 51.15163553463349,2.6797952628750368,11.316778126717773,1.3217416718102597,0
648
+ 71.39660800181909,6.03536920509721,23.160583128744094,0.5866750535074703,1
649
+ 53.552669851662635,1.8127449692433024,10.41391988300508,1.388598171794827,0
650
+ 59.1966944857654,2.043822279172065,13.826587781176706,1.2726462117729793,0
651
+ 55.1423059079385,2.938696832487335,11.868140268946178,1.5528004430906448,0
652
+ 50.57181727182605,1.8719725316795164,12.13180145562109,1.400663277101311,0
653
+ 56.11430365804723,2.749595777773907,11.968940453840649,1.6390283870364812,0
654
+ 52.22597534171088,1.6740563635507932,11.36615852580188,1.707191852333839,0
655
+ 48.989986175836414,1.954172192517258,11.347950789415298,1.6656742537808351,0
656
+ 78.82123992413631,6.400508265284292,20.407144800455978,0.5895837027945765,1
657
+ 56.583735497723296,2.154564535187019,12.13523524150136,1.7341779799764723,0
658
+ 56.45381735135629,3.052926340272282,11.869942948736815,1.4400419915565355,0
659
+ 67.59368542530659,6.613054932776252,19.787607590290428,0.7145836779644378,1
660
+ 63.513878929740656,1.971764427887639,11.593659559393593,1.382489841915507,0
661
+ 82.71910050799099,5.329552470120472,18.752842210094286,0.5878197435475486,1
662
+ 48.301268221182575,2.2548238772870044,9.335402555486558,1.7052704090647695,0
663
+ 50.665204690567755,1.953299329808661,14.116975478815068,1.6983203841117716,0
664
+ 70.0662816245989,6.366642050759749,16.359133841241356,0.6929011262466673,1
665
+ 59.54419473422171,1.4164114547072768,11.429942906711705,1.3730846795734004,0
666
+ 55.95094240932911,2.9211523955931225,12.764731061664177,1.4453357372903637,0
667
+ 65.06989615013568,3.085670621133842,12.847730068214654,1.6201078682504484,0
668
+ 53.164638027402795,1.7075025361377794,14.066604354412117,1.2676114235483635,0
669
+ 57.95006227386835,2.5169551888668713,11.804960907752266,1.3527135231073795,0
670
+ 51.65040710469015,1.9196229179561275,10.847466510678132,1.5278269959877115,0
671
+ 60.41434355827759,2.795206781646872,9.771656995153393,1.3126886083938434,0
672
+ 55.04580516668262,1.9466986520143987,9.481334358564425,1.2628033827733511,0
673
+ 50.29354112228279,2.6390292894541,9.586789936095043,1.2961684131115476,0
674
+ 54.79521155273361,1.4496652986090808,10.513340526618974,1.4251593675057082,0
675
+ 52.144500703854064,2.3707543427684015,12.491619704927924,1.2784188054808452,0
676
+ 54.0425774901079,2.5098509827412396,9.800721026295687,1.6264761465034003,0
677
+ 53.721315134570794,1.6187856099300348,13.008171472644655,1.5170812791213018,0
678
+ 50.85738498869675,2.097965707780576,12.368056513492999,1.7146378528236528,0
679
+ 53.42503531110171,2.5769275349668415,12.907187373825852,1.6578966626423342,0
680
+ 69.136153474096,5.059985447619374,14.0,0.884823779569971,1
681
+ 50.12474775830549,1.8027002724374728,10.333603357176418,1.5030055936299467,0
682
+ 59.8500753473264,2.604560655495122,9.236423306953991,1.3470623237748836,0
683
+ 54.62680540138604,1.5440984171113945,10.56474493068053,1.5606817789629235,0
684
+ 57.96005694521734,2.1486689544796835,13.992234931343695,1.302745634169337,0
685
+ 54.93279536998284,2.234959790497413,12.059540289896344,1.5453387327728192,0
686
+ 50.02317648455652,2.329903928402755,11.705252369402839,1.5671572545142602,0
687
+ 54.5442101693805,1.6245677454072167,12.329377390769917,1.3583365682395363,0
688
+ 62.8040502405052,1.5540588658841552,13.012716989842346,1.5627748611825576,0
689
+ 54.303309064780166,1.8378287402958997,11.395255984604926,1.5630484244664193,0
690
+ 51.05257168628705,1.9192584866085585,16.2861576347098,1.1225857206340852,0
691
+ 53.685899107508426,2.148801646694452,13.157811438554743,1.2678250750890134,0
692
+ 62.19037808973726,2.14041558133604,11.5321630316169,1.436799408803145,0
693
+ 54.72807897606238,2.762521960854013,11.642345473529547,1.4510634477564257,0
694
+ 52.521336263485544,2.1058079363678086,11.346404867749891,1.6168244575681547,0
695
+ 57.19495527545651,2.2729691470723874,12.367022888231025,1.4488655130832475,0
696
+ 52.76908445001914,2.196047742313382,10.451951632257634,1.7020984862420339,0
697
+ 55.928679558505024,2.0726959151169853,12.409293777038659,1.5456653284220723,0
698
+ 50.8627677933024,2.233956584584668,10.648448956117573,1.4240746099961499,0
699
+ 53.51234167471484,1.7367334444214249,10.79321005466278,1.8496537007337106,0
700
+ 53.860463734469704,2.4827302095845467,10.700375792010842,1.5430936141554545,0
701
+ 54.36546065184525,1.5791222355608039,12.084617350754357,1.47673045657014,0
702
+ 50.670291210446855,2.129302248928099,12.464119259639887,1.5134263499645721,0
703
+ 49.02237752072277,2.0695500884995752,12.105169738099825,1.4477745313744987,0
704
+ 48.1840285495585,2.707757608241465,9.135355641380578,1.4179492918732508,0
705
+ 56.5401517506244,2.037227494240234,12.977310930965938,1.6724065261436727,0
706
+ 59.97978951458578,2.754584905746066,9.36528491888053,1.3464528357450163,0
707
+ 51.59385124325693,2.368200469344936,13.456509503938783,1.4464042409599775,0
708
+ 54.43683645433446,2.47129723164598,10.636345667094966,1.4068767921479117,0
709
+ 52.55161280376077,1.931168711548489,10.87175869789872,1.4148416785120947,0
710
+ 54.61528425230667,2.488701288759625,11.677133315135768,1.501199104432322,0
711
+ 85.14360407320751,6.341621006013791,24.35861706194245,1.1265755327928302,1
712
+ 46.010925778636576,2.0981090694377262,12.946857492100722,1.7887519202603777,0
713
+ 53.7048331828536,2.1270947709555923,9.125103798722684,1.5248418225348979,0
714
+ 48.67362240218423,2.114217744891826,11.453434060660138,1.6333474770606973,0
715
+ 46.70806625603483,2.6310000252060672,11.70753017082032,1.6014921827664788,0
716
+ 57.92309876455458,2.4619754770963356,12.289772369719797,1.5019855009202505,0
717
+ 55.73293774888762,1.5009451701005747,12.29757174093966,1.5767270552878787,0
718
+ 60.43675030096175,2.5080673340011193,13.693486651443026,1.3453196897340622,0
719
+ 55.124342351084614,1.9171806258224806,10.75978634191039,1.244385056152889,0
720
+ 48.25761073046077,3.1987570889023815,8.441706707904729,1.348655103361762,0
721
+ 56.070845849375345,2.250962943686329,8.729450686892717,1.6097720091481331,0
722
+ 72.5583780894246,5.976437922752776,17.979567060027616,0.7113163935201676,1
723
+ 53.42157950856164,2.4472783276614267,11.862689970872689,1.511792650429768,0
724
+ 57.15213775971301,2.2661732532013366,11.1964276908459,1.4334147545371865,0
725
+ 56.05099690058855,2.4087359793710075,10.627313010780748,1.8449496104422258,0
726
+ 44.73336623627481,2.5750609060684724,13.228145925521163,1.8585334065977706,0
727
+ 54.28155434467416,2.22674081341095,11.19069722711829,1.3475975205887667,0
728
+ 55.87998673588706,2.4049142286643463,9.117743204177042,1.6013968283710385,0
729
+ 59.42515484023956,2.23095824183998,11.621905776894966,1.6711219184042072,0
730
+ 55.362339627606985,2.4991735235374417,12.65101473517516,1.65318334338287,0
731
+ 52.382866893249776,3.555372763609163,10.646240240335063,1.5806150781341006,0
732
+ 50.61285768618144,2.4365435990137376,12.990663849822656,1.7400070921979411,0
733
+ 55.79116032776741,3.11811291986501,12.020847313998766,1.6123220828973714,0
734
+ 74.08322223692524,8.914353273889166,18.555435686778274,1.0053929027963753,1
735
+ 47.86555548114327,1.8518939742100504,10.5876935966553,1.8095841803485002,0
736
+ 68.11333715337318,5.285713638527375,16.920597064342974,0.42153742079532003,1
737
+ 51.42261581568989,2.6573120269934236,13.8111375424668,1.2996419236043146,0
738
+ 53.27464224704196,1.4039934988792724,11.640343480659613,1.5304810400090858,0
739
+ 51.2936962343779,2.7227661373948404,13.098641714644257,1.8740890508591983,0
740
+ 50.54644783231261,1.3563261527933244,12.414621546380632,1.5731987056206882,0
741
+ 58.282113901669675,2.507135219178532,12.136200035415072,1.6171771807835613,0
742
+ 55.04578175636586,1.8802483045562624,12.690327959152595,1.6311513642669582,0
743
+ 61.91598136354281,2.1553397986496328,15.409487738969084,1.2682050081706864,0
744
+ 55.63247633962044,2.742257580464983,13.568460180313899,1.5789303027185844,0
745
+ 75.21933231824762,5.596729330744626,18.386246275661247,0.5038730559466771,1
746
+ 52.21622955331719,1.705686425282697,12.71490445098597,1.6368228593965168,0
747
+ 57.79678692677955,2.619961302566399,12.856761099436572,1.6146171608252684,0
748
+ 83.1705509652202,4.46718034820257,17.169980167735716,0.8267673844433696,1
749
+ 50.939728377084734,2.468148484590447,11.349558772268718,1.7911300408772803,0
750
+ 54.47108537387531,1.9732808508157038,10.51072978824909,1.4728153448179948,0
751
+ 76.40675715222459,5.837025218470627,18.249229354409216,1.018551942844646,1
752
+ 56.88454517359972,1.9877686451090513,12.151405187602732,1.6365152242409657,0
753
+ 47.432214986752356,2.7597503404014585,11.640574266848029,1.4087448756143972,0
754
+ 59.99866106817511,3.3934758997869614,12.538434660977206,1.5152730919654949,0
755
+ 56.75854642406797,1.5368019483407258,11.81729216392,1.325739996159848,0
756
+ 81.40302424211816,6.0044345510111485,17.77465412940155,0.9703786742680311,1
757
+ 56.86032083800122,2.4565999055385905,12.392130619094953,1.4177481693202472,0
758
+ 56.40702563359682,3.1008709738735734,11.951494321957178,1.397757817120435,0
759
+ 50.4422839956337,1.530808794338078,14.486064180348745,1.5985227790080208,0
760
+ 56.314648009129925,2.4138981991235666,10.791009586752303,1.9547643622665951,0
761
+ 47.67437566313951,2.50132622315325,15.858776155454596,1.3047330393879735,0
762
+ 52.62340017721282,1.9496276281215421,12.827788157296938,1.4369237484844664,0
763
+ 54.01695399994839,1.4950151484580623,10.947349580599827,1.2410089978314334,0
764
+ 56.26242001436136,1.8570736619116788,12.989226321377844,1.6767277279225776,0
765
+ 54.813650918642644,3.6047844850481963,11.016384806351528,1.627629135578879,0
766
+ 56.79239745574481,2.1784332051795463,11.468118679122963,1.6056022611482481,0
767
+ 56.089479021096956,2.0900321023668322,11.350151015065467,1.2695591528933634,0
768
+ 58.36728026756025,2.386526159217089,10.175094427065893,1.6156048173142146,0
769
+ 81.36924692771787,3.5,22.51653883412661,0.8233080884856614,1
770
+ 62.01476410680432,2.453291577095127,10.545902133392069,1.47689500251362,0
771
+ 59.82341448355294,2.8908537966888987,11.404629238143313,1.6584578379046324,0
772
+ 55.99514923920433,2.5201068296643796,13.491525702186477,1.662206219090572,0
773
+ 64.53040913073629,2.2147117877924867,8.952570647005459,1.5937817895869197,0
774
+ 52.210304706798894,1.0751081110241965,12.161301270080452,1.6585783905362048,0
775
+ 55.65756281190921,2.475595864350847,13.153448807360618,1.5808956829414311,0
776
+ 49.071258410228715,1.6099996107663705,13.185590215449258,1.5352679914727498,0
777
+ 56.91550215408185,1.9182642872874653,12.58984466547724,1.233758543313191,0
778
+ 57.589938762837896,2.0080995371461277,11.539309390371322,1.4939486420198982,0
779
+ 51.546618941042475,3.069824020965506,13.016227263137091,1.3992228390358192,0
780
+ 54.46470814193584,0.9745639357299569,11.095920955454666,1.5276550060763496,0
781
+ 55.396139284028806,1.4539470822635043,11.931662809868188,1.665900943725418,0
782
+ 60.45057055921336,2.1148057883219447,11.134727290277532,1.509620520356723,0
783
+ 53.37892293820267,2.6907398746540583,10.472526701458113,1.2171640643334793,0
784
+ 58.70975392623272,1.799894151699075,10.269487625400359,1.4706566503788467,0
785
+ 54.179353244535825,1.9001252754405678,12.721542997145484,1.4986599198162045,0
786
+ 48.59488825152459,2.2302342240586843,9.389245516458276,1.4293767513336695,0
787
+ 55.36195912651149,2.1079121267423893,9.999788521898697,1.3985629953954577,0
788
+ 82.31455827653002,6.409332113123424,18.12907659191482,0.7776807685186701,1
789
+ 52.487735665098505,1.6936580743059193,9.214784397089751,1.5535134435462536,0
790
+ 53.86254464783962,2.4024275438178546,12.946912095182364,1.6464998054967195,0
791
+ 57.36362529117342,1.2961515701125337,13.404854033785181,1.5784265641123545,0
792
+ 52.82601796826946,2.5473353058142045,11.260167231741134,1.4485733020635245,0
793
+ 57.098029501144346,2.9581843233626683,11.805395695217245,1.2557936679073183,0
794
+ 80.56488625272503,5.551147027694447,17.965986893138954,1.0319771900062993,1
795
+ 85.36164525861564,5.838505469001856,19.588224272924673,0.4697333377627191,1
796
+ 82.83660130080082,5.221449171405571,14.0,1.6,1
797
+ 60.804715396084255,1.2327346321434414,8.509350304582036,1.61608367713648,0
798
+ 55.05594088746117,2.514398146805152,11.121122684322623,1.4620916531140413,0
799
+ 56.51712013746065,1.0373143125628568,12.307060029030795,1.3214274367967467,0
800
+ 54.43198714236991,2.08167058767405,15.905439448125616,1.4651449140934842,0
801
+ 67.71541471747014,1.9115018143112334,14.460531140847467,1.7408225074190946,0
802
+ 51.98588967857049,3.34979454651866,12.225121695517537,1.402881085728072,0
803
+ 89.49260814943716,3.9737737785989378,19.025838907955887,1.1949719908336212,1
804
+ 59.991799940237726,1.471431043540222,10.95146722034411,1.1835074029680042,0
805
+ 54.509261450019494,2.405106007839776,10.765946965381348,1.493730415818673,0
806
+ 56.94788992314233,2.5159907418806977,12.400104251964962,1.5141704987729456,0
807
+ 47.96908643457348,1.1992271277806608,14.874667315103116,1.503667308287968,0
808
+ 51.339375536616295,2.9888841024659434,11.177890600132766,1.2212636006831197,0
809
+ 50.2602249343319,2.4223634090976165,11.120922540036663,1.3665314510554203,0
810
+ 60.61528556826623,2.29065710893071,8.424916945563957,1.5382623065801637,0
811
+ 59.51588917088357,2.4947734430178015,12.131944344496503,1.439582558834064,0
812
+ 48.25412739506359,1.8676869999684347,14.21919321577829,1.6670489560111947,0
813
+ 52.380849218282435,2.1015571506480453,11.646248634278727,1.2234678873811935,0
814
+ 57.349036667211166,1.5120432056992246,11.384199017977478,1.4482264699135654,0
815
+ 51.667853108815954,1.3708322172088776,10.080754806129153,1.492561453817709,0
816
+ 56.699863589744595,3.3338221019496275,10.574195689221387,1.5614626829434934,0
817
+ 58.40514229937916,2.356909510053561,11.229545608927635,1.6573429299542164,0
818
+ 76.35604941061798,8.859636666204771,19.21499766251304,1.2711151625527406,1
819
+ 54.24931603628619,2.1914810553312685,12.218272208003393,1.5160732609258984,0
820
+ 49.21155011030765,2.376360081513172,11.127609098577592,1.6013409949746717,0
821
+ 51.93785889028115,2.429852977507494,12.72050144382207,1.7417865716201235,0
822
+ 51.49255688732965,3.0593975015249297,13.38395958418178,1.746399044015435,0
823
+ 50.91750792194665,0.9929460744844816,11.519189432493679,1.5095966567053283,0
824
+ 55.75937357134977,2.104619769832726,11.467954045560484,1.2124776192352384,0
825
+ 56.256308895479194,1.5067788733649037,13.22297410825745,1.3389446380923298,0
826
+ 56.25563284583021,2.0110967336208643,8.434064262405029,1.4922648240785679,0
827
+ 63.14029321092427,2.0023779274982645,12.296334423791254,1.6449194521506159,0
828
+ 44.99320062336138,2.350776153406452,13.930263393968254,1.3800513866553534,0
829
+ 51.627078918828516,1.5220930144367233,11.85870813697375,1.6713883834185173,0
830
+ 53.11289586544666,2.0027135740653033,10.501282663003481,1.6406065450379472,0
831
+ 47.85316995452769,1.575470014660974,9.587721283182688,1.7161218897006394,0
832
+ 55.916845496460276,1.8692915538465922,12.021108124310258,1.4015270839771914,0
833
+ 55.33448430964223,2.311983714186724,12.302017279822383,1.704368736600032,0
834
+ 52.17094188019414,1.9541262901349328,12.43680780169724,1.3858702882427736,0
835
+ 60.34959242977097,2.0193647874982776,11.009549825967017,1.7746431433134848,0
836
+ 47.19585924538465,1.8888962773526412,12.138531057381687,1.5316296903132132,0
837
+ 49.88063616943992,2.340977933697079,9.285574546624156,1.7131613907104675,0
838
+ 63.210739927783564,2.3184776943596233,10.54257184048056,1.7531329559229958,0
839
+ 81.78480098487611,5.796408048981009,16.186941224050415,0.6733377843778415,1
840
+ 49.30506225840376,2.647802621657173,9.445832082160035,1.4738738156668203,0
841
+ 48.52051202243292,2.2041409549789637,12.921660184338712,1.4573851491958825,0
842
+ 55.813552962479775,3.3628898959408424,11.735451074266004,1.3734285032212916,0
843
+ 60.84471546688132,2.766026144207089,13.02358876471919,1.5562886217250105,0
844
+ 52.91470832545086,1.848465459551099,11.946262880001067,1.399663598999487,0
845
+ 56.59909690689375,2.2653820939557723,11.325044427203027,1.5860043705259417,0
846
+ 60.14932444642026,2.318413058394014,13.768431867887472,1.524228697823077,0
847
+ 58.069268961844905,2.995226148958012,11.442873395876898,1.5787643960958897,0
848
+ 51.40122085404899,1.069792621331074,14.389368133684211,1.4434210687816393,0
849
+ 54.52983133068748,1.7017906869988053,11.315765705826964,1.6137529548966099,0
850
+ 52.12207906686084,2.097965242475783,7.855986741489385,1.4540696881542678,0
851
+ 55.89438219509873,0.7347028120736123,10.322541274190185,1.429520212617064,0
852
+ 52.95102908371385,2.7826537677735885,10.324008596923088,1.759112742994215,0
853
+ 49.789391532662144,2.059699776580968,14.058513514299777,1.502759132335698,0
854
+ 53.65624309983941,2.255675214699056,11.122217326609483,1.3778745027020831,0
855
+ 56.350298195195734,2.765049658202257,11.322073530219738,1.4159326785308441,0
856
+ 49.11677482198937,1.9360411813378433,9.974851322810368,1.5739901690758649,0
857
+ 56.461776257456314,2.406896158595107,14.33822437169863,1.4745673926449334,0
858
+ 55.902239358040724,2.6045973659265864,13.849295614963514,1.596752503397259,0
859
+ 49.14623199265199,1.7528963240102615,13.962369910319865,1.388082527558591,0
860
+ 57.66234094525372,1.7420882613517814,9.629491023231697,1.2956923753721021,0
861
+ 56.020853667423495,2.267561725934041,14.210119622162635,1.6643283617243714,0
862
+ 61.41701744606856,2.3818490751714814,12.904510280140014,1.3111790310473495,0
863
+ 53.83131525678578,2.5064826902373,11.055983273498244,1.5332974166514406,0
864
+ 54.72344826109544,1.4574722604362822,11.026105620584795,1.3763803917990785,0
865
+ 58.34323158525735,1.4732003600341848,10.6385737408491,1.498758017410562,0
866
+ 55.21741434156153,1.9804730449475314,10.603389768086846,1.4002407419457565,0
867
+ 62.28519540325244,1.8887299236672237,9.510168177870469,1.4257877354211432,0
868
+ 47.03675201950401,2.4877732549999476,11.238899135399363,1.653713510062616,0
869
+ 62.986923566767146,2.6028393196212507,10.984088723986083,1.679450922805537,0
870
+ 55.651012260420025,1.6988280096545996,14.118769604941509,1.419972071147568,0
871
+ 53.3716870545987,2.614560535533027,10.364329121174283,1.603291755146833,0
872
+ 48.077313577971125,1.7983799540241476,11.312877297497808,1.5266386675385388,0
873
+ 52.44099386900101,2.1976835138878275,13.299337801287793,1.25034654100047,0
874
+ 71.71674743953778,4.412282728867404,16.192055044780098,0.9938137737824405,1
875
+ 51.11940192139435,2.091386920890662,12.629197339279873,1.7140477150839704,0
876
+ 62.34954670195008,1.7901230356145783,12.996438453083453,1.6294638680416362,0
877
+ 75.42316412463299,5.8636579395192605,16.040602257349512,1.0550971416483426,1
878
+ 57.84490631917142,2.1821946319049546,12.434828213877601,1.4186994144711043,0
879
+ 56.0115392598796,2.520495359697487,11.095532531149495,1.4061563840397906,0
880
+ 56.87003736900818,2.6937025725232004,12.255265414787898,1.4787895993761933,0
881
+ 55.521098085891545,2.27492120699364,13.362094265276978,1.4908473973457388,0
882
+ 57.97301668481377,2.3058048663975255,11.119018855854332,1.3720593273311592,0
883
+ 53.855005065777235,1.9287210899440876,13.80405120980422,1.512938075433751,0
884
+ 53.1692022761727,2.0909854359477893,11.439886594764177,1.657204436642588,0
885
+ 50.102123873117996,1.4281873987389595,10.84917439720404,1.521248504608654,0
886
+ 57.54762513348884,3.0991438504615316,14.523575378010147,1.2928254102763839,0
887
+ 57.1524617480157,2.766840239378351,11.957875387343952,1.7363880432818084,0
888
+ 49.99873784430741,1.4137358749987796,15.23798851605725,1.3567032736770286,0
889
+ 49.171376720577335,2.438764668633398,11.550993138372418,1.2571392269822752,0
890
+ 54.586319545701464,1.6392844769913726,9.339878191785479,1.5836363764237225,0
891
+ 56.248037886204976,2.485268518069243,13.269456093461594,1.4856174596151044,0
892
+ 53.51313321365722,2.110672415493055,9.397535876931851,1.4192551357025025,0
893
+ 50.91087887341068,1.8199049556905473,9.43279026040431,1.6842591552501576,0
894
+ 51.30845423241893,2.296210558884091,14.839573328133815,1.9221671179899242,0
895
+ 55.70604968548979,3.1802423003915137,13.17703307419753,1.3850307248703497,0
896
+ 54.01975739523719,2.766344910259795,12.373370398012545,1.6237406834421153,0
897
+ 56.366222203762035,2.6813287862434207,10.16294283352419,1.6132292838711064,0
898
+ 56.130347931677186,1.0278510531056615,11.8949807117808,1.5571243879256509,0
899
+ 51.66652477620238,2.6581557205372834,10.822831129266014,1.5820000548924726,0
900
+ 55.6407623732683,2.4330888310986554,10.226324141690345,1.3835288387777454,0
901
+ 73.80448741101571,3.5084837940083147,15.579692884366738,1.203498124111994,1
902
+ 56.24581133721376,2.263298355138847,10.981531028472027,1.4543283288380209,0
903
+ 54.76635502456527,1.8849587448721654,11.478925749602203,1.3115917810697943,0
904
+ 55.00033757236566,2.0182083548466005,11.705993553232476,1.4951288514123817,0
905
+ 60.629927445254864,2.507049588556312,11.001183433319346,1.289024905948165,0
906
+ 52.099095741856985,2.9270250907287294,11.039264892216861,1.5949302485335932,0
907
+ 53.77166712666169,2.1428950541110816,8.720337031874148,1.5513005186131532,0
908
+ 50.5218564989179,2.7389216778725913,11.187024899660711,1.618876111750891,0
909
+ 55.78710438662783,1.157798922505763,11.734711209640807,1.421664228068624,0
910
+ 50.87674511891539,2.8322699046690185,13.513002533932259,1.393042937746303,0
911
+ 59.25540613093743,2.4780376369115755,10.082867455932295,1.6294631277068032,0
912
+ 60.75110775966585,1.5011569184407985,10.975362297622238,1.5060504608332037,0
913
+ 60.436882401182444,1.4009738123616433,12.959904248701188,1.4545197574934254,0
914
+ 54.17824976852948,2.370104988434169,10.258632065419892,1.5163053229220114,0
915
+ 57.95765068920379,2.2201282510002316,14.220148805570874,1.5592714228547588,0
916
+ 49.34893646443054,2.6120998098979316,12.823474311115366,1.6454114686122308,0
917
+ 50.840063575038016,2.2512765918631334,12.663681907454567,1.3331933618461198,0
918
+ 86.01827674726094,7.353339373742408,18.654882311796165,1.0409182019205145,1
919
+ 78.8206447039002,4.365692137751949,19.809297238947664,0.7927409674336395,1
920
+ 56.33718051399086,1.8376944742411379,10.502964610059184,1.3361726509369563,0
921
+ 56.82710095022965,2.4316849030163437,13.0872820073343,1.7256760077883841,0
922
+ 54.805126392279526,2.550361578429793,13.684017381845608,1.5061770030523767,0
923
+ 57.46391769030198,2.354810040954584,12.86799245072275,1.496154140947849,0
924
+ 55.81118910759112,1.3924745547076063,12.571907085121463,1.5916113233694291,0
925
+ 52.76171085580204,2.1956026552572143,13.936543582776203,1.653132423150371,0
926
+ 61.88307932466394,1.4055512179106375,12.8689229569814,1.56193370928336,0
927
+ 55.27752454053112,3.1564774038658765,13.550679251908349,1.408764040599407,0
928
+ 52.02564708474974,1.7819714425771065,16.218973872358085,1.538473796766531,0
929
+ 54.60605806196231,2.9396372553371153,10.825230207427248,1.4837195050972265,0
930
+ 57.43504588889776,2.9759400600612445,13.888672274002104,1.4892002111340317,0
931
+ 51.550728162097826,2.125963797726123,12.218445471515826,1.4143296128460394,0
932
+ 58.60073825607985,2.6942766212326577,15.797857016613266,1.4264306758959435,0
933
+ 46.74704689278103,2.2339933130255445,10.958604356627896,1.443972900422873,0
934
+ 50.626114518152065,2.6942659314257313,10.776260028023351,1.1793749105879119,0
935
+ 54.62294978298977,1.040194636624391,12.990056237685502,1.689773991823249,0
936
+ 59.508964827872134,1.888916149872871,11.989324717307227,1.3289689715023263,0
937
+ 53.81371618586117,1.5109953615760672,11.611186111027376,1.4149930462034774,0
938
+ 57.06164161160324,1.916852542209497,11.33089593231175,1.5825380614550548,0
939
+ 57.09675137125108,2.188383144574817,11.297361453150813,1.3641952180977253,0
940
+ 63.37267323572238,1.7010740083779874,11.607657148400397,1.4123956000166988,0
941
+ 58.726292051496976,1.6640187238548907,12.357582562256137,1.5765208073420163,0
942
+ 62.62024085625788,2.005683409466591,12.882960227606103,1.526557402126487,0
943
+ 66.36748423797884,5.050253016738091,14.0,0.8085233487182514,1
944
+ 57.46102706787425,1.309630946218265,11.435843714160626,1.5384951571622294,0
945
+ 56.092816091408494,2.503145578054354,10.843154750648042,1.501886775352775,0
946
+ 54.772867222429234,1.3239507136365147,12.687838704318253,1.6035137122763092,0
947
+ 74.20047478635844,5.950129796505029,17.778293577592592,0.998223328559262,1
948
+ 43.14188464863339,1.9096742986272077,12.554037089549857,1.5643448086690799,0
949
+ 61.245752807214295,2.184583742957908,10.520639834225104,1.471986279779347,0
950
+ 49.13181901843604,1.9284145844719434,10.854841024034009,1.4559895363404038,0
951
+ 54.36140677031193,1.5568033324581516,13.679095742997571,1.0875846920942167,0
952
+ 47.165634238411876,2.3484579353680566,12.548231017557757,1.2153096722247756,0
953
+ 55.204568234208644,1.7731203887062943,11.471602447575346,1.5495779292881393,0
954
+ 58.163206884715954,1.0278283457905633,12.160657545014207,1.4964865561198777,0
955
+ 61.603711728925,2.0616499549571436,9.959634843611738,1.4501336198490344,0
956
+ 62.19024466657856,1.9310943268214305,11.869560036590968,1.6462127722629871,0
957
+ 54.195581381924676,1.6662031154775572,13.847812701433956,1.4258490074725958,0
958
+ 53.64296606446394,2.3822672445166315,7.4043302005314064,1.2358065893036183,0
959
+ 57.50034080499262,2.1234870618968937,10.678142328845924,1.5487327078236877,0
960
+ 48.756166588022225,1.990575628037481,13.239610964839887,1.506180910017243,0
961
+ 51.536675537227026,2.199040073411827,12.590065305381145,1.61252223948485,0
962
+ 57.47668446790157,2.1878513081145923,12.190300464443764,1.616521154829772,0
963
+ 54.717278473391715,2.681480286624724,14.35499772749842,1.5161173054045975,0
964
+ 56.34633250642174,3.0549719770060357,12.402244171432974,1.4682680095379208,0
965
+ 57.0651902884058,2.784769073646942,15.030959548163748,1.6467889295497447,0
966
+ 61.91479057762237,2.3363226317160644,13.73842437356535,1.4558146868007582,0
967
+ 52.276281822384234,1.766497371838287,13.153854312055692,1.6934894547927362,0
968
+ 56.755972634953196,1.8432230093148227,12.297867931022274,1.5177996254585995,0
969
+ 54.896548608184574,2.0730186609761097,12.826386571340311,1.395266781040114,0
970
+ 51.139532951070514,2.123157447818991,12.246480989072873,1.2797040854527062,0
971
+ 51.94777116122093,1.8190127708448713,11.94828770244805,1.382361223662723,0
972
+ 80.08760686309627,4.903930356647553,14.31961124391651,0.2991558784422512,1
973
+ 54.281923146869595,2.204252813361577,12.81798489295059,1.5632425244864745,0
974
+ 51.823454839898304,2.3252231501303804,12.02600194372696,1.6108989038512356,0
975
+ 59.399918601368334,3.1514537311370843,10.653760543718006,1.747216824273582,0
976
+ 57.997735598910964,2.4019770103678058,14.667481360079734,1.6169294131157175,0
977
+ 56.46612562894892,2.9386968170850176,13.712221152154827,1.376724705538867,0
978
+ 56.65556114149077,1.9345117477221427,12.591356474163046,1.426162936685192,0
979
+ 61.727266477203294,1.8506597820075852,12.704040989431162,1.640460062552197,0
980
+ 57.33062096795083,3.340816438638031,10.80276996336775,1.4594405166294961,0
981
+ 54.929748694090215,2.269962156019557,10.030248422700094,1.1611179183633582,0
982
+ 53.44076078737693,2.7938171963605605,9.42125829918593,1.3627161418270015,0
983
+ 53.63063624534447,1.6265839589162798,10.216679769603592,1.3607513803816458,0
984
+ 50.96842820150582,2.2360088209585265,14.153967187202664,1.6177431433031877,0
985
+ 51.378083778559756,2.611876565938091,10.386396062032151,1.4034658312574029,0
986
+ 58.42717593026611,2.0125276550754325,11.550520403916952,1.2643353386144074,0
987
+ 55.04997647491075,2.365520077498098,12.299452526867272,1.4915338354669339,0
988
+ 56.33228149047302,1.9948300133274455,13.626879587195766,1.28145218688281,0
989
+ 61.04491373310689,1.9252236894349588,12.147002871149075,1.4850248129256824,0
990
+ 53.68930762255216,2.2510156486202875,14.38532820843267,1.553604745823351,0
991
+ 53.82723365340495,1.6365060448995683,12.912677604644518,1.3685910803834131,0
992
+ 55.71710253982526,2.3580239353221435,13.54035861948093,1.5448377228876227,0
993
+ 51.77360438277051,1.3588367591044868,13.66495446465855,1.6631181930222696,0
994
+ 54.26055054581896,2.041046725685769,8.838465918578397,1.5263550684247276,0
995
+ 59.45186356664105,2.1725325668985414,12.829615180537868,1.5598472851053518,0
996
+ 50.46685114398608,2.146909034688712,11.157290184711616,1.5865062542315103,0
997
+ 51.199911780357674,2.5350396211010953,12.048555151090547,1.7589198562004265,0
998
+ 52.11376786582861,1.625398001405853,11.486770663901929,1.6542080348098775,0
999
+ 51.071922320678794,1.6118998416782837,10.487536670588607,1.6076588413125095,0
1000
+ 52.579997148765074,3.129747403811656,10.434083892797037,1.331260596734677,0
1001
+ 53.5749441157543,1.9927634670820709,12.904405415632834,1.6311416518378596,0
models/anomaly_iforest.joblib ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9dc690ec59c1639e4bcdc6d85f3ae61e9e932ae935b250bab7dd5de7654d62fa
3
+ size 2149241
models/anomaly_scaler.joblib ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6eedcb449295a4276c34a0e08175010fd3b6958e8fc7158658461a9820011ff9
3
+ size 679
models/intent_pipeline.joblib ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2a036b8e8f424ee6a56643919058a5b8df1be3db1e3673cd0618f3aabd6b6b04
3
+ size 65196
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ gradio==5.9.1
2
+ scikit-learn==1.7.2
3
+ pandas==2.2.3
4
+ numpy==1.26.4
5
+ matplotlib==3.9.2
6
+ joblib==1.4.2
7
+ huggingface_hub==0.26.5
8
+ spaces>=0.30.0
src/__init__.py ADDED
File without changes
src/anomaly_model.py ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ anomaly_model.py
3
+ -----------------
4
+ Isolation Forest based anomaly detector for conveyor / crane motor sensor
5
+ streams (motor temperature, vibration, current draw, belt speed). This
6
+ powers the "Predictive Maintenance" tab -- flags abnormal equipment
7
+ behaviour before it causes an unplanned stoppage, which is exactly the kind
8
+ of workload Daifuku's intralogistics platforms (e.g. AS/RS, sorters, AGVs)
9
+ generate continuously in production.
10
+ """
11
+
12
+ from dataclasses import dataclass
13
+
14
+ import joblib
15
+ import numpy as np
16
+ from sklearn.ensemble import IsolationForest
17
+ from sklearn.preprocessing import StandardScaler
18
+
19
+ FEATURES = ["motor_temp_c", "vibration_mm_s", "current_amps", "belt_speed_mps"]
20
+
21
+
22
+ @dataclass
23
+ class AnomalyResult:
24
+ is_anomaly: bool
25
+ anomaly_score: float # higher = more anomalous, roughly in [0, 1]
26
+ raw_score: float
27
+
28
+
29
+ def build_model(contamination: float = 0.1, seed: int = 42) -> IsolationForest:
30
+ return IsolationForest(
31
+ n_estimators=200,
32
+ contamination=contamination,
33
+ random_state=seed,
34
+ )
35
+
36
+
37
+ def score_reading(model: IsolationForest, scaler: StandardScaler, reading: dict) -> AnomalyResult:
38
+ x = np.array([[reading[f] for f in FEATURES]])
39
+ x_scaled = scaler.transform(x)
40
+ raw = model.decision_function(x_scaled)[0] # higher = more normal
41
+ pred = model.predict(x_scaled)[0] # 1 = normal, -1 = anomaly
42
+ # squash raw decision_function (~[-0.5, 0.5]) into a 0-1 "anomaly score"
43
+ anomaly_score = float(np.clip(0.5 - raw, 0, 1))
44
+ return AnomalyResult(is_anomaly=(pred == -1), anomaly_score=anomaly_score, raw_score=float(raw))
45
+
46
+
47
+ def save_artifacts(model, scaler, model_path: str, scaler_path: str):
48
+ joblib.dump(model, model_path)
49
+ joblib.dump(scaler, scaler_path)
50
+
51
+
52
+ def load_artifacts(model_path: str, scaler_path: str):
53
+ return joblib.load(model_path), joblib.load(scaler_path)
src/data_generation.py ADDED
@@ -0,0 +1,222 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ data_generation.py
3
+ -------------------
4
+ Generates the synthetic datasets used to train/evaluate the two ML models
5
+ that power the Smart Warehouse AI Assistant:
6
+
7
+ 1. Intent classifier -> routes free-text queries into warehouse-ops intents
8
+ 2. Anomaly detector -> flags abnormal conveyor/AGV sensor readings
9
+
10
+ All data is synthetically generated with templates + randomised slots so the
11
+ project is fully self-contained and reproducible (no external datasets or
12
+ scraping required). A fixed random seed keeps results reproducible.
13
+ """
14
+
15
+ import random
16
+ import numpy as np
17
+ import pandas as pd
18
+
19
+ RANDOM_SEED = 42
20
+
21
+
22
+ # --------------------------------------------------------------------------
23
+ # 1. INTENT CLASSIFICATION DATA
24
+ # --------------------------------------------------------------------------
25
+
26
+ INTENT_TEMPLATES = {
27
+ "inventory_check": [
28
+ "How many units of {sku} are in {zone}?",
29
+ "What is the current stock level for {sku}?",
30
+ "Check inventory count for {sku} in {zone}",
31
+ "Do we have enough {sku} to fulfill 200 units?",
32
+ "Show me the on-hand quantity of {sku}",
33
+ "Is {sku} in stock at {zone}?",
34
+ "Give me stock levels across all zones for {sku}",
35
+ "How much inventory is left for {sku}?",
36
+ ],
37
+ "order_status": [
38
+ "What's the status of order {order_id}?",
39
+ "Has order {order_id} shipped yet?",
40
+ "Track order {order_id} for me",
41
+ "Is order {order_id} delayed?",
42
+ "When will order {order_id} be delivered?",
43
+ "Show the fulfillment status of {order_id}",
44
+ "Why hasn't order {order_id} left the dock yet?",
45
+ ],
46
+ "equipment_maintenance": [
47
+ "The conveyor belt in {zone} is making noise",
48
+ "Crane {equip_id} reported a fault code",
49
+ "Schedule maintenance for {equip_id}",
50
+ "{equip_id} motor temperature seems high",
51
+ "The sorter in {zone} keeps jamming",
52
+ "Report vibration issue on {equip_id}",
53
+ "Belt {equip_id} stopped unexpectedly, please check",
54
+ "Log a breakdown for {equip_id} in {zone}",
55
+ ],
56
+ "agv_navigation": [
57
+ "Route {equip_id} to picking station {station}",
58
+ "Send AGV {equip_id} to {zone}",
59
+ "Why is {equip_id} stuck near {zone}?",
60
+ "Reassign {equip_id} to charging station",
61
+ "What is the current location of {equip_id}?",
62
+ "Redirect {equip_id} around the blocked aisle in {zone}",
63
+ ],
64
+ "picking_optimization": [
65
+ "What's the fastest picking route for order {order_id}?",
66
+ "Optimize the pick path for {zone}",
67
+ "Should we batch pick these orders together?",
68
+ "Suggest a wave picking plan for {zone}",
69
+ "How can we reduce travel time for pickers in {zone}?",
70
+ "Recommend a picking strategy for high-velocity SKUs",
71
+ ],
72
+ "safety_incident": [
73
+ "A forklift near-miss was reported in {zone}",
74
+ "Log a safety incident involving {equip_id}",
75
+ "There was a near collision between {equip_id} and a pedestrian in {zone}",
76
+ "File an incident report for {zone}",
77
+ "A worker slipped near {equip_id}, please log it",
78
+ "Report unsafe pallet stacking in {zone}",
79
+ ],
80
+ "system_status": [
81
+ "Is {equip_id} operational?",
82
+ "What is the uptime for {equip_id} today?",
83
+ "Check system health for {zone}",
84
+ "Are all cranes online in {zone}?",
85
+ "Give me the current status of the WMS integration",
86
+ "Is the sorter in {zone} running normally?",
87
+ ],
88
+ "general_faq": [
89
+ "What is a WMS?",
90
+ "Explain how an AS/RS works",
91
+ "What's the difference between AGV and AMR?",
92
+ "What is cycle counting?",
93
+ "How does goods-to-person picking work?",
94
+ "What KPIs matter most in warehouse automation?",
95
+ "What is predictive maintenance?",
96
+ "How do sortation systems decide where to route a parcel?",
97
+ ],
98
+ }
99
+
100
+ ZONES = ["Zone A", "Zone B", "Zone C", "Zone D", "the mezzanine", "the receiving dock"]
101
+ EQUIP_IDS = ["AGV-07", "AGV-12", "Crane-03", "Sorter-02", "Conveyor-14", "AMR-21", "Crane-05"]
102
+ STATIONS = ["3", "5", "7", "12"]
103
+
104
+
105
+ def _rand_sku():
106
+ return f"SKU-{random.randint(1000, 9999)}"
107
+
108
+
109
+ def _rand_order():
110
+ return f"#{random.randint(10000, 99999)}"
111
+
112
+
113
+ def generate_intent_dataset(n_per_intent: int = 45, seed: int = RANDOM_SEED) -> pd.DataFrame:
114
+ """Generate a labelled (text, intent) dataset by sampling + slot-filling templates."""
115
+ rng = random.Random(seed)
116
+ rows = []
117
+ for intent, templates in INTENT_TEMPLATES.items():
118
+ for _ in range(n_per_intent):
119
+ template = rng.choice(templates)
120
+ text = template.format(
121
+ sku=_rand_sku(),
122
+ order_id=_rand_order(),
123
+ zone=rng.choice(ZONES),
124
+ equip_id=rng.choice(EQUIP_IDS),
125
+ station=rng.choice(STATIONS),
126
+ )
127
+ rows.append({"text": text, "intent": intent})
128
+ df = pd.DataFrame(rows)
129
+ df = df.sample(frac=1.0, random_state=seed).reset_index(drop=True)
130
+ return df
131
+
132
+
133
+ # --------------------------------------------------------------------------
134
+ # 2. INVENTORY / ORDERS DATA (used by the Inventory & Task Query tab)
135
+ # --------------------------------------------------------------------------
136
+
137
+ def generate_inventory_db(n_skus: int = 60, seed: int = RANDOM_SEED) -> pd.DataFrame:
138
+ rng = np.random.default_rng(seed)
139
+ categories = ["Electronics", "Apparel", "Automotive Parts", "Food & Beverage", "Household"]
140
+ zones = ["Zone A", "Zone B", "Zone C", "Zone D"]
141
+ rows = []
142
+ for i in range(n_skus):
143
+ sku = f"SKU-{1000 + i}"
144
+ rows.append({
145
+ "sku": sku,
146
+ "description": f"{rng.choice(categories)} item {1000 + i}",
147
+ "category": rng.choice(categories),
148
+ "zone": rng.choice(zones),
149
+ "on_hand_units": int(rng.integers(0, 2000)),
150
+ "reorder_point": int(rng.integers(50, 300)),
151
+ "unit_cost_jpy": int(rng.integers(200, 15000)),
152
+ })
153
+ return pd.DataFrame(rows)
154
+
155
+
156
+ def generate_orders_db(n_orders: int = 80, seed: int = RANDOM_SEED) -> pd.DataFrame:
157
+ rng = np.random.default_rng(seed)
158
+ statuses = ["Received", "Picking", "Packed", "Shipped", "Delayed"]
159
+ weights = [0.15, 0.25, 0.2, 0.3, 0.1]
160
+ rows = []
161
+ for i in range(n_orders):
162
+ order_id = f"#{10000 + i}"
163
+ rows.append({
164
+ "order_id": order_id,
165
+ "status": rng.choice(statuses, p=weights),
166
+ "num_lines": int(rng.integers(1, 25)),
167
+ "priority": rng.choice(["Standard", "Express", "Same-Day"], p=[0.6, 0.3, 0.1]),
168
+ "zone": rng.choice(["Zone A", "Zone B", "Zone C", "Zone D"]),
169
+ })
170
+ return pd.DataFrame(rows)
171
+
172
+
173
+ # --------------------------------------------------------------------------
174
+ # 3. SENSOR DATA FOR ANOMALY DETECTION (predictive maintenance)
175
+ # --------------------------------------------------------------------------
176
+
177
+ def generate_sensor_dataset(n_normal: int = 900, n_anomaly: int = 100, seed: int = RANDOM_SEED) -> pd.DataFrame:
178
+ """
179
+ Synthetic conveyor/crane motor sensor readings.
180
+ Features: motor_temp_c, vibration_mm_s, current_amps, belt_speed_mps
181
+ Label: 1 = anomaly (bearing wear / misalignment / overload pattern), 0 = normal
182
+ """
183
+ rng = np.random.default_rng(seed)
184
+
185
+ normal = pd.DataFrame({
186
+ "motor_temp_c": rng.normal(55, 4, n_normal).clip(35, 75),
187
+ "vibration_mm_s": rng.normal(2.2, 0.5, n_normal).clip(0.2, 5),
188
+ "current_amps": rng.normal(12, 1.5, n_normal).clip(5, 20),
189
+ "belt_speed_mps": rng.normal(1.5, 0.15, n_normal).clip(0.8, 2.2),
190
+ "label": 0,
191
+ })
192
+
193
+ # Anomalies: elevated temp + vibration + current, reduced/erratic belt speed
194
+ anomaly = pd.DataFrame({
195
+ "motor_temp_c": rng.normal(78, 6, n_anomaly).clip(65, 100),
196
+ "vibration_mm_s": rng.normal(5.5, 1.2, n_anomaly).clip(3.5, 10),
197
+ "current_amps": rng.normal(19, 2.5, n_anomaly).clip(14, 28),
198
+ "belt_speed_mps": rng.normal(0.9, 0.3, n_anomaly).clip(0.1, 1.6),
199
+ "label": 1,
200
+ })
201
+
202
+ df = pd.concat([normal, anomaly], ignore_index=True)
203
+ df = df.sample(frac=1.0, random_state=seed).reset_index(drop=True)
204
+ return df
205
+
206
+
207
+ # --------------------------------------------------------------------------
208
+ # 4. RETRIEVAL EVALUATION SET (query -> expected KB doc id)
209
+ # --------------------------------------------------------------------------
210
+
211
+ RETRIEVAL_EVAL_SET = [
212
+ ("How does an AS/RS crane retrieve a pallet?", "asrs_overview"),
213
+ ("What's the difference between an AGV and an AMR?", "agv_amr_overview"),
214
+ ("What does a WMS integrate with?", "wms_overview"),
215
+ ("Why would a sorter jam?", "conveyor_sorting"),
216
+ ("What is batch picking?", "picking_strategies"),
217
+ ("How can we predict a motor failure before it happens?", "predictive_maintenance"),
218
+ ("What should I do after a near-miss with a forklift?", "safety_protocol"),
219
+ ("How do we keep inventory counts accurate?", "inventory_accuracy"),
220
+ ("What KPIs should a warehouse manager track?", "kpi_overview"),
221
+ ("How can automated warehouses save energy?", "energy_efficiency"),
222
+ ]
src/intent_model.py ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ intent_model.py
3
+ ----------------
4
+ TF-IDF + Logistic Regression intent classifier that routes free-text
5
+ warehouse queries into one of 8 operational intents. Chosen deliberately
6
+ over a heavier transformer classifier: it trains in <1s, needs no GPU/
7
+ internet on Spaces startup, and reaches high accuracy on this
8
+ template-generated-but-linguistically-varied dataset -- a good example of
9
+ picking the right-sized model for the job rather than defaulting to the
10
+ biggest one.
11
+ """
12
+
13
+ from dataclasses import dataclass
14
+
15
+ import joblib
16
+ from sklearn.feature_extraction.text import TfidfVectorizer
17
+ from sklearn.linear_model import LogisticRegression
18
+ from sklearn.pipeline import Pipeline
19
+
20
+
21
+ @dataclass
22
+ class IntentPrediction:
23
+ intent: str
24
+ confidence: float
25
+
26
+
27
+ INTENT_DESCRIPTIONS = {
28
+ "inventory_check": "Inventory / stock level lookup",
29
+ "order_status": "Order status / tracking",
30
+ "equipment_maintenance": "Equipment fault / maintenance request",
31
+ "agv_navigation": "AGV / AMR routing & navigation",
32
+ "picking_optimization": "Picking route / strategy optimization",
33
+ "safety_incident": "Safety incident reporting",
34
+ "system_status": "Equipment / system status check",
35
+ "general_faq": "General warehouse automation question",
36
+ }
37
+
38
+
39
+ def build_pipeline() -> Pipeline:
40
+ return Pipeline([
41
+ ("tfidf", TfidfVectorizer(ngram_range=(1, 2), min_df=1, stop_words="english")),
42
+ ("clf", LogisticRegression(max_iter=1000, C=8.0)),
43
+ ])
44
+
45
+
46
+ def predict(pipeline: Pipeline, text: str) -> IntentPrediction:
47
+ probs = pipeline.predict_proba([text])[0]
48
+ classes = pipeline.classes_
49
+ best_idx = probs.argmax()
50
+ return IntentPrediction(intent=classes[best_idx], confidence=float(probs[best_idx]))
51
+
52
+
53
+ def load_pipeline(path: str) -> Pipeline:
54
+ return joblib.load(path)
55
+
56
+
57
+ def save_pipeline(pipeline: Pipeline, path: str):
58
+ joblib.dump(pipeline, path)
src/inventory_db.py ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ inventory_db.py
3
+ ----------------
4
+ Very small "NL -> structured query" layer over the synthetic inventory and
5
+ orders tables. It uses the intent classifier's output plus simple regex
6
+ slot extraction (SKU codes, order IDs, zone names) to filter the
7
+ in-memory DataFrames -- a lightweight stand-in for the kind of
8
+ WMS/WCS query interface a production assistant would call as a tool.
9
+ """
10
+
11
+ import re
12
+
13
+ import pandas as pd
14
+
15
+ SKU_RE = re.compile(r"SKU-\d{3,4}", re.IGNORECASE)
16
+ ORDER_RE = re.compile(r"#\d{4,6}")
17
+ ZONE_RE = re.compile(r"zone [a-d]", re.IGNORECASE)
18
+
19
+
20
+ def extract_sku(text: str):
21
+ m = SKU_RE.search(text)
22
+ return m.group(0).upper() if m else None
23
+
24
+
25
+ def extract_order_id(text: str):
26
+ m = ORDER_RE.search(text)
27
+ return m.group(0) if m else None
28
+
29
+
30
+ def extract_zone(text: str):
31
+ m = ZONE_RE.search(text)
32
+ return m.group(0).title() if m else None
33
+
34
+
35
+ def query_inventory(inventory_df: pd.DataFrame, text: str) -> pd.DataFrame:
36
+ sku = extract_sku(text)
37
+ zone = extract_zone(text)
38
+ df = inventory_df.copy()
39
+ if sku:
40
+ df = df[df["sku"].str.upper() == sku]
41
+ if zone:
42
+ df = df[df["zone"].str.lower() == zone.lower()]
43
+ if df.empty and not sku and not zone:
44
+ # no specific filters recognised -> show low-stock items as a useful default
45
+ df = inventory_df[inventory_df["on_hand_units"] <= inventory_df["reorder_point"]]
46
+ return df.reset_index(drop=True)
47
+
48
+
49
+ def query_orders(orders_df: pd.DataFrame, text: str) -> pd.DataFrame:
50
+ order_id = extract_order_id(text)
51
+ zone = extract_zone(text)
52
+ df = orders_df.copy()
53
+ if order_id:
54
+ df = df[df["order_id"] == order_id]
55
+ elif zone:
56
+ df = df[df["zone"].str.lower() == zone.lower()]
57
+ elif "delay" in text.lower():
58
+ df = df[df["status"] == "Delayed"]
59
+ return df.reset_index(drop=True)
src/knowledge_base.py ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ knowledge_base.py
3
+ ------------------
4
+ A small in-house knowledge base describing generic intralogistics / smart
5
+ warehouse concepts (ASRS, AGV/AMR, WMS, conveyor sorting, safety, picking
6
+ strategy). This is original written content (not scraped from any vendor
7
+ site) used purely as grounding context for the Retrieval-Augmented
8
+ Generation (RAG) pipeline that powers the AI Assistant tab.
9
+
10
+ Each entry has:
11
+ id - short unique key
12
+ title - human readable title
13
+ text - the passage used for retrieval + generation grounding
14
+ category - tag used for the retrieval evaluation set
15
+ """
16
+
17
+ KNOWLEDGE_BASE = [
18
+ {
19
+ "id": "asrs_overview",
20
+ "title": "Automated Storage & Retrieval Systems (AS/RS)",
21
+ "category": "equipment",
22
+ "text": (
23
+ "An Automated Storage and Retrieval System (AS/RS) uses stacker "
24
+ "cranes, shuttles, or mini-load systems to automatically place "
25
+ "and retrieve pallets, totes, or cartons from high-density "
26
+ "racking. AS/RS units are typically monitored for crane cycle "
27
+ "time, load/unload faults, and rail or lift motor temperature. "
28
+ "When a crane reports a fault code, the standard response is to "
29
+ "pause the aisle, dispatch a technician, and reroute retrieval "
30
+ "jobs to an adjacent aisle if one is available."
31
+ ),
32
+ },
33
+ {
34
+ "id": "agv_amr_overview",
35
+ "title": "AGVs and Autonomous Mobile Robots (AMR)",
36
+ "category": "equipment",
37
+ "text": (
38
+ "Automated Guided Vehicles (AGV) follow fixed paths such as "
39
+ "magnetic tape or wires, while Autonomous Mobile Robots (AMR) "
40
+ "navigate dynamically using LiDAR and SLAM mapping. Both are "
41
+ "used to move totes between picking stations, buffer zones, and "
42
+ "packing lines. Fleet management software assigns tasks based "
43
+ "on battery level, current queue length, and distance to the "
44
+ "target station. A vehicle blocked for more than a defined "
45
+ "timeout is automatically re-routed and flagged for review."
46
+ ),
47
+ },
48
+ {
49
+ "id": "wms_overview",
50
+ "title": "Warehouse Management System (WMS)",
51
+ "category": "software",
52
+ "text": (
53
+ "A Warehouse Management System (WMS) coordinates inbound "
54
+ "receiving, put-away, inventory tracking, order picking, "
55
+ "packing, and outbound shipping. It integrates with a "
56
+ "Warehouse Control System (WCS) that talks directly to "
57
+ "conveyors, sorters, and AS/RS controllers in real time. Key "
58
+ "WMS metrics include inventory accuracy, order cycle time, and "
59
+ "pick rate (lines picked per hour)."
60
+ ),
61
+ },
62
+ {
63
+ "id": "conveyor_sorting",
64
+ "title": "Conveyor and Sortation Systems",
65
+ "category": "equipment",
66
+ "text": (
67
+ "Sortation systems such as cross-belt, tilt-tray, or shoe "
68
+ "sorters route totes and parcels to the correct chute based on "
69
+ "barcode or RFID reads. Conveyor health is typically monitored "
70
+ "through motor current, belt speed, and vibration sensors. A "
71
+ "sudden rise in motor temperature combined with increased "
72
+ "vibration usually indicates bearing wear or belt misalignment "
73
+ "and should trigger a maintenance work order before a jam or "
74
+ "unplanned stoppage occurs."
75
+ ),
76
+ },
77
+ {
78
+ "id": "picking_strategies",
79
+ "title": "Order Picking Strategies",
80
+ "category": "process",
81
+ "text": (
82
+ "Common picking strategies include discrete picking (one order "
83
+ "at a time), batch picking (multiple orders in one pass), zone "
84
+ "picking (pickers assigned to fixed areas), and wave picking "
85
+ "(orders released in scheduled waves aligned with shipping "
86
+ "cutoffs). Goods-to-person systems, where an AS/RS or AMR "
87
+ "brings inventory to a stationary operator, generally reduce "
88
+ "walking time and increase pick rate compared to person-to-goods "
89
+ "picking."
90
+ ),
91
+ },
92
+ {
93
+ "id": "predictive_maintenance",
94
+ "title": "Predictive Maintenance in Warehouse Equipment",
95
+ "category": "maintenance",
96
+ "text": (
97
+ "Predictive maintenance uses sensor data such as motor "
98
+ "temperature, vibration amplitude, and current draw to detect "
99
+ "abnormal equipment behaviour before a breakdown occurs. "
100
+ "Machine-learning models such as Isolation Forest or "
101
+ "autoencoders are commonly trained on historical sensor "
102
+ "readings to flag anomalies. Catching a deviation early lets "
103
+ "a technician schedule maintenance during a planned downtime "
104
+ "window instead of reacting to an unplanned line stoppage."
105
+ ),
106
+ },
107
+ {
108
+ "id": "safety_protocol",
109
+ "title": "Warehouse Safety Protocols",
110
+ "category": "safety",
111
+ "text": (
112
+ "Safety protocols in automated warehouses cover pedestrian "
113
+ "separation from AGV/AMR traffic lanes, lockout-tagout (LOTO) "
114
+ "procedures before entering an AS/RS aisle, and near-miss "
115
+ "incident reporting. Any near-miss or safety incident should be "
116
+ "logged immediately with the location, equipment involved, and "
117
+ "a brief description, and forwarded to the site safety officer "
118
+ "the same shift."
119
+ ),
120
+ },
121
+ {
122
+ "id": "inventory_accuracy",
123
+ "title": "Inventory Accuracy and Cycle Counting",
124
+ "category": "process",
125
+ "text": (
126
+ "Inventory accuracy is usually maintained through cycle "
127
+ "counting, where a subset of SKUs or storage locations is "
128
+ "counted on a rolling schedule rather than a single annual "
129
+ "count. Discrepancies between system quantity and physical "
130
+ "quantity above a defined tolerance trigger a recount and, if "
131
+ "confirmed, an inventory adjustment transaction in the WMS."
132
+ ),
133
+ },
134
+ {
135
+ "id": "kpi_overview",
136
+ "title": "Core Warehouse KPIs",
137
+ "category": "process",
138
+ "text": (
139
+ "Frequently tracked warehouse KPIs include order accuracy, "
140
+ "on-time shipment rate, dock-to-stock time, pick rate (lines "
141
+ "per hour), equipment uptime, and inventory turns. Automation "
142
+ "projects are typically justified using expected improvements "
143
+ "in throughput, labour cost per order, and space utilisation."
144
+ ),
145
+ },
146
+ {
147
+ "id": "energy_efficiency",
148
+ "title": "Energy Efficiency in Automated Warehouses",
149
+ "category": "sustainability",
150
+ "text": (
151
+ "Energy use in automated warehouses can be reduced through "
152
+ "regenerative braking on AS/RS cranes and conveyors, "
153
+ "variable-frequency drives on motors that scale power to load, "
154
+ "and scheduling high-throughput operations to avoid peak "
155
+ "electricity tariff windows."
156
+ ),
157
+ },
158
+ ]
src/llm_client.py ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ llm_client.py
3
+ -------------
4
+ Wraps a hosted LLM (via huggingface_hub's InferenceClient, using HF's
5
+ serverless Inference Providers) to answer warehouse-operations questions,
6
+ grounded with context retrieved from the local knowledge base (simple RAG).
7
+
8
+ Design notes
9
+ ------------
10
+ * Reads the HF token from the `HF_TOKEN` environment variable, which should
11
+ be added as a Space "secret" when deployed (Settings -> Variables and
12
+ secrets). The public demo also works without a token: it falls back to a
13
+ deterministic, still-useful extractive answer built from the retrieved
14
+ knowledge-base passages, so the Space never shows a broken demo.
15
+ * The model name is configurable via `LLM_MODEL_ID` (defaults to a small,
16
+ fast, freely-hostable instruct model).
17
+ """
18
+
19
+ import os
20
+ import time
21
+ from dataclasses import dataclass
22
+ from typing import List
23
+
24
+ from src.retriever import KBRetriever, RetrievedDoc
25
+
26
+ DEFAULT_MODEL_ID = os.environ.get("LLM_MODEL_ID", "Qwen/Qwen2.5-7B-Instruct")
27
+
28
+ SYSTEM_PROMPT = (
29
+ "You are the Smart Warehouse AI Assistant, a helpful operations copilot "
30
+ "for a large automated distribution center (conveyors, AS/RS, AGVs/AMRs, "
31
+ "sortation, and a WMS). Answer concisely and practically, in the tone of "
32
+ "an experienced warehouse operations engineer. Use the provided CONTEXT "
33
+ "when relevant, and say so plainly if the question is outside the "
34
+ "context. Prefer short paragraphs or bullet points over long prose."
35
+ )
36
+
37
+
38
+ @dataclass
39
+ class AssistantResponse:
40
+ answer: str
41
+ used_llm: bool
42
+ sources: List[RetrievedDoc]
43
+ latency_s: float
44
+ model_id: str
45
+
46
+
47
+ def _extractive_fallback(query: str, sources: List[RetrievedDoc]) -> str:
48
+ """Deterministic answer used when no HF token / API call fails, so the
49
+ Space always returns something useful instead of an error."""
50
+ if not sources:
51
+ return (
52
+ "I don't have grounded context for that yet. Try asking about "
53
+ "inventory, order status, equipment maintenance, AGV routing, "
54
+ "picking strategy, safety incidents, or general warehouse "
55
+ "automation concepts."
56
+ )
57
+ lead = sources[0]
58
+ bullets = "\n".join(f"- **{s.title}**: {s.text}" for s in sources)
59
+ return (
60
+ f"(Offline / no LLM API key configured -- showing retrieved "
61
+ f"knowledge instead of a generated answer.)\n\n"
62
+ f"Based on **{lead.title}**, here's the relevant information:\n\n{bullets}"
63
+ )
64
+
65
+
66
+ def answer_query(
67
+ query: str,
68
+ retriever: KBRetriever,
69
+ k: int = 2,
70
+ model_id: str = DEFAULT_MODEL_ID,
71
+ max_tokens: int = 350,
72
+ ) -> AssistantResponse:
73
+ start = time.time()
74
+ sources = retriever.retrieve(query, k=k)
75
+ context_block = "\n\n".join(f"[{s.title}]\n{s.text}" for s in sources)
76
+
77
+ hf_token = os.environ.get("HF_TOKEN")
78
+
79
+ if not hf_token:
80
+ answer = _extractive_fallback(query, sources)
81
+ return AssistantResponse(
82
+ answer=answer,
83
+ used_llm=False,
84
+ sources=sources,
85
+ latency_s=time.time() - start,
86
+ model_id="extractive-fallback",
87
+ )
88
+
89
+ try:
90
+ from huggingface_hub import InferenceClient
91
+
92
+ client = InferenceClient(model=model_id, token=hf_token)
93
+ messages = [
94
+ {"role": "system", "content": SYSTEM_PROMPT},
95
+ {
96
+ "role": "user",
97
+ "content": f"CONTEXT:\n{context_block}\n\nQUESTION: {query}",
98
+ },
99
+ ]
100
+ completion = client.chat_completion(messages=messages, max_tokens=max_tokens, temperature=0.3)
101
+ text = completion.choices[0].message.content
102
+ return AssistantResponse(
103
+ answer=text,
104
+ used_llm=True,
105
+ sources=sources,
106
+ latency_s=time.time() - start,
107
+ model_id=model_id,
108
+ )
109
+ except Exception as e: # noqa: BLE001 -- deliberately broad: any API/network issue -> fallback
110
+ answer = _extractive_fallback(query, sources)
111
+ answer += f"\n\n_(LLM call failed: {type(e).__name__}. Showing retrieval-only answer.)_"
112
+ return AssistantResponse(
113
+ answer=answer,
114
+ used_llm=False,
115
+ sources=sources,
116
+ latency_s=time.time() - start,
117
+ model_id="extractive-fallback",
118
+ )
src/retriever.py ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ retriever.py
3
+ ------------
4
+ Lightweight TF-IDF + cosine-similarity retriever used to ground the LLM's
5
+ answers in the warehouse knowledge base (simple RAG pipeline). Kept
6
+ dependency-light (scikit-learn only) so it trains instantly and runs fast
7
+ on the free CPU tier of Hugging Face Spaces.
8
+ """
9
+
10
+ from dataclasses import dataclass
11
+ from typing import List
12
+
13
+ import joblib
14
+ import numpy as np
15
+ from sklearn.feature_extraction.text import TfidfVectorizer
16
+ from sklearn.metrics.pairwise import cosine_similarity
17
+
18
+ from src.knowledge_base import KNOWLEDGE_BASE
19
+
20
+
21
+ @dataclass
22
+ class RetrievedDoc:
23
+ id: str
24
+ title: str
25
+ text: str
26
+ score: float
27
+
28
+
29
+ class KBRetriever:
30
+ def __init__(self):
31
+ self.vectorizer = TfidfVectorizer(stop_words="english", ngram_range=(1, 2))
32
+ self.doc_ids = [d["id"] for d in KNOWLEDGE_BASE]
33
+ self.docs = {d["id"]: d for d in KNOWLEDGE_BASE}
34
+ corpus = [d["title"] + ". " + d["text"] for d in KNOWLEDGE_BASE]
35
+ self.doc_matrix = self.vectorizer.fit_transform(corpus)
36
+
37
+ def retrieve(self, query: str, k: int = 2) -> List[RetrievedDoc]:
38
+ q_vec = self.vectorizer.transform([query])
39
+ sims = cosine_similarity(q_vec, self.doc_matrix).flatten()
40
+ top_idx = np.argsort(sims)[::-1][:k]
41
+ results = []
42
+ for idx in top_idx:
43
+ doc_id = self.doc_ids[idx]
44
+ d = self.docs[doc_id]
45
+ results.append(RetrievedDoc(id=doc_id, title=d["title"], text=d["text"], score=float(sims[idx])))
46
+ return results
47
+
48
+ def save(self, path: str):
49
+ joblib.dump(self.vectorizer, path)
50
+
51
+ @staticmethod
52
+ def top1_id(query: str, retriever: "KBRetriever") -> str:
53
+ return retriever.retrieve(query, k=1)[0].id