|
15 | 15 | AMBER=RGBColor(0xF5,0x9E,0x0B); INK=RGBColor(0x16,0x1B,0x26); GREY=RGBColor(0x5B,0x63,0x72) |
16 | 16 | LIGHT=RGBColor(0xF5,0xF8,0xFC); WHITE=RGBColor(0xFF,0xFF,0xFF); LINE=RGBColor(0xE2,0xE8,0xF0) |
17 | 17 | VIOLET=RGBColor(0x7C,0x3A,0xED) |
18 | | -VERSION="v42"; VERSION_DATE="1 July 2026" |
| 18 | +VERSION="v43"; VERSION_DATE="3 July 2026" |
19 | 19 | # ─── EDIT PER COURSE ───────────────────────────────────────────── |
20 | 20 | TITLE = "Agentic AI Automation with n8n" # <<Course Title>> |
21 | 21 | COURSE_CODE = "TGS-2023035977" # <<Course Code, e.g. TGS-XXXXXXXXXX>> |
@@ -276,26 +276,23 @@ def brk(kind,dur,color): |
276 | 276 | "See labs/n8n-installation/docker-compose.yml in the course repo."],kicker="GET READY") |
277 | 277 | # --- n8n Cloud Account Login Details --- |
278 | 278 | _s=slide(); head(_s,"n8n Account Login Details",kicker="YOUR LOGIN · CLOUD INSTANCE") |
279 | | -rect(_s,Inches(0.85),Inches(1.85),Inches(11.6),Inches(0.5),RGBColor(0xEB,0xF4,0xFF)) |
280 | | -txt(_s,Inches(1.05),Inches(1.89),Inches(2.2),Inches(0.44),[[("Workspace URL",13,BLUE,True)]],anchor=MSO_ANCHOR.MIDDLE) |
281 | | -txt(_s,Inches(3.3),Inches(1.89),Inches(9.0),Inches(0.44),[[("http://n8n.srv923061.hstgr.cloud:5678",14,INK,False)]],anchor=MSO_ANCHOR.MIDDLE) |
282 | | -rect(_s,Inches(0.85),Inches(2.43),Inches(11.6),Inches(0.5),RGBColor(0xEB,0xF4,0xFF)) |
283 | | -txt(_s,Inches(1.05),Inches(2.47),Inches(2.2),Inches(0.44),[[("Password",13,BLUE,True)]],anchor=MSO_ANCHOR.MIDDLE) |
284 | | -txt(_s,Inches(3.3),Inches(2.47),Inches(3.5),Inches(0.44),[[("Tertiary@888",14,TEAL,True)]],anchor=MSO_ANCHOR.MIDDLE) |
285 | | -txt(_s,Inches(6.9),Inches(2.47),Inches(4.8),Inches(0.44),[[("(same for all accounts)",12,GREY,False)]],anchor=MSO_ANCHOR.MIDDLE) |
286 | | -_RH=Inches(0.355); _TY=Inches(3.08) |
287 | | -for _ci in range(2): |
288 | | - _bx=Inches(0.85)+_ci*Inches(6.0); _cw=Inches(5.7); _nw=Inches(0.55) |
289 | | - _ew=_cw-_nw-Inches(0.1) |
290 | | - rect(_s,_bx,_TY,_cw,_RH,BLUE) |
291 | | - txt(_s,_bx+Inches(0.05),_TY,_nw,_RH,[[("No.",11,WHITE,True)]],align=PP_ALIGN.CENTER,anchor=MSO_ANCHOR.MIDDLE) |
292 | | - txt(_s,_bx+_nw+Inches(0.1),_TY,_ew,_RH,[[("Email",11,WHITE,True)]],anchor=MSO_ANCHOR.MIDDLE) |
293 | | - for _ri in range(10): |
294 | | - _no=_ci*10+_ri+1; _em=f"n8n{1000+_no:04d}@tertiaryinfotech.com" |
295 | | - _ry=_TY+_RH*(_ri+1) |
296 | | - rect(_s,_bx,_ry,_cw,_RH,LIGHT if _ri%2==0 else WHITE,line=LINE) |
297 | | - txt(_s,_bx+Inches(0.05),_ry,_nw,_RH,[[(str(_no),11,INK,True)]],align=PP_ALIGN.CENTER,anchor=MSO_ANCHOR.MIDDLE) |
298 | | - txt(_s,_bx+_nw+Inches(0.1),_ry,_ew,_RH,[[(_em,11,INK,False)]],anchor=MSO_ANCHOR.MIDDLE) |
| 279 | +_TY=Inches(1.78); _RH=Inches(0.247); _bx=Inches(0.85) |
| 280 | +_wNo=Inches(0.55); _wUrl=Inches(4.95); _wEm=Inches(4.35); _wPw=Inches(1.75) |
| 281 | +_cols=[(_bx,_wNo,"No.",PP_ALIGN.CENTER), |
| 282 | + (_bx+_wNo+Inches(0.1),_wUrl-Inches(0.1),"Workspace URL",PP_ALIGN.LEFT), |
| 283 | + (_bx+_wNo+_wUrl+Inches(0.1),_wEm-Inches(0.1),"Login (Email)",PP_ALIGN.LEFT), |
| 284 | + (_bx+_wNo+_wUrl+_wEm+Inches(0.1),_wPw-Inches(0.1),"Password",PP_ALIGN.LEFT)] |
| 285 | +rect(_s,_bx,_TY,_wNo+_wUrl+_wEm+_wPw,_RH,BLUE) |
| 286 | +for _cx,_cw2,_lbl,_al in _cols: |
| 287 | + txt(_s,_cx,_TY,_cw2,_RH,[[(_lbl,11,WHITE,True)]],align=_al,anchor=MSO_ANCHOR.MIDDLE) |
| 288 | +for _ri in range(20): |
| 289 | + _no=_ri+1; _acct=f"n8n{1000+_no:04d}" |
| 290 | + _ry=_TY+_RH*(_ri+1) |
| 291 | + rect(_s,_bx,_ry,_wNo+_wUrl+_wEm+_wPw,_RH,LIGHT if _ri%2==0 else WHITE,line=LINE) |
| 292 | + for (_cx,_cw2,_lbl,_al),(_val,_c,_b) in zip(_cols, |
| 293 | + [(str(_no),INK,True),(f"https://{_acct}.app.n8n.cloud/signin",BLUE,False), |
| 294 | + (f"{_acct}@tertiaryinfotech.com",INK,False),("Tertiary@888",TEAL,False)]): |
| 295 | + txt(_s,_cx,_ry,_cw2,_RH,[[(_val,10,_c,_b)]],align=_al,anchor=MSO_ANCHOR.MIDDLE) |
299 | 296 | footer(_s) |
300 | 297 | content("Credential Setup",[ |
301 | 298 | "Add credentials once under Credentials → Add credential.", |
@@ -688,47 +685,47 @@ def activity_block(a): |
688 | 685 | (TEAL,"Supabase (pgvector)",["Postgres + vector extension","SQL table + match function","Self-host or hosted; great if you already use Postgres"]), |
689 | 686 | (BLUE,"Pinecone",["Fully managed SaaS","Just create an index (no schema)","Zero-ops, serverless, scales fast"]), |
690 | 687 | (VIOLET,"Qdrant",["Open-source vector DB","Run via Docker or Qdrant Cloud","Full control / self-hosted"])],kicker="ACT 7b · CHOOSE ONE") |
691 | | -content("One Embedding Model, One Dimension",[ |
692 | | - "All three stores ingest the same 20 brochures using OpenAI text-embedding-3-small.", |
693 | | - "That model outputs 1536-dimension vectors — the store's dimension MUST equal 1536.", |
694 | | - "Change the embedding model and the dimension changes too (e.g. -3-large = 3072).", |
| 688 | +content("Embedding Model Sets the Dimension",[ |
| 689 | + "Supabase & Qdrant flows embed with OpenAI text-embedding-3-small → 1536-dim vectors.", |
| 690 | + "The Pinecone flow & CX Agent embed with Google Gemini gemini-embedding-001 → 3072-dim.", |
| 691 | + "The store's dimension MUST equal the embedding model's output dimension.", |
695 | 692 | "Mismatched dimensions are the #1 cause of failed inserts."],kicker="DIMENSION RULE") |
696 | 693 | website_slide("Pinecone — Example Managed Store",IMG("courseware/assets/site-pinecone.png"), |
697 | | - ["Pinecone is a managed (cloud) vector database for RAG.","Free 'Starter' tier is enough for this lab.","Create an index: Dimensions = 1536, Metric = cosine."], |
| 694 | + ["Pinecone is a managed (cloud) vector database for RAG.","Free 'Starter' tier is enough for this lab.","Create an index: Dimensions = 3072 (Gemini), Metric = cosine."], |
698 | 695 | kicker="VECTOR DATABASE") |
699 | 696 |
|
700 | 697 | # ===== Activity 7b — Customer-support RAG agent for a training center ===== |
701 | 698 | activity_overview("ACT 7b","Activity 7b — Customer-Support RAG Agent (Cook & Bake Academy)", |
702 | 699 | "A cooking & bakery training center's website has a support chatbot. Ingest 20 course brochures from Google Drive into a vector database, then a CX Agent answers visitor questions about course duration, fees, location and schedule — grounded in the brochures.", |
703 | | - "Manual Trigger → Drive (list+download) → Split → Embeddings (OpenAI) → Vector Store | Website → Webhook → AI Agent + retriever → reply", |
704 | | - "manualTrigger, googleDrive, textSplitter, embeddingsOpenAi, vectorStore (Supabase/Pinecone/Qdrant), agent, webhook, respondToWebhook",kicker=K3) |
| 700 | + "Manual Trigger → Drive (list+download) → Split → Embeddings → Vector Store | Website → Webhook (POST) → AI Agent + retriever tool → Respond to Webhook", |
| 701 | + "manualTrigger, googleDrive, textSplitter, embeddings (OpenAI/Gemini), vectorStore (Supabase/Pinecone/Qdrant), agent, lmChatGoogleGemini, webhook, respondToWebhook",kicker=K3) |
705 | 702 | img_slide("Activity 7b — Ingestion Workflow",IMG("labs/activity7-rag/Activity7b-Pinecone-Upload.png"), |
706 | | - "Ingestion pattern (shown: Pinecone) — list & download brochures → split → embed (OpenAI 1536-d) → upsert. Same flow for Supabase & Qdrant.",kicker=K3) |
| 703 | + "Ingestion pattern (shown: Pinecone) — list & download brochures → whole-brochure split (1 brochure = 1 chunk) → embed (Gemini 3072-d) → upsert. Supabase & Qdrant use OpenAI 1536-d.",kicker=K3) |
707 | 704 | img_slide("Activity 7b — CX Agent Workflow",IMG("labs/activity7-rag/Activity7b-CX-Agent.png"), |
708 | | - "The answering agent: website webhook → retrieve from the vector store → respond to the chat widget",kicker=K3) |
| 705 | + "The answering agent: website webhook (POST) → AI Agent with Pinecone retriever tool + Gemini chat model → respond to the chat widget",kicker=K3) |
709 | 706 | website_slide("Cook & Bake Academy — Support Chatbot",IMG("labs/activity7-rag/Activity7b-website.png"), |
710 | 707 | ["A one-page training-center site with a floating chat widget.", |
711 | 708 | "Visitors ask about any course — duration, fee, location, schedule.", |
712 | 709 | "Answers are grounded in the 20 ingested brochures.", |
713 | 710 | "Set WEBHOOK_URL in script.js to your n8n CX Agent URL."],kicker="ACT 7b · THE WEBSITE") |
714 | 711 | for i,t in enumerate([ |
715 | 712 | "Upload the 20 course brochures (labs/activity7-rag/brochures/) to a Google Drive folder named 'Course Brochures'; copy the folder ID from the URL.", |
716 | | - "Choose one vector database — Supabase, Pinecone or Qdrant. All use OpenAI text-embedding-3-small (1536-dim); the store must match 1536.", |
| 713 | + "Choose one vector database — Supabase, Pinecone or Qdrant. Supabase/Qdrant use OpenAI text-embedding-3-small (1536-dim); Pinecone uses Google Gemini gemini-embedding-001 (3072-dim).", |
717 | 714 | "Supabase: create a project, enable pgvector, run the SQL to create the documents table + match_documents function, then add a Supabase credential.", |
718 | | - "Pinecone: create an index 'course-brochures' (Dimensions = 1536, Metric = cosine); add a Pinecone credential.", |
| 715 | + "Pinecone: create an index 'course-brochures' (Dimensions = 3072, Metric = cosine); add Pinecone + Google Gemini credentials. Upload & retrieval must use the SAME namespace (both default).", |
719 | 716 | "Qdrant: create a cluster (Qdrant Cloud) or run via Docker; create collection 'course-brochures' (size 1536, Cosine); add a Qdrant credential.", |
720 | | - "Import the matching ingestion workflow (Activity7b-Supabase / Pinecone / Qdrant-Upload.json). Set the Drive folder ID on 'List Brochures in Folder' and your OpenAI + Drive + DB credentials.", |
721 | | - "Click Execute workflow — it lists, downloads, splits, embeds and upserts ~30–60 vectors. Verify the rows / vectors appear in your DB.", |
722 | | - "Import Activity7b-CX-Agent.json. Point its retriever vector-store node at the same store you ingested into (same 1536-dim embeddings); add OpenAI + DB credentials.", |
723 | | - "Activate and copy the Webhook production URL. Set WEBHOOK_URL in website/script.js to it.", |
| 717 | + "Import the matching ingestion workflow (Activity7b-Supabase / Pinecone / Qdrant-Upload.json). Set the Drive folder ID on 'List Brochures in Folder' and your Drive + embeddings + DB credentials.", |
| 718 | + "Click Execute workflow. Pinecone keeps 1 brochure = 1 chunk (similar brochures confuse retrieval if split) → exactly 20 vectors; Supabase/Qdrant upsert ~30–60 chunks.", |
| 719 | + "Import Activity7b-CX-Agent.json. Point its Pinecone retriever tool at the same 'course-brochures' index — same Gemini embeddings (3072-dim) and same (default) namespace.", |
| 720 | + "Activate and copy the Webhook production URL (the webhook accepts POST and replies via Respond to Webhook). Set WEBHOOK_URL in website/script.js to it.", |
724 | 721 | "Open website/index.html, click the 💬 chat button, and ask 'How much is the sourdough course?'"],1): |
725 | 722 | step_slide(K3,"Activity 7b — Customer-Support RAG Agent (Cook & Bake Academy)",i,10,t) |
726 | 723 | test_slide("Activity 7b — Customer-Support RAG Agent (Cook & Bake Academy)","On the website chat widget ask 'How long is the French Pastry course?' or 'Where are you located?' — the chatbot answers grounded in the brochures retrieved from your vector database.",K3) |
727 | 724 | content("Vector Databases — Quick Comparison",[ |
728 | 725 | "Supabase (pgvector): Postgres + extension · SQL table & function · self-host or hosted · best if you already use Postgres.", |
729 | 726 | "Pinecone: managed SaaS · just create an index · zero-ops · scales fast.", |
730 | 727 | "Qdrant: open-source · Docker or Qdrant Cloud · full control / self-hosted.", |
731 | | - "All three store the same 1536-dim OpenAI embeddings — swap the store, keep the RAG flow."],kicker="ACT 7b · RECAP") |
| 728 | + "Match the store's dimension to the embedding model (OpenAI 1536 / Gemini 3072) — swap the store, keep the RAG flow."],kicker="ACT 7b · RECAP") |
732 | 729 | brk("Lunch Break","1 hour",AMBER) |
733 | 730 |
|
734 | 731 | # ---------- TOPIC 6: SECURITY ---------- |
|
0 commit comments