Skip to content

Commit 3580d99

Browse files
wierdvanderhaaramotl
authored andcommitted
Latest-Changes
1 parent 67b0f5a commit 3580d99

File tree

1 file changed

+115
-80
lines changed

1 file changed

+115
-80
lines changed

topic/chatbot/table-augmented-generation/workshop/telemetry-diagnostics-assistant.ipynb

Lines changed: 115 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -936,7 +936,24 @@
936936
" )\n",
937937
" return response.choices[0].message.content.strip()\n",
938938
" except Exception as e:\n",
939-
" return f\"⚠️ Failed to explain result: {e}\""
939+
" return f\"⚠️ Failed to explain result: {e}\"\n",
940+
"\n",
941+
"# 🧠 Use LLM to explain manual guidance in plain language\n",
942+
"def explain_manual_guidance(question, anomaly_text, emergency_text):\n",
943+
" try:\n",
944+
" context = f\"Anomaly Detection:\\n{anomaly_text}\\n\\nEmergency Protocol:\\n{emergency_text}\"\n",
945+
" response = openai_client.chat.completions.create(\n",
946+
" model=\"gpt-3.5-turbo\",\n",
947+
" messages=[\n",
948+
" {\"role\": \"system\", \"content\": \"You are a helpful assistant that explains machine manuals in plain language.\"},\n",
949+
" {\"role\": \"user\", \"content\": f\"The user asked: {question}\\n\\nHere is the relevant manual content:\\n\\n{context}\\n\\nPlease provide a clear answer based on the manual.\"}\n",
950+
" ],\n",
951+
" temperature=0.3,\n",
952+
" max_tokens=300\n",
953+
" )\n",
954+
" return response.choices[0].message.content.strip()\n",
955+
" except Exception as e:\n",
956+
" return f\"⚠️ Failed to generate manual-based explanation: {e}\""
940957
]
941958
},
942959
{
@@ -1146,39 +1163,40 @@
11461163
{
11471164
"cell_type": "code",
11481165
"execution_count": null,
1149-
"id": "a9d328af",
1166+
"id": "782359be",
11501167
"metadata": {},
11511168
"outputs": [],
11521169
"source": [
11531170
"def get_combined_answer(question):\n",
1154-
" # Step 1: Fetch table schemas dynamically\n",
1155-
" schema_motor = fetch_table_schema(\"motor_readings\")\n",
1156-
" schema_manual = fetch_table_schema(\"machine_manuals\")\n",
1157-
"\n",
1158-
" # Step 2: Analyze question to extract context\n",
1159-
" machine_id = extract_machine_id_from_query(question)\n",
1160-
" needs_manual = detect_manual_intent(question)\n",
1161-
"\n",
1162-
" # Step 3: Optionally load manual and extract anomaly/emergency info\n",
1163-
" manual_context = \"\"\n",
1164-
" anomaly_text, emergency_text = None, None\n",
1165-
" sql2 = None # placeholder for optional manual SQL\n",
1166-
"\n",
1167-
" if needs_manual and machine_id is not None:\n",
1168-
" manual = fetch_machine_manual(machine_id)\n",
1169-
" if manual:\n",
1170-
" anomaly_text, emergency_text = extract_anomaly_info(manual)\n",
1171-
" manual_context = f'''\n",
1171+
" try:\n",
1172+
" # Step 1: Fetch table schemas dynamically\n",
1173+
" schema_motor = fetch_table_schema(\"motor_readings\")\n",
1174+
" schema_manual = fetch_table_schema(\"machine_manuals\")\n",
1175+
"\n",
1176+
" # Step 2: Analyze question to extract context\n",
1177+
" machine_id = extract_machine_id_from_query(question)\n",
1178+
" needs_manual = detect_manual_intent(question)\n",
1179+
"\n",
1180+
" # Step 3: Optionally load manual and extract anomaly/emergency info\n",
1181+
" manual_context = \"\"\n",
1182+
" anomaly_text, emergency_text = None, None\n",
1183+
" sql2 = None # placeholder for optional manual SQL\n",
1184+
"\n",
1185+
" if needs_manual and machine_id is not None:\n",
1186+
" manual = fetch_machine_manual(machine_id)\n",
1187+
" if manual:\n",
1188+
" anomaly_text, emergency_text = extract_anomaly_info(manual)\n",
1189+
" manual_context = f'''\n",
11721190
"Manual Guidance for Machine {machine_id}:\n",
11731191
"--- Anomaly Detection ---\n",
11741192
"{anomaly_text}\n",
11751193
"--- Emergency Protocol ---\n",
11761194
"{emergency_text}\n",
11771195
"'''\n",
1178-
" sql2 = f\"SELECT manual FROM machine_manuals WHERE machine_id = {machine_id};\"\n",
1196+
" sql2 = f\"SELECT manual FROM machine_manuals WHERE machine_id = {machine_id};\"\n",
11791197
"\n",
1180-
" # Step 4: Build LLM prompt\n",
1181-
" prompt = f'''\n",
1198+
" # Step 4: Build LLM prompt\n",
1199+
" prompt = f'''\n",
11821200
"You are a CrateDB data assistant. Your job is to answer questions using telemetry data and machine manuals.\n",
11831201
"\n",
11841202
"Tables:\n",
@@ -1188,10 +1206,11 @@
11881206
"{manual_context}\n",
11891207
"\n",
11901208
"Instructions:\n",
1191-
"- For telemetry questions (e.g., performance metrics), generate SQL and explain the result.\n",
1209+
"- For telemetry questions (e.g., performance metrics), generate SQL that directly supports answering the user's question.\n",
1210+
" - If the question implies a condition (e.g., \"Is the machine overheating?\"), retrieve the most recent values and select only the relevant columns (e.g., temperature, timestamp).\n",
1211+
" - Prefer checking the condition using WHERE clauses when thresholds are known.\n",
11921212
"- For manual-related queries, summarize anomaly and emergency procedures using the context above.\n",
1193-
"- If the question involves conditions (e.g., overheating, excessive vibration), \n",
1194-
" retrieve **both telemetry and manual**. Compare telemetry values against safe thresholds.\n",
1213+
"- If the question involves conditions (e.g., overheating, excessive vibration), retrieve **both telemetry and manual**. Compare telemetry values against safe thresholds.\n",
11951214
"- Use the following format:\n",
11961215
"\n",
11971216
"---\n",
@@ -1206,78 +1225,75 @@
12061225
"<your explanation>\n",
12071226
"'''\n",
12081227
"\n",
1209-
" # Step 5: Query the LLM with the prompt and question\n",
1210-
" response = openai_client.chat.completions.create(\n",
1211-
" model=\"gpt-3.5-turbo\",\n",
1212-
" messages=[\n",
1213-
" {\"role\": \"system\", \"content\": \"You are a helpful assistant working with CrateDB telemetry and manuals.\"},\n",
1214-
" {\"role\": \"user\", \"content\": prompt + f\"\\n\\nUser question: {question}\"}\n",
1215-
" ],\n",
1216-
" temperature=0,\n",
1217-
" max_tokens=700\n",
1218-
" )\n",
1228+
" # Step 5: Query the LLM with the prompt and question\n",
1229+
" response = openai_client.chat.completions.create(\n",
1230+
" model=\"gpt-3.5-turbo\",\n",
1231+
" messages=[\n",
1232+
" {\"role\": \"system\", \"content\": \"You are a helpful assistant working with CrateDB telemetry and manuals.\"},\n",
1233+
" {\"role\": \"user\", \"content\": prompt + f\"\\n\\nUser question: {question}\"}\n",
1234+
" ],\n",
1235+
" temperature=0,\n",
1236+
" max_tokens=700\n",
1237+
" )\n",
12191238
"\n",
1220-
" output = response.choices[0].message.content.strip()\n",
1239+
" output = response.choices[0].message.content.strip()\n",
12211240
"\n",
1222-
" # Step 6: Parse and clean LLM output\n",
1223-
" parsed_sql1, parsed_sql2, answer = extract_sql_blocks(output)\n",
1224-
" sql1 = patch_cratedb_sql(parsed_sql1) if parsed_sql1 else None\n",
1225-
" sql2 = patch_cratedb_sql(parsed_sql2) if parsed_sql2 else sql2\n",
1241+
" # Step 6: Parse and clean LLM output\n",
1242+
" parsed_sql1, parsed_sql2, answer = extract_sql_blocks(output)\n",
1243+
" sql1 = patch_cratedb_sql(parsed_sql1) if parsed_sql1 else None\n",
1244+
" sql2 = patch_cratedb_sql(parsed_sql2) if parsed_sql2 else sql2\n",
12261245
"\n",
1227-
" # Step 7: Execute queries\n",
1228-
" df1, df2 = None, None\n",
1246+
" # Step 7: Execute queries\n",
1247+
" df1, df2 = None, None\n",
12291248
"\n",
1230-
" try:\n",
12311249
" if sql1:\n",
1232-
" df1 = pd.read_sql(sql1, con=engine)\n",
1233-
" except Exception as e:\n",
1234-
" print(\"❌ Failed to execute SQL 1:\", sql1)\n",
1235-
" print(e)\n",
1250+
" try:\n",
1251+
" df1 = pd.read_sql(sql1, con=engine)\n",
1252+
" except Exception as e:\n",
1253+
" print(\"❌ Failed to execute SQL 1:\", sql1)\n",
1254+
" print(e)\n",
12361255
"\n",
1237-
" try:\n",
12381256
" if sql2:\n",
1239-
" df2 = pd.read_sql(sql2, con=engine)\n",
1240-
" except Exception as e:\n",
1241-
" print(\"❌ Failed to execute SQL 2:\", sql2)\n",
1242-
" print(e)\n",
1257+
" try:\n",
1258+
" df2 = pd.read_sql(sql2, con=engine)\n",
1259+
" except Exception as e:\n",
1260+
" print(\"❌ Failed to execute SQL 2:\", sql2)\n",
1261+
" print(e)\n",
1262+
"\n",
1263+
" # ✅ Step 8: Construct final answer\n",
1264+
" if needs_manual and anomaly_text and emergency_text:\n",
1265+
" final_answer = explain_manual_guidance(question, anomaly_text, emergency_text)\n",
1266+
" elif df1 is not None and not df1.empty:\n",
1267+
" final_answer = explain_result_with_llm(question, df1)\n",
1268+
" else:\n",
1269+
" final_answer = answer or \"No answer could be generated.\"\n",
12431270
"\n",
1244-
" # Step 8: Construct final natural language explanation\n",
1245-
" if needs_manual and anomaly_text and emergency_text:\n",
1246-
" final_answer = f'''\n",
1247-
"📌 Manual Guidance for Machine {machine_id}\n",
1271+
" print(\"✅ Finished get_combined_answer\") # ✅ DEBUG\n",
1272+
" return sql1, sql2, df1, df2, final_answer\n",
12481273
"\n",
1249-
"--- Anomaly Detection ---\n",
1250-
"{anomaly_text}\n",
1251-
"\n",
1252-
"--- Emergency Protocol ---\n",
1253-
"{emergency_text}\n",
1254-
"'''.strip()\n",
1255-
" elif df1 is not None and not df1.empty:\n",
1256-
" final_answer = explain_result_with_llm(question, df1)\n",
1257-
" else:\n",
1258-
" final_answer = answer or \"No answer could be generated.\"\n",
1259-
"\n",
1260-
" return sql1, sql2, df1, df2, final_answer"
1274+
" except Exception as e:\n",
1275+
" print(\"❌ ERROR inside get_combined_answer:\", e)\n",
1276+
" return None"
12611277
]
12621278
},
12631279
{
12641280
"cell_type": "markdown",
1265-
"id": "cc65dc9e",
1281+
"id": "d26052c9",
12661282
"metadata": {},
12671283
"source": [
12681284
"### Ask a Question (Natural Language Interface)\n",
12691285
"\n",
12701286
"This is your main interaction point with the assistant. Just type in a natural language question, and the assistant will:\n",
1271-
"\t\tAnalyze your query\n",
1272-
"\t\tDecide if telemetry data or manual context is needed\n",
1273-
"\t\tGenerate and run SQL queries\n",
1274-
"\t\tExplain the results in plain language\n",
1275-
"\t\tOptionally summarize emergency protocols from manuals\n",
1287+
"- Analyze your query\n",
1288+
"- Decide if telemetry data or manual context is needed\n",
1289+
"- Generate and run SQL queries\n",
1290+
"- Explain the results in plain language\n",
1291+
"- Optionally summarize emergency protocols from manuals\n",
12761292
"\n",
12771293
"\n",
12781294
"Here are some example queries and what kind of answers you can expect:\n",
12791295
"\n",
1280-
"| 💬 Question | 🧠 Assistant Behavior |\n",
1296+
"| Question | Assistant Behavior |\n",
12811297
"|-----------------------------------------------------------------------------|----------------------------------------------------------------------------------|\n",
12821298
"| `What was the average temperature for machine 3 last week?` | Retrieves average temperature from telemetry and explains the result. |\n",
12831299
"| `Is machine 4 overheating?` | Checks the latest temperature and compares it with manual thresholds if present.|\n",
@@ -1289,10 +1305,12 @@
12891305
{
12901306
"cell_type": "code",
12911307
"execution_count": null,
1292-
"id": "c03bb3ca",
1308+
"id": "eb35d155",
12931309
"metadata": {},
12941310
"outputs": [],
12951311
"source": [
1312+
"from IPython.display import display, HTML\n",
1313+
"\n",
12961314
"# Ask a combined question\n",
12971315
"# Example questions:\n",
12981316
"# \n",
@@ -1303,7 +1321,7 @@
13031321
"# Show me the maintenance steps for machine 1.\n",
13041322
"\n",
13051323
"# question = \"Type your question here and push ▶️\"\n",
1306-
"question = \"Give me the max and min vibration for machine 6 when RPM > 1600\"\n",
1324+
"question = \"Is machine 4 overheating?\"\n",
13071325
"\n",
13081326
"sql1, sql2, df1, df2, final_answer = get_combined_answer(question)\n",
13091327
"\n",
@@ -1330,8 +1348,25 @@
13301348
"output.append(\"\\n🧾 Final Answer:\")\n",
13311349
"output.append(final_answer.strip() if final_answer else \"No answer returned.\")\n",
13321350
"\n",
1333-
"# Join and print once\n",
1334-
"print(\"\\n\".join(output))"
1351+
"# Join all parts of the output\n",
1352+
"joined_output = \"\\n\".join(output)\n",
1353+
"\n",
1354+
"# Display in dark theme box\n",
1355+
"display(HTML(f\"\"\"\n",
1356+
"<div style=\"\n",
1357+
" background-color: #1e1e1e;\n",
1358+
" color: #f0f0f0;\n",
1359+
" border: 1px solid #444;\n",
1360+
" padding: 16px;\n",
1361+
" border-radius: 6px;\n",
1362+
" white-space: pre-wrap;\n",
1363+
" font-family: 'Courier New', monospace;\n",
1364+
" font-size: 14px;\n",
1365+
" line-height: 1.6;\n",
1366+
"\">\n",
1367+
"{joined_output}\n",
1368+
"</div>\n",
1369+
"\"\"\"))"
13351370
]
13361371
},
13371372
{

0 commit comments

Comments
 (0)