├── .github
└── workflows
│ └── auto_add_to_project.yml
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── SECURITY.md
├── SESSION_RESOURCE.md
├── SUPPORT.md
├── img
├── azure-db-doodle.png
└── session-cover.png
└── session-delivery-resources
├── 1-cosmos-db-nosql
└── README.md
├── 2-postgres-rag
└── README.md
├── 3-azure-sql-ai-search
├── README.md
└── src
│ ├── AzureSQL_CogSearch_IntegratedVectorization.ipynb
│ ├── README.md
│ ├── customer_reviews.csv
│ ├── example.env
│ └── requirements.txt
└── README.md
/.github/workflows/auto_add_to_project.yml:
--------------------------------------------------------------------------------
1 | name: Add new issues to AI Tour GH Project
2 |
3 | on:
4 | issues:
5 | types:
6 | - opened
7 |
8 | jobs:
9 | add-to-project:
10 | name: Add issue to project
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/add-to-project@v1.0.2
14 | with:
15 | project-url: ${{ secrets.GH_PROJECT_URL }}
16 | github-token: ${{ secrets.ADD_TO_PROJECT }}
17 | label_issues:
18 | runs-on: ubuntu-latest
19 | permissions:
20 | issues: write
21 | steps:
22 | - run: gh issue edit "$NUMBER" --add-label "$LABELS"
23 | env:
24 | GH_TOKEN: ${{ secrets.ADD_TO_PROJECT }}
25 | GH_REPO: ${{ github.repository }}
26 | NUMBER: ${{ github.event.issue.number }}
27 | LABELS: Data
28 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Microsoft Open Source Code of Conduct
2 |
3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
4 |
5 | Resources:
6 |
7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Microsoft
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Next gen AI apps with databases at scale anywhere
2 |
3 | This repo is a companion to this session at Microsoft AI Tour, a worldwide tour of events.
4 |
5 | > Learn more about Microsoft AI Tour on the official website.
6 |
7 | 
8 |
9 | ## Session Description
10 |
11 | Introducing a new era of cloud databases that are designed and optimized for AI applications with hyperscale performance, built-in intelligence, Copilot assistants, integrated vector capabilities, and seamless integrations. Learn how to build and deploy intelligent applications with Azure Cosmos DB, Azure SQL Database, and Azure Database for PostgreSQL. Discover how this the Microsoft Intelligent Data Platform can transform your business applications with AI, simplify app development, extend your on-premises investments, and modernize your workloads for growth.
12 |
13 | ## Learning Outcomes
14 |
15 | - Understand how databases within the Microsoft Intelligent Data Platform empower developers to innovate with AI and make app development easy.
16 |
17 | - Learn how each database within the Microsoft Intelligent Data Platform is AI Ready, with built-in intelligence, Copilot assistants, integrated vector database, and Azure AI Search integration.
18 |
19 | - Learn how to build and deploy intelligent applications with Azure Cosmos DB, Azure SQL Database, and Azure Database for PostgreSQL.
20 |
21 | 
22 |
23 | ## Technology Used
24 |
25 | - Azure Cosmos DB for NoSQL
26 | - Azure Database for PostgresSQL
27 | - Azure SQL Database
28 |
29 |
30 | ## Additional Resources and Continued Learning
31 | Access the slides to this presentationn [here](https://aka.ms/AAs6qfn)
32 |
33 | You can find additional resources about the technologies used [here](./SESSION_RESOURCE.md).
34 |
35 | If you will present this talk, you can find the [trainer resources here](./session-delivery-resources/README.md).
36 |
37 | ## Content Owners
38 |
39 |
40 |
41 |
57 |
58 |
59 |
60 |
61 | ## Responsible AI
62 | Microsoft is committed to helping our customers use our AI products responsibly, sharing our learnings, and building trust-based partnerships through tools like Transparency Notes and Impact Assessments. Many of these resources can be found at [https://aka.ms/RAI](https://aka.ms/RAI). Microsoft’s approach to responsible AI is grounded in our AI principles of fairness, reliability and safety, privacy and security, inclusiveness, transparency, and accountability.
63 |
64 | Large-scale natural language, image, and speech models - like the ones used in this sample - can potentially behave in ways that are unfair, unreliable, or offensive, in turn causing harms. Please consult the [Azure OpenAI service Transparency note](https://learn.microsoft.com/legal/cognitive-services/openai/transparency-note?tabs=text) to be informed about risks and limitations.
65 |
66 | The recommended approach to mitigating these risks is to include a safety system in your architecture that can detect and prevent harmful behavior. [Azure AI Content Safety](https://learn.microsoft.com/azure/ai-services/content-safety/overview) provides an independent layer of protection, able to detect harmful user-generated and AI-generated content in applications and services. Azure AI Content Safety includes text and image APIs that allow you to detect material that is harmful. Within Azure AI Studio, the Content Safety service allows you to view, explore and try out sample code for detecting harmful content across different modalities. The following [quickstart documentation](https://learn.microsoft.com/azure/ai-services/content-safety/quickstart-text?tabs=visual-studio%2Clinux&pivots=programming-language-rest) guides you through making requests to the service.
67 |
68 | Another aspect to take into account is the overall application performance. With multi-modal and multi-models applications, we consider performance to mean that the system performs as you and your users expect, including not generating harmful outputs. It's important to assess the performance of your overall application using [Performance and Quality and Risk and Safety evaluators](https://learn.microsoft.com/azure/ai-studio/concepts/evaluation-metrics-built-in). You also have the ability to create and evaluate with [custom evaluators](https://learn.microsoft.com/azure/ai-studio/how-to/develop/evaluate-sdk#custom-evaluators).
69 |
70 | You can evaluate your AI application in your development environment using the [Azure AI Evaluation SDK](https://microsoft.github.io/promptflow/index.html). Given either a test dataset or a target, your generative AI application generations are quantitatively measured with built-in evaluators or custom evaluators of your choice. To get started with the azure ai evaluation sdk to evaluate your system, you can follow the [quickstart guide](https://learn.microsoft.com/azure/ai-studio/how-to/develop/flow-evaluate-sdk). Once you execute an evaluation run, you can [visualize the results in Azure AI Studio](https://learn.microsoft.com/azure/ai-studio/how-to/evaluate-flow-results).
71 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Security
4 |
5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet) and [Xamarin](https://github.com/xamarin).
6 |
7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/security.md/definition), please report it to us as described below.
8 |
9 | ## Reporting Security Issues
10 |
11 | **Please do not report security vulnerabilities through public GitHub issues.**
12 |
13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/security.md/msrc/create-report).
14 |
15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/security.md/msrc/pgp).
16 |
17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
18 |
19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
20 |
21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
22 | * Full paths of source file(s) related to the manifestation of the issue
23 | * The location of the affected source code (tag/branch/commit or direct URL)
24 | * Any special configuration required to reproduce the issue
25 | * Step-by-step instructions to reproduce the issue
26 | * Proof-of-concept or exploit code (if possible)
27 | * Impact of the issue, including how an attacker might exploit the issue
28 |
29 | This information will help us triage your report more quickly.
30 |
31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/security.md/msrc/bounty) page for more details about our active programs.
32 |
33 | ## Preferred Languages
34 |
35 | We prefer all communications to be in English.
36 |
37 | ## Policy
38 |
39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/security.md/cvd).
40 |
41 |
42 |
--------------------------------------------------------------------------------
/SESSION_RESOURCE.md:
--------------------------------------------------------------------------------
1 | # Resources: Power a new era of apps. At any scale. Anywhere.
2 |
3 | Below are session resources for the session "Power a new era of apps. At any scale. Anywhere." at Microsoft AI Tour.
4 |
5 | # Azure Cosmos DB
6 |
7 | [Try Azure Cosmos DB free of charge](https://aka.ms/aitour-data-cosmosdb-trycosmosdb)
8 |
9 | - No Credit Card Required
10 | - 6 APIs to choose from
11 | - Distributed data across 4 regions
12 | - Up to 10 GB of storage
13 |
14 | Signup for the [DiskANN Preview](https://aka.ms/aitour-data-cosmosdb-diskannpreview)
15 |
16 | ## Documentation
17 |
18 | - [Vector Search Announcements](https://aka.ms/aitour-data-cosmosdb-vectorsearchannouncements)
19 | - [Vector Search Documentation](https://aka.ms/aitour-data-cosmosdb-vectorsearch)
20 |
21 |
22 | ## Demos and Code Samples
23 |
24 | - [**Session Demo**: RAG on Azure Cosmos DB for NoSQL - Build a Copilot app using Azure Cosmos DB for NoSQL, Azure OpenAI Service, Azure App Service and Semantic Kernel](https://aka.ms/aitour-data-cosmosdb-demo)
25 | - [Cosmos DB AI Samples](https://aka.ms/aitour-data-cosmosdb-aisamples)
26 |
27 | # Azure Database for PostgreSQL
28 |
29 | [Try Azure Azure Database for PostgreSQL for free](https://aka.ms/trypostgresql)
30 |
31 | - **750 hours** of **Burstable B1MS** instance
32 | - **32 GB** storage / **32 GB** backup storage
33 |
34 | ## Documentation
35 |
36 | **AI with PostgreSQL**
37 | - [Enable and use pgvector on Azure Database for PostgreSQL](https://aka.ms/aitour-data-postgresql-pgvector)
38 | - [Azure AI extension on Azure Database for PostgreSQL](https://aka.ms/aitour-data-postgresql-azure-ai)
39 | - [Build AI Apps with Azure Database for PostgreSQL - Microsoft Learn](https://aka.ms/aitour-data-postgresql-build-ai-apps)
40 | - [GraphRAG Solution for Azure Database for PostgreSQL Blog](https://aka.ms/aitour-data-postgresql-graphrag-blog)
41 |
42 | **PostgreSQL Product Documentation**
43 | - [Azure Database for PostgreSQL - Flexible Server documentation](https://aka.ms/aitour-data-postgresql-docs)
44 | - [Migrate from PostgreSQL to Azure Database for PostgreSQL](https://aka.ms/aitour-data-postgresql-migration)
45 | - [Azure Database for PostgreSQL - Microsoft Learn](https://aka.ms/aitour-data-postgresql-learn)
46 |
47 | ## Videos from the Azure Database for PostgreSQL Team
48 |
49 | - [Product Demo: Azure PostgreSQL for your AI app's backend](https://aka.ms/aitour-data-postgresql-product-demo)
50 |
51 | ## Demos and Code Samples
52 |
53 | - [**Session Demo**: RAG on PostgreSQL - Hybrid search on the PostgreSQL database table, using the pgvector extension](https://aka.ms/aitour-data-postgresql-demo)
54 | - [GraphRAG Solution for Azure Database for PostgreSQL Repo](https://aka.ms/aitour-data-postgresql-graphrag-repo)
55 |
56 | # Azure SQL Database
57 |
58 | [Try Azure SQL Database free of charge](https://aka.ms/aitour-data-azuresql-freedboffer)
59 |
60 | - 100,000 vCore seconds compute every month
61 | - 32 GB of storage every month
62 |
63 | Sign up for the [Vector private preview](https://aka.ms/aitour-data-azuresql-vector-eap)
64 |
65 | ## Documentation
66 |
67 | - [Azure SQL AI Docs](https://aka.ms/aitour-data-azuresql-aidocs)
68 |
69 | ## Videos from the Azure SQL Team
70 | - [Data Exposed](https://aka.ms/aitour-data-azuresql-dataexposed)
71 | - [Azure SQL Essentials](https://aka.ms/aitour-data-azuresql-essentials)
72 |
73 | ## Demos and Code Samples
74 | - [End to End RAG](https://aka.ms/aitour-data-azuresql-e2e)
75 | - [SQL AI Samples](https://aka.ms/aitour-data-azuresql-aisamples)
76 |
--------------------------------------------------------------------------------
/SUPPORT.md:
--------------------------------------------------------------------------------
1 | # TODO: The maintainer of this repo has not yet edited this file
2 |
3 | **REPO OWNER**: Do you want Customer Service & Support (CSS) support for this product/project?
4 |
5 | - **No CSS support:** Fill out this template with information about how to file issues and get help.
6 | - **Yes CSS support:** Fill out an intake form at [aka.ms/onboardsupport](https://aka.ms/onboardsupport). CSS will work with/help you to determine next steps.
7 | - **Not sure?** Fill out an intake as though the answer were "Yes". CSS will help you decide.
8 |
9 | *Then remove this first heading from this SUPPORT.MD file before publishing your repo.*
10 |
11 | # Support
12 |
13 | ## How to file issues and get help
14 |
15 | This project uses GitHub Issues to track bugs and feature requests. Please search the existing
16 | issues before filing new issues to avoid duplicates. For new issues, file your bug or
17 | feature request as a new Issue.
18 |
19 | For help and questions about using this project, please **REPO MAINTAINER: INSERT INSTRUCTIONS HERE
20 | FOR HOW TO ENGAGE REPO OWNERS OR COMMUNITY FOR HELP. COULD BE A STACK OVERFLOW TAG OR OTHER
21 | CHANNEL. WHERE WILL YOU HELP PEOPLE?**.
22 |
23 | ## Microsoft Support Policy
24 |
25 | Support for this **PROJECT or PRODUCT** is limited to the resources listed above.
26 |
--------------------------------------------------------------------------------
/img/azure-db-doodle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/aitour-ai-apps-with-scalable-database/2e97730df9e551ebbeb837e0a84cb2bd909c3d3c/img/azure-db-doodle.png
--------------------------------------------------------------------------------
/img/session-cover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/aitour-ai-apps-with-scalable-database/2e97730df9e551ebbeb837e0a84cb2bd909c3d3c/img/session-cover.png
--------------------------------------------------------------------------------
/session-delivery-resources/1-cosmos-db-nosql/README.md:
--------------------------------------------------------------------------------
1 | # Demo: Retrieval Augmented Generation (RAG) with Azure Cosmos DB for NoSQL
2 |
3 | Demo shows a multi-tenant, multi-user, Generative-AI RAG Pattern application using Azure Cosmos DB for NoSQL with its new vector database capabilities with Azure OpenAI Service on Azure App Service.
4 |
5 |
6 | Services Used:
7 | - Azure Cosmos DB for NoSQL
8 | - Azure OpenAI Service
9 | - Azure App Service
10 |
11 |
12 | ## Setup:
13 |
14 | ### 1. Clone repo and configure for RAG
15 |
16 | [Clone the repo](https://github.com/AzureCosmosDB/cosmosdb-nosql-copilot).
17 |
18 | **To enable rag in the application**: Clone the repo, and open up the `src > services > ChatService.cs` file.
19 |
20 | Replace it with the following:
21 |
22 | ```
23 | using Cosmos.Copilot.Models;
24 | using Microsoft.ML.Tokenizers;
25 |
26 | namespace Cosmos.Copilot.Services;
27 |
28 | public class ChatService
29 | {
30 |
31 | private readonly CosmosDbService _cosmosDbService;
32 | private readonly OpenAiService _openAiService;
33 | private readonly SemanticKernelService _semanticKernelService;
34 | private readonly int _maxConversationTokens;
35 | private readonly double _cacheSimilarityScore;
36 | private readonly int _productMaxResults;
37 |
38 | public ChatService(CosmosDbService cosmosDbService, OpenAiService openAiService, SemanticKernelService semanticKernelService, string maxConversationTokens, string cacheSimilarityScore, string productMaxResults)
39 | {
40 | _cosmosDbService = cosmosDbService;
41 | _openAiService = openAiService;
42 | _semanticKernelService = semanticKernelService;
43 |
44 | _maxConversationTokens = Int32.TryParse(maxConversationTokens, out _maxConversationTokens) ? _maxConversationTokens : 100;
45 | _cacheSimilarityScore = Double.TryParse(cacheSimilarityScore, out _cacheSimilarityScore) ? _cacheSimilarityScore : 0.99;
46 | _productMaxResults = Int32.TryParse(productMaxResults, out _productMaxResults) ? _productMaxResults: 10;
47 | }
48 |
49 | public async Task InitializeAsync()
50 | {
51 | await _cosmosDbService.LoadProductDataAsync();
52 | }
53 |
54 | ///
55 | /// Returns list of chat session ids and names for left-hand nav to bind to (display Name and ChatSessionId as hidden)
56 | ///
57 | public async Task> GetAllChatSessionsAsync(string tenantId, string userId)
58 | {
59 | return await _cosmosDbService.GetSessionsAsync(tenantId,userId);
60 | }
61 |
62 | ///
63 | /// Returns the chat messages to display on the main web page when the user selects a chat from the left-hand nav
64 | ///
65 | public async Task> GetChatSessionMessagesAsync(string tenantId, string userId,string? sessionId)
66 | {
67 | ArgumentNullException.ThrowIfNull(tenantId);
68 | ArgumentNullException.ThrowIfNull(userId);
69 | ArgumentNullException.ThrowIfNull(sessionId);
70 |
71 | return await _cosmosDbService.GetSessionMessagesAsync(tenantId,userId, sessionId); ;
72 | }
73 |
74 | ///
75 | /// User creates a new Chat Session.
76 | ///
77 | public async Task CreateNewChatSessionAsync(string tenantId, string userId)
78 | {
79 |
80 | Session session = new(tenantId, userId);
81 |
82 | await _cosmosDbService.InsertSessionAsync(tenantId, userId,session);
83 |
84 | return session;
85 |
86 | }
87 |
88 | ///
89 | /// Rename the Chat Session from "New Chat" to the summary provided by OpenAI
90 | ///
91 | public async Task RenameChatSessionAsync(string tenantId, string userId,string? sessionId, string newChatSessionName)
92 | {
93 | ArgumentNullException.ThrowIfNull(tenantId);
94 | ArgumentNullException.ThrowIfNull(userId);
95 | ArgumentNullException.ThrowIfNull(sessionId);
96 |
97 | Session session = await _cosmosDbService.GetSessionAsync(tenantId, userId,sessionId);
98 |
99 | session.Name = newChatSessionName;
100 |
101 | await _cosmosDbService.UpdateSessionAsync(tenantId, userId,session);
102 | }
103 |
104 | ///
105 | /// User deletes a chat session
106 | ///
107 | public async Task DeleteChatSessionAsync(string tenantId, string userId, string? sessionId)
108 | {
109 | ArgumentNullException.ThrowIfNull(tenantId);
110 | ArgumentNullException.ThrowIfNull(userId);
111 | ArgumentNullException.ThrowIfNull(sessionId);
112 |
113 | await _cosmosDbService.DeleteSessionAndMessagesAsync( tenantId, userId, sessionId);
114 | }
115 |
116 | ///
117 | /// Get a completion for a user prompt from Azure OpenAi Service
118 | /// This is the main LLM Workflow for the Chat Service
119 | ///
120 | public async Task GetChatCompletionAsync(string tenantId, string userId, string? sessionId, string promptText)
121 | {
122 | ArgumentNullException.ThrowIfNull(tenantId);
123 | ArgumentNullException.ThrowIfNull(userId);
124 | ArgumentNullException.ThrowIfNull(sessionId);
125 |
126 | //Create a message object for the new User Prompt and calculate the tokens for the prompt
127 | Message chatMessage = await CreateChatMessageAsync(tenantId, userId, sessionId, promptText);
128 |
129 | //Grab context window from the conversation history up to the maximum configured tokens
130 | List contextWindow = await GetChatSessionContextWindow( tenantId, userId, sessionId);
131 |
132 | //Perform a cache search to see if this prompt has already been used in the same context window as this conversation
133 | (string cachePrompts, float[] cacheVectors, string cacheResponse) = await GetCacheAsync(contextWindow);
134 |
135 | //Cache hit, return the cached completion
136 | if (!string.IsNullOrEmpty(cacheResponse))
137 | {
138 | chatMessage.Completion = cacheResponse;
139 | chatMessage.Completion += " (cached response)";
140 | chatMessage.CompletionTokens = 0;
141 |
142 | //Persist the prompt/completion, update the session tokens
143 | await UpdateSessionAndMessage( tenantId, userId, sessionId, chatMessage);
144 |
145 | return chatMessage;
146 | }
147 | else //Cache miss, send to OpenAI to generate a completion
148 | {
149 | //Generate embeddings for the user prompt
150 | float[] promptVectors = await _openAiService.GetEmbeddingsAsync(promptText);
151 |
152 | //These functions are just for simple completions without RAG Pattern
153 | //Generate a completion and tokens used with current context window (just user prompts, no vector search results, non RAG Pattern)
154 | //(chatMessage.Completion, chatMessage.CompletionTokens) = await _openAiService.GetChatCompletionAsync(sessionId, contextWindow);
155 | //(chatMessage.Completion, chatMessage.CompletionTokens) = await _semanticKernelService.GetChatCompletionAsync(sessionId, contextWindow);
156 |
157 | //These functions are for doing RAG Pattern completions
158 | //Uncomment SearchProductsAsync() and one of the GetRagCompletionAsync() functions to do RAG Pattern completions
159 | //Perform vector search for products
160 | List products = await _cosmosDbService.SearchProductsAsync(promptVectors, _productMaxResults);
161 |
162 | //Generate a completion and tokens used from current context window and vector search results
163 | (chatMessage.Completion, chatMessage.CompletionTokens) = await _openAiService.GetRagCompletionAsync(sessionId, contextWindow, products);
164 | //(chatMessage.Completion, chatMessage.CompletionTokens) = await _semanticKernelService.GetRagCompletionAsync(sessionId, contextWindow, products);
165 |
166 | //Cache the prompts in the current context window and their vectors with the generated completion
167 | await CachePutAsync(cachePrompts, cacheVectors, chatMessage.Completion);
168 | }
169 |
170 |
171 | //Persist the prompt/completion, update the session tokens
172 | await UpdateSessionAndMessage( tenantId, userId, sessionId, chatMessage);
173 |
174 | return chatMessage;
175 | }
176 |
177 | ///
178 | /// Get the context window for this conversation. This is used in cache search as well as generating completions
179 | ///
180 | private async Task> GetChatSessionContextWindow(string tenantId, string userId, string sessionId)
181 | {
182 | ArgumentNullException.ThrowIfNull(tenantId);
183 | ArgumentNullException.ThrowIfNull(userId);
184 | ArgumentNullException.ThrowIfNull(sessionId);
185 |
186 | int? tokensUsed = 0;
187 |
188 | List allMessages = await _cosmosDbService.GetSessionMessagesAsync(tenantId, userId, sessionId);
189 | List contextWindow = new List();
190 |
191 | //Start at the end of the list and work backwards
192 | //This includes the latest user prompt which is already cached
193 | for (int i = allMessages.Count - 1; i >= 0; i--)
194 | {
195 | tokensUsed += allMessages[i].PromptTokens + allMessages[i].CompletionTokens;
196 |
197 | if (tokensUsed > _maxConversationTokens)
198 | break;
199 |
200 | contextWindow.Add(allMessages[i]);
201 | }
202 |
203 | //Invert the chat messages to put back into chronological order
204 | contextWindow = contextWindow.Reverse().ToList();
205 |
206 | return contextWindow;
207 |
208 | }
209 |
210 | ///
211 | /// Use OpenAI to summarize the conversation to give it a relevant name on the web page
212 | ///
213 | public async Task SummarizeChatSessionNameAsync(string tenantId, string userId, string? sessionId)
214 | {
215 | ArgumentNullException.ThrowIfNull(tenantId);
216 | ArgumentNullException.ThrowIfNull(userId);
217 | ArgumentNullException.ThrowIfNull(sessionId);
218 |
219 | //Get the messages for the session
220 | List messages = await _cosmosDbService.GetSessionMessagesAsync( tenantId, userId, sessionId);
221 |
222 | //Create a conversation string from the messages
223 | string conversationText = string.Join(" ", messages.Select(m => m.Prompt + " " + m.Completion));
224 |
225 | //Send to OpenAI to summarize the conversation
226 | string completionText = await _openAiService.SummarizeAsync(sessionId, conversationText);
227 | //string completionText = await _semanticKernelService.SummarizeConversationAsync(conversationText);
228 |
229 | await RenameChatSessionAsync( tenantId, userId, sessionId, completionText);
230 |
231 | return completionText;
232 | }
233 |
234 | ///
235 | /// Add user prompt to a new chat session message object, calculate token count for prompt text.
236 | ///
237 | private async Task CreateChatMessageAsync(string tenantId, string userId, string sessionId, string promptText)
238 | {
239 | ArgumentNullException.ThrowIfNull(tenantId);
240 | ArgumentNullException.ThrowIfNull(userId);
241 | ArgumentNullException.ThrowIfNull(sessionId);
242 |
243 | //Calculate tokens for the user prompt message.
244 | int promptTokens = GetTokens(promptText);
245 |
246 | //Create a new message object.
247 | Message chatMessage = new(tenantId, userId, sessionId, promptTokens, promptText, "");
248 |
249 | await _cosmosDbService.InsertMessageAsync(tenantId, userId, chatMessage);
250 |
251 | return chatMessage;
252 | }
253 |
254 | ///
255 | /// Update session with user prompt and completion tokens and update the cache
256 | ///
257 | private async Task UpdateSessionAndMessage(string tenantId, string userId, string sessionId, Message chatMessage)
258 | {
259 | ArgumentNullException.ThrowIfNull(tenantId);
260 | ArgumentNullException.ThrowIfNull(userId);
261 | ArgumentNullException.ThrowIfNull(sessionId);
262 |
263 | //Update the tokens used in the session
264 | Session session = await _cosmosDbService.GetSessionAsync(tenantId, userId, sessionId);
265 | session.Tokens += chatMessage.PromptTokens + chatMessage.CompletionTokens;
266 |
267 | //Insert new message and Update session in a transaction
268 | await _cosmosDbService.UpsertSessionBatchAsync( tenantId, userId, session, chatMessage);
269 |
270 | }
271 |
272 | ///
273 | /// Calculate the number of tokens from the user prompt
274 | ///
275 | private int GetTokens(string userPrompt)
276 | {
277 |
278 | Tokenizer _tokenizer = Tokenizer.CreateTiktokenForModel("gpt-3.5-turbo");
279 |
280 | return _tokenizer.CountTokens(userPrompt);
281 |
282 | }
283 |
284 | ///
285 | /// Query the semantic cache with user prompt vectors for the current context window in this conversation
286 | ///
287 | private async Task<(string cachePrompts, float[] cacheVectors, string cacheResponse)> GetCacheAsync(List contextWindow)
288 | {
289 | //Grab the user prompts for the context window
290 | string prompts = string.Join(Environment.NewLine, contextWindow.Select(m => m.Prompt));
291 |
292 | //Get the embeddings for the user prompts
293 | float[] vectors = await _openAiService.GetEmbeddingsAsync(prompts);
294 | //float[] vectors = await _semanticKernelService.GetEmbeddingsAsync(prompts);
295 |
296 | //Check the cache for similar vectors
297 | string response = await _cosmosDbService.GetCacheAsync(vectors, _cacheSimilarityScore);
298 |
299 | return (prompts, vectors, response);
300 | }
301 |
302 | ///
303 | /// Cache the last generated completion with user prompt vectors for the current context window in this conversation
304 | ///
305 | private async Task CachePutAsync(string cachePrompts, float[] cacheVectors, string generatedCompletion)
306 | {
307 | //Include the user prompts text to view. They are not used in the cache search.
308 | CacheItem cacheItem = new(cacheVectors, cachePrompts, generatedCompletion);
309 |
310 | //Put the prompts, vectors and completion into the cache
311 | await _cosmosDbService.CachePutAsync(cacheItem);
312 | }
313 |
314 | ///
315 | /// Clear the Semantic Cache
316 | ///
317 | public async Task ClearCacheAsync()
318 | {
319 | await _cosmosDbService.CacheClearAsync();
320 | }
321 | }
322 | ```
323 |
324 | ### 1. Deploy
325 | Follow the instructions to deploy the sample in the [demo repository](https://github.com/AzureCosmosDB/cosmosdb-nosql-copilot?tab=readme-ov-file#instructions). It instructs you to clone the repo and then use `azd up` to begin deployment. Either complete this step in the Azure Cloud Shell or use the [Azure CLI]() to complete on a local machine. Be sure to make the change in the previous step to enable RAG.
326 |
327 | You should now have the following resources deployed:
328 | - Resource group named `CosmosNoSQLRAGDemo`
329 | - Azure App Service .NET Web App named `web-XXXX`.
330 | - App Service plan named `plan-XXXX`
331 | - Managed Identity named `ua-id-XXXX`
332 | - Azure Cosmos DB for NoSQL Account named `cosmos-XXXX` with the feature `Vector Search for NoSQL API (preview)` set to `On`
333 | - Database named `cosmoscopilotdb` with containers `cache`, `chat`, and `products`
334 | - Azure Open AI Service named `openai-XXXX` with
335 | - Deployed GPT 4o model named `gpt-4o`
336 | - Deployed `text-embedding-3-large` model named `text-3-large`
337 |
338 | ## Presenting the Demo
339 |
340 | ### Setup
341 | It's recommended to have 2 tabs open in your browser for this demo:
342 | - Azure Portal OR cosmos.azure.com Cosmos DB data explorer with the `cosmoscopilotdb` database selected.
343 | - Deployed chat app
344 |
345 | **(Optional)** Try some prompts to generate data for the database.
346 |
347 | **Note**: If you have been testing previously, you may want to clear the cache (top right of the app, or delete all the documents in the cache container)
348 |
349 | ### 1. Describe the scenario (optionally, show the generated data in Data Explorer):
350 |
351 | ```
352 | Let's look at a full end to end RAG scenario with Azure Cosmos DB for NoSQL. It's is a multitenant and multiuser app that is a knowledge base for biking products.
353 | We're using vector capabilities in 2 distinct ways: For vector search using the RAG pattern and also as a semantic cache to store previous answers. Let's learn more about the cache.
354 |
355 | Generating completions from an LLM are computationally expensive in time and cost. These metrics increase as the amount of text increases, especially when applying the RAG pattern.We can create a cache for this type of solution to reduce both cost and latency.
356 |
357 | So instead of immediately sending the prompt to the completions model, we vectorize the query and check the cache first. If there's a match the response will be very fast. If not, the query will be sent to the completions model.
358 |
359 | We're applying RAG here by including a product catalog for a bike shop as part of the generation. Users can ask questions about bikes and biking accessories in the catalog. The user's prompt is vectorized and used to execute a vector search against the vectorized product data in the catalog. The most relevant items are returned then passed to the LLM to generate a response.
360 |
361 | Let's explore how they work in the chat app.
362 |
363 | ```
364 |
365 | ### 2. Ask a Question in the Chat
366 |
367 | `Let's check what's in our product catalog`
368 |
369 | - Start with `What bikes do you have?`, wait for response
370 | - Switch to data explorer
371 |
372 | ```
373 | Behind the scenes 3 things happened:
374 | 1. We stored the session history in the chat container (show chat container, you can ask Query Advisor/Copilot for Cosmos DB to show the most recent entries).
375 |
376 | 2. We checked the cache to see if the same question has been asked. The vector query compares the vectors in the cache and returns the best result above the similarity score filter. The similarity score is set to .99, so the queries must be very similar. If there's no match, the query is sent to the completion model. (show cache container)
377 |
378 | 3. We finally vectorize the prompt and store it along with the completion.
379 | ```
380 |
381 | ### 3. RAG Walkthrough
382 | - Return to app
383 |
384 | ```
385 | Let's see if there's products other than bikes in here
386 | ```
387 |
388 | - Ask `What products do you have?`, wait for response
389 |
390 | ```
391 | While it's great to see what's available. Applying the RAG pattern would be especially helpful here If I wanted to make a purchase here with a specified budget, the completions model could give me some recommendations. Let's try it.
392 | ```
393 |
394 | - Ask `I'd like to get a bike and 2 pairs of bike shorts. I have a budget of 2000`
395 | - Then ask `Is there a more expensive bike I could purchase within my $2000 budget?`
396 | - Feel free to try other combinations.
397 |
398 | ### 3. Semantic Cache
399 |
400 | ```
401 | We mentioned before that our queries are saved in the cache, let's take a look at how fast our response is to a previous question.
402 | ```
403 |
404 | - Ask a previous question like `What bikes do you have?` (try to make it as similar as possible to a previous question, similarity score is .99!)
405 | - Wait for response, the reply will end with the note `(cached response)`
406 |
407 | ### 4. Wrap up
408 |
409 | ```
410 | With Azure Cosmos DB, we're able to build a efficient intelligent app that revolutionizes the way we interact with data. With clever techniques like RAG and semantic caching we can streamline interactions with data and embed a layer of smart, responsive features.
411 | ```
--------------------------------------------------------------------------------
/session-delivery-resources/2-postgres-rag/README.md:
--------------------------------------------------------------------------------
1 | # DEMO 2: Retrieval Augmented Generation with Azure Database for PostgreSQL
2 |
--------------------------------------------------------------------------------
/session-delivery-resources/3-azure-sql-ai-search/README.md:
--------------------------------------------------------------------------------
1 | # DEMO 3: Retrieval Augmented Generation with Azure SQL Database and Azure AI Search
2 |
3 | The demo showcases the seamless integration of Azure SQL Database as a Platform-as-a-Service (PaaS) offering within the Microsoft Intelligent Data Platform. It demonstrates the utilization of Azure SQL Database as a data source in Azure AI Studio, along with the application of a RAG pattern using Azure OpenAI Service to analyze customer product reviews.
4 |
5 | Services Used:
6 | - Azure SQL Server and Database
7 | - Azure AI Search
8 | - Azure OpenAI Service
9 |
10 | ## Setup
11 |
12 | ### 1. Deploy
13 |
14 | Click on the the Deploy to Azure button below to deploy services needed. Alternatively you can run the Bicep file.
15 |
16 | You should now have the following resources deployed:
17 | - Resource group names `rg-aitour-databases`
18 | - Azure SQL server named `aitour-dbserver-XXXXX` and a database named `reviews_demo`.
19 | - Azure AI Search resource named `aitour-search-XXXXX`
20 | - Azure Open AI Service named `aitour-aoai-XXXXX` with
21 | - Deployed GPT 3.5 Turbo model named `completions`
22 | - Deployed `text-embedding-ada-002` model named `embeddings`
23 |
24 | ### 2. Add data and configure services
25 |
26 | -
27 | - pip install -r requirements.txt
28 | - Add service keys to .env file
29 |
30 | Run the python script to:
31 | - Populate the `reviews_demo` database with a table named `customer_reviews` with 99 records.
32 | - Enable change tracking on the database
33 | - Set `customer_reviews` as AI Search datasource with fields configured
34 | - Create an index named `sql-customer-index` with 2 skillsets: chunking data and vectorization
35 | - Indexer for the data
36 |
37 | Alternatively, you can do this in the notebook and test it out.
38 |
39 | ### 3. Chat with data in Azure OpenAI Studio Chat Playground
40 |
41 | 1. In Azure OpenAI Studio, open Chat and make sure your `completions` model is selected
42 | 1. Select Add your data and set fields to:
43 | - Select your AI Search as data source
44 | - Select deployed resource and index named `sql-customer-index`
45 | - Check `Add vector search...`
46 | 1. Select next and in Data management and set fields:
47 | - Search type `Vector`
48 | 1. Select next and select `API`
49 | 1. Select Review and Finish > Save and Close
50 |
51 | ## Presenting the Demo
52 |
53 | ### Prepare
54 |
55 | It's recommended to have 3 tabs open in your browser for this demo:
56 | - Azure Portal with Azure SQL Database Query Editor for the `customer_reviews` table selected
57 | - Azure Portal with Azure AI Search resource open to Indexes > `sql-customer-index`
58 | - Azure OpenAI Studio Chat Playground (make sure your Index is selected and system message added)
59 |
60 |
61 | ### 1. Describe the scenario:
62 |
63 | ```
64 | Let's walk through how Azure SQL seamlessly integrates with Azure AI Services to create a Copilot for product suggestions based on customer reviews.
65 |
66 | In the database we have a collection of a variety of product reviews, let's explore the data with Copilot. We're curious to about any reviews for pet products, like a dog.
67 | ```
68 |
69 | ### 2. Use Copilot in Query editor to search for `Find all the product reviews that mention dogs`
70 |
71 | It should return a this query:
72 |
73 | `
74 | SELECT *
75 | FROM dbo.customer_reviews
76 | WHERE Text LIKE '%dogs%';
77 | `
78 |
79 | Select **Accept**
80 |
81 | ### 3. Run the query - it returns 3 rows. Explain what's happening:
82 |
83 | ```
84 | We used natural language to describe what we're looking for, and Copilot describes why it generated this SQL query. This is great for situations when you're unsure how to put together a complex query or when you need to optimize your query. Copilot is designed to understand the context of your database to generate accurate queries by using your database metadata so things like tables, column names, primary keys, and foreign keys are taken into consideration when generating a query.
85 |
86 | This transforms the way we interact with our data, making it more accessible and intuitive.
87 | ```
88 |
89 | ### 4. Transition to from Query Editor to Azure AI Search
90 |
91 | ```
92 | Right here in the portal, there’s a button to set up Azure AI Search. With just a few clicks, we can connect our SQL data to Azure AI Search, enriching our database with AI capabilities.
93 |
94 | Azure SQL Database has vector search capabilities all on its own, but with Azure AI search we can apply cognitive skills to our data or extract key information to make our data work smarter.
95 |
96 | We already have an index set up so let's take a look in Azure AI Search.
97 | ```
98 |
99 | ### 4. Move on to Azure AI Search - Indexes Blade
100 |
101 | #### (Optional) - Search Explorer
102 |
103 | ```
104 | Here's our data, let's use the search explorer to find highly rated products, we define as a score greater than 4.
105 | ```
106 |
107 | **Go to View > JSON View and paste in the query**
108 |
109 | ```
110 | {
111 | "search": "{ \"search\": \"top rated products\", \"searchFields\": \"parent_text, parent_summary\", \"select\": \"id, parent_product_id, parent_text, parent_summary, parent_score\", \"filter\": \"parent_score gt 4\", \"orderby\": \"parent_score desc\" }",
112 | "answers": "extractive|count-3",
113 | "captions": "extractive",
114 | "queryLanguage": "en-US",
115 | "semanticConfiguration": "my-semantic-config",
116 | "queryType": "semantic",
117 | "vectorQueries": [
118 | {
119 | "kind": "text",
120 | "text": "{ \"search\": \"top rated products\", \"searchFields\": \"parent_text, parent_summary\", \"select\": \"id, parent_product_id, parent_text, parent_summary, parent_score\", \"filter\": \"parent_score gt 4\", \"orderby\": \"parent_score desc\" }",
121 | "fields": "vector"
122 | }
123 | ]
124 | }
125 | ```
126 |
127 |
128 | #### Fields View
129 |
130 | ```
131 | The Fields view has all the columns we pulled in from our table. This data is configured so that we each review has unique identifier that can be easily searched and filtered with any tokenization.
132 |
133 | The parent text, summary, and score fields provide additional context and metadata about the scores.
134 |
135 | Finally the The vector field stores vector representations of the review text to find semantically similar reviews. We'll look at how these were turned into vectors with skills but first let's talk about how we convert queries into vectors.
136 | ```
137 |
138 | #### Vector Profiles
139 |
140 | ```
141 | Vectorizers in a vector profile turn texts or images into vector representation during query execution. We use a deployed Azure OpenAI model to find semantically similar reviews.
142 |
143 | Let's look at how the data that's stored is turned into vectors with skills.
144 | ```
145 |
146 |
147 | ### 5. Azure AI Search - Indexes Blade > sql-customer-index-skillset
148 |
149 | ```
150 | Skillsets are used during the indexing process to transform the data into vector representations. We're using a vectorization skill to generate embeddings of the review content, and is stored in the vector field. Any new data that is added to the SQL table would also go through the same vectorization process.
151 |
152 | There's also another skill in here that splits the document text into chunks based on pages, making it easier to generate embeddings, perform detailed searches, and the token limits are much easier to manage.
153 |
154 | The data we saw in the table has been transformed into vectors and is now a knowledge base of product reviews. We can take it even further in Azure OpenAI Chat Playground and create an interactive experience where users can ask questions about the products and receive detailed, context-aware responses.
155 | ```
156 |
157 |
158 | ### 6. Azure OpenAI Studio Chat Playground
159 |
160 | #### SETUP
161 | **NOTE**: The system message will reset when you refresh the page. Consider adding the system message right before you deliver the session.
162 |
163 | Add the system message:
164 |
165 | ```
166 | The user is searching for a product matching their query. Tell the user that after searching through our product database, you recommend the product described in the provided product review. Your answer should summarize the review text, include the product ID, and mention the score given in the review. Present the answer in a readable format that clearly lists the products.
167 | ```
168 |
169 |
170 | ```
171 | In the playground I have set up the index as my source (show Add your data configuration) and a system message. Let's try asking a question.
172 | ```
173 |
174 | Try these prompts:
175 | - `What are customers saying about the dog products?`
176 | - `What food products do customers like as snacks?`
177 | - `What are customers general sentiment about the oatmeal?`
178 |
179 | The citations point to specific reviews from the response.
180 |
181 | ```
182 | The data we saw in the table has been transformed into vectors and now is a knowledge base of product reviews in Azure OpenAI Studio. We could take it even further here and transform it into an app (show the Deploy button).
183 |
184 | We can achieve all of this programmatically through APIs or directly in the Azure Portal, giving you the flexibility to choose the approach that best fits your needs.
185 |
186 | ```
187 |
188 | ### 7. Wrap up
189 |
190 | ```
191 | We started with Copilot, using natural language to query our database to help us learn and optimize our database interactions.
192 |
193 | Next, we enhanced our search capabilities with Azure AI Search index.
194 |
195 | Finally, we integrated our data with the Azure OpenAI Chat Playground. This allowed us to ask questions about our product reviews and receive detailed, context-aware responses.
196 |
197 | Solid integration across the Microsoft Intelligent Data platform makes your AI transformation much smoother and efficient.
198 | ```
--------------------------------------------------------------------------------
/session-delivery-resources/3-azure-sql-ai-search/src/AzureSQL_CogSearch_IntegratedVectorization.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Azure SQL Database + Azure AI Search: Integrated Vectorization\n",
8 | "\n",
9 | "Adapted from [this sample](https://github.com/Azure-Samples/SQL-AI-samples/tree/main/AzureSQLACSSamples)\n",
10 | "\n",
11 | "We will create a small example of an AI application that responds to users' queries based on a SQL table of Amazon product reviews.\n",
12 | "\n",
13 | "The end behavior will be something like:\n",
14 | "\n",
15 | "```\n",
16 | "[User search]: Canned dog food\n",
17 | "[AI Response]: After searching through our product database, I recommend because... \n",
18 | "```\n",
19 | "\n",
20 | "Behind the scenes, we take the following steps:\n",
21 | "* Set up a sample table in a SQL DB and upload data to it\n",
22 | "* Set up an index in Azure Cognitive Search to store the data we need, including vectorized versions of the text reviews\n",
23 | "* Set up an indexer in Azure Cognitive Search to pull data into the index \n",
24 | " * Automatically chunks and vectorizes the data using an Azure OpenAI Embedding service\n",
25 | "* Use Azure Cognitive Search to process the user's query and search for the most relevant data\n",
26 | "* Use an Azure OpenAI Completion service to respond to the user's query\n",
27 | "\n",
28 | "\n",
29 | "Copyright (c) Microsoft Corporation.\n",
30 | "Licensed under the MIT license."
31 | ]
32 | },
33 | {
34 | "cell_type": "markdown",
35 | "metadata": {},
36 | "source": [
37 | "## Requirements\n",
38 | "\n",
39 | "You will need:\n",
40 | "* The Python packages listed in `requirements.txt` (can all be installed using `pip install -r requirements.txt`)\n",
41 | " * Please note that we are using a preview version of the [azure-search-documents](https://pypi.org/project/azure-search-documents/#description), version `11.6.0b4`.\n",
42 | " * This notebook uses Python 3.10.\n",
43 | "* An existing SQL Database with server name, DB name, username, and password copied into `example.env`\n",
44 | " * You must have permission to create a new table and enable and view change tracking on the database\n",
45 | " * You must whitelist your IP to access your SQL server by opening the SQL server resource in the Azure portal, navigating to Security / Networking, and adding your IP.\n",
46 | "* An OpenAI resource with both an embedding deployment and a completion deployment, with the details copied into `example.env`\n",
47 | "* A Cognitive Search resource with the endpoint and key copied into `example.env`\n",
48 | "* The Microsoft ODBC 18 driver, [instructions here](https://learn.microsoft.com/en-us/sql/connect/odbc/microsoft-odbc-driver-for-sql-server?view=sql-server-ver16).\n"
49 | ]
50 | },
51 | {
52 | "cell_type": "markdown",
53 | "metadata": {},
54 | "source": [
55 | "# Load environment variables and keys"
56 | ]
57 | },
58 | {
59 | "cell_type": "code",
60 | "execution_count": 1,
61 | "metadata": {},
62 | "outputs": [],
63 | "source": [
64 | "from dotenv import dotenv_values\n",
65 | "# specify the name of the .env file name \n",
66 | "env_name = \"example.env\"\n",
67 | "config = dotenv_values(env_name)"
68 | ]
69 | },
70 | {
71 | "cell_type": "code",
72 | "execution_count": 2,
73 | "metadata": {},
74 | "outputs": [],
75 | "source": [
76 | "# Load Azure SQL database connection details\n",
77 | "server = config[\"server\"] \n",
78 | "database = config[\"database\"] \n",
79 | "username = config[\"username\"] \n",
80 | "password = config[\"password\"] \n",
81 | "driver = '{ODBC Driver 18 for SQL Server}'"
82 | ]
83 | },
84 | {
85 | "cell_type": "code",
86 | "execution_count": 3,
87 | "metadata": {},
88 | "outputs": [],
89 | "source": [
90 | "# Load Open AI deployment details\n",
91 | "import openai\n",
92 | "openai.api_type = config[\"openai_api_type\"]\n",
93 | "openai.api_key = config['openai_api_key']\n",
94 | "openai.api_base = config['openai_api_base']\n",
95 | "openai.api_version = config['openai_api_version']\n",
96 | "openai_deployment_completion = config[\"openai_deployment_completion\"]\n",
97 | "openai_model_completion = config[\"openai_model_completion\"]\n",
98 | "openai_deployment_embedding = config[\"openai_deployment_embedding\"]\n",
99 | "openai_model_embedding = config[\"openai_model_embedding\"]\n",
100 | "EMBEDDING_LENGTH = 1536"
101 | ]
102 | },
103 | {
104 | "cell_type": "code",
105 | "execution_count": 4,
106 | "metadata": {},
107 | "outputs": [],
108 | "source": [
109 | "# Load Cognitive Search service details\n",
110 | "cogsearch_key = config[\"cogsearch_api_key\"]\n",
111 | "service_endpoint = config[\"cogsearch_endpoint\"]\n",
112 | "index_name = config[\"cogsearch_index_name\"] # Desired name of index -- does not need to exist already\n"
113 | ]
114 | },
115 | {
116 | "cell_type": "markdown",
117 | "metadata": {},
118 | "source": [
119 | "# Upload data to SQL DB"
120 | ]
121 | },
122 | {
123 | "cell_type": "markdown",
124 | "metadata": {},
125 | "source": [
126 | "## Create table"
127 | ]
128 | },
129 | {
130 | "cell_type": "markdown",
131 | "metadata": {},
132 | "source": [
133 | "### Connect to database\n",
134 | "\n",
135 | "For simplicity, we set `autocommit=True` in the pyodbc connection parameters, which allows us to execute `ALTER` statements. In a production scenario, setting `autocommit=True` is not recommended; instead, the `ALTER` statements can be executed in SSMS or similar.\n",
136 | "\n",
137 | "If a timeout error occurs, retry the cell."
138 | ]
139 | },
140 | {
141 | "cell_type": "code",
142 | "execution_count": 5,
143 | "metadata": {},
144 | "outputs": [],
145 | "source": [
146 | "import pyodbc\n",
147 | "\n",
148 | "# Create a connection string\n",
149 | "conn_str = f\"DRIVER={driver};SERVER={server};DATABASE={database};UID={username};PWD={password}\"\n",
150 | "\n",
151 | "# Establish a connection to the Azure SQL database\n",
152 | "conn = pyodbc.connect(conn_str, autocommit=True)\n",
153 | "cursor = conn.cursor()"
154 | ]
155 | },
156 | {
157 | "cell_type": "markdown",
158 | "metadata": {},
159 | "source": [
160 | "### Create a table in the database\n",
161 | "\n",
162 | "We will create a new table \"foodreview\" and upload the data from a csv file. We include a primary key, which is necessary for change tracking."
163 | ]
164 | },
165 | {
166 | "cell_type": "code",
167 | "execution_count": 6,
168 | "metadata": {},
169 | "outputs": [
170 | {
171 | "name": "stdout",
172 | "output_type": "stream",
173 | "text": [
174 | "Finished dropping table (if existed)\n",
175 | "Finished creating table\n",
176 | "Finished creating index\n"
177 | ]
178 | }
179 | ],
180 | "source": [
181 | "table_name = \"foodreview\" \n",
182 | "\n",
183 | "# Drop previous table of same name if one exists\n",
184 | "cursor.execute(f\"DROP TABLE IF EXISTS {table_name};\")\n",
185 | "print(\"Finished dropping table (if existed)\")\n",
186 | "\n",
187 | "# Create a table\n",
188 | "cursor.execute(f\"\"\"\n",
189 | " CREATE TABLE {table_name} \n",
190 | " (Id int NOT NULL, \n",
191 | " CONSTRAINT PK_{table_name}_Id PRIMARY KEY CLUSTERED (Id), \n",
192 | " ProductId text, \n",
193 | " UserId text, \n",
194 | " ProfileName text, \n",
195 | " HelpfulnessNumerator integer, \n",
196 | " HelpfulnessDenominator integer, \n",
197 | " Score integer, \n",
198 | " Time bigint, \n",
199 | " Summary text, \n",
200 | " Text text,\n",
201 | " TextConcat text);\n",
202 | " \"\"\")\n",
203 | "print(\"Finished creating table\")\n",
204 | "\n",
205 | "# Create a index\n",
206 | "cursor.execute(f\"CREATE INDEX idx_Id ON {table_name}(Id);\")\n",
207 | "print(\"Finished creating index\")"
208 | ]
209 | },
210 | {
211 | "cell_type": "markdown",
212 | "metadata": {},
213 | "source": [
214 | "### Enable change tracking\n",
215 | "\n",
216 | "This allows us to automatically update the index when changes are made to the data."
217 | ]
218 | },
219 | {
220 | "cell_type": "code",
221 | "execution_count": 7,
222 | "metadata": {},
223 | "outputs": [
224 | {
225 | "name": "stdout",
226 | "output_type": "stream",
227 | "text": [
228 | "('42000', \"[42000] [Microsoft][ODBC Driver 18 for SQL Server][SQL Server]Change tracking is already enabled for database 'test_vector_notebook'. (5088) (SQLExecDirectW); [42000] [Microsoft][ODBC Driver 18 for SQL Server][SQL Server]ALTER DATABASE statement failed. (5069)\")\n"
229 | ]
230 | }
231 | ],
232 | "source": [
233 | "try:\n",
234 | " cursor.execute(f\"ALTER DATABASE [{database}] SET CHANGE_TRACKING = ON (CHANGE_RETENTION = 2 DAYS, AUTO_CLEANUP = ON)\")\n",
235 | "except Exception as e:\n",
236 | " print(e)"
237 | ]
238 | },
239 | {
240 | "cell_type": "code",
241 | "execution_count": 8,
242 | "metadata": {},
243 | "outputs": [],
244 | "source": [
245 | "try:\n",
246 | " cursor.execute(f\"ALTER TABLE {table_name} ENABLE CHANGE_TRACKING WITH (TRACK_COLUMNS_UPDATED = ON)\")\n",
247 | "except Exception as e:\n",
248 | " print(e)"
249 | ]
250 | },
251 | {
252 | "cell_type": "markdown",
253 | "metadata": {},
254 | "source": [
255 | "## Upload data"
256 | ]
257 | },
258 | {
259 | "cell_type": "markdown",
260 | "metadata": {},
261 | "source": [
262 | "### Load data from CSV\n",
263 | "\n",
264 | "The data contains a few product reviews, with related info."
265 | ]
266 | },
267 | {
268 | "cell_type": "code",
269 | "execution_count": null,
270 | "metadata": {},
271 | "outputs": [],
272 | "source": [
273 | "## Load Data\n",
274 | "import numpy as np\n",
275 | "import pandas as pd\n",
276 | "df_all = pd.read_csv('customer_reviews.csv')\n",
277 | "\n",
278 | "df_all.head(3)"
279 | ]
280 | },
281 | {
282 | "cell_type": "markdown",
283 | "metadata": {},
284 | "source": [
285 | "### Upload to DB"
286 | ]
287 | },
288 | {
289 | "cell_type": "code",
290 | "execution_count": 11,
291 | "metadata": {},
292 | "outputs": [],
293 | "source": [
294 | "# Split the dataframe into batches\n",
295 | "batch_size = 30\n",
296 | "batches = [df_all[i:i + batch_size] for i in range(0, len(df_all), batch_size)]\n",
297 | "\n",
298 | "#Iterate over each batch and insert the data into the database\n",
299 | "for batch in batches:\n",
300 | " # Convert the batch dataframe to a list of tuples for bulk insertion\n",
301 | " rows = [tuple(row) for row in batch.itertuples(index=False)]\n",
302 | " \n",
303 | " # Define the SQL query for bulk insertion\n",
304 | " query = f\"INSERT INTO {table_name} (Id, ProductId, UserId, ProfileName, HelpfulnessNumerator, HelpfulnessDenominator, Score, Time, Summary, Text, TextConcat) \\\n",
305 | " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\"\n",
306 | " cursor.executemany(query, rows)"
307 | ]
308 | },
309 | {
310 | "cell_type": "markdown",
311 | "metadata": {},
312 | "source": [
313 | "## Example query\n",
314 | "\n",
315 | "This checks that the data was uploaded correctly. We should have 99 rows at this point."
316 | ]
317 | },
318 | {
319 | "cell_type": "code",
320 | "execution_count": 12,
321 | "metadata": {},
322 | "outputs": [
323 | {
324 | "name": "stdout",
325 | "output_type": "stream",
326 | "text": [
327 | "(99,)\n"
328 | ]
329 | }
330 | ],
331 | "source": [
332 | "# Execute the SELECT statement\n",
333 | "try:\n",
334 | " cursor.execute(f\"SELECT count(Id) FROM {table_name};\")\n",
335 | " rows = cursor.fetchall()\n",
336 | " for row in rows:\n",
337 | " print(row)\n",
338 | "except Exception as e:\n",
339 | " print(f\"Error executing SELECT statement: {e}\")"
340 | ]
341 | },
342 | {
343 | "cell_type": "markdown",
344 | "metadata": {},
345 | "source": [
346 | "## Commit changes"
347 | ]
348 | },
349 | {
350 | "cell_type": "code",
351 | "execution_count": 13,
352 | "metadata": {},
353 | "outputs": [],
354 | "source": [
355 | "cursor.commit()\n",
356 | "cursor.close()"
357 | ]
358 | },
359 | {
360 | "cell_type": "markdown",
361 | "metadata": {},
362 | "source": [
363 | "# Set up data source connection in Cog Search"
364 | ]
365 | },
366 | {
367 | "cell_type": "markdown",
368 | "metadata": {},
369 | "source": [
370 | "## Import needed CogSearch functions"
371 | ]
372 | },
373 | {
374 | "cell_type": "code",
375 | "execution_count": 14,
376 | "metadata": {},
377 | "outputs": [],
378 | "source": [
379 | "from azure.core.credentials import AzureKeyCredential \n",
380 | "from azure.search.documents import SearchClient \n",
381 | "from azure.search.documents.indexes import SearchIndexClient, SearchIndexerClient \n",
382 | "from azure.search.documents.models import VectorizableTextQuery\n",
383 | "from azure.search.documents.indexes.models import ( \n",
384 | " AzureOpenAIEmbeddingSkill, \n",
385 | " AzureOpenAIParameters, \n",
386 | " AzureOpenAIVectorizer, \n",
387 | " HnswAlgorithmConfiguration, \n",
388 | " InputFieldMappingEntry,\n",
389 | " OutputFieldMappingEntry, \n",
390 | " SemanticPrioritizedFields, \n",
391 | " SearchField, \n",
392 | " SearchFieldDataType, \n",
393 | " SearchIndex, \n",
394 | " SearchIndexer, \n",
395 | " SearchIndexerDataContainer, \n",
396 | " SearchIndexerDataSourceConnection, \n",
397 | " SearchIndexerIndexProjectionSelector, \n",
398 | " SearchIndexerIndexProjections, \n",
399 | " SearchIndexerSkillset, \n",
400 | " SemanticConfiguration, \n",
401 | " SemanticField, \n",
402 | " SemanticSearch,\n",
403 | " SplitSkill, \n",
404 | " SqlIntegratedChangeTrackingPolicy,\n",
405 | " VectorSearch, \n",
406 | " VectorSearchAlgorithmKind,\n",
407 | " VectorSearchProfile\n",
408 | ") "
409 | ]
410 | },
411 | {
412 | "cell_type": "markdown",
413 | "metadata": {},
414 | "source": [
415 | "## Create data source connection\n",
416 | "\n",
417 | "This step creates a connection that will be used to pull data from our SQL table.\n",
418 | "\n",
419 | "Documentation can be found [here.](https://learn.microsoft.com/en-us/azure/search/search-howto-connecting-azure-sql-database-to-azure-search-using-indexers)"
420 | ]
421 | },
422 | {
423 | "cell_type": "code",
424 | "execution_count": 15,
425 | "metadata": {},
426 | "outputs": [
427 | {
428 | "name": "stdout",
429 | "output_type": "stream",
430 | "text": [
431 | "Data source 'amazon-review-jordan-v1-azuresql-connection' created or updated\n"
432 | ]
433 | }
434 | ],
435 | "source": [
436 | "ds_conn_str = f'Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;Server=tcp:{server};Database={database};User ID={username};Password={password};'\n",
437 | "\n",
438 | "cogsearch_credential = AzureKeyCredential(cogsearch_key)\n",
439 | "ds_client = SearchIndexerClient(service_endpoint, cogsearch_credential)\n",
440 | "container = SearchIndexerDataContainer(name=table_name)\n",
441 | "\n",
442 | "change_detection_policy = SqlIntegratedChangeTrackingPolicy()\n",
443 | "\n",
444 | "data_source_connection = SearchIndexerDataSourceConnection(\n",
445 | " name=f\"{index_name}-azuresql-connection\",\n",
446 | " type=\"azuresql\",\n",
447 | " connection_string=ds_conn_str,\n",
448 | " container=container,\n",
449 | " data_change_detection_policy=change_detection_policy\n",
450 | ")\n",
451 | "data_source = ds_client.create_or_update_data_source_connection(data_source_connection)\n",
452 | "\n",
453 | "print(f\"Data source '{data_source.name}' created or updated\")"
454 | ]
455 | },
456 | {
457 | "cell_type": "markdown",
458 | "metadata": {},
459 | "source": [
460 | "# Set up automatic chunking + vectorization + indexing"
461 | ]
462 | },
463 | {
464 | "cell_type": "markdown",
465 | "metadata": {},
466 | "source": [
467 | "## Create index\n",
468 | "\n",
469 | "The plan is:\n",
470 | "1. Take the combined text (summary + review text) from each product review\n",
471 | "2. Split the combined text into chunks\n",
472 | "3. Embed each chunk as a vector\n",
473 | "4. (Later) search for the most relevant chunk based on the incoming query. \n",
474 | "\n",
475 | "To enable this, the search index will store all of the following data, for each chunk of text:\n",
476 | "* Id of chunk\n",
477 | "* Chunk text\n",
478 | "* Vector version of chunk text\n",
479 | "* Id of parent row\n",
480 | "* Product Id from parent row\n",
481 | "* Review text from parent row\n",
482 | "* Summary text from parent row\n",
483 | "* Score from parent row\n",
484 | "\n",
485 | "All of these values will be stored in SearchFields specified in the code below.\n",
486 | "\n",
487 | "In this step we also configure the search algorithm(s), and the vectorizer that will automatically vectorize the incoming query.\n",
488 | "\n",
489 | "Documentation about creating indexes can be found [here.](https://learn.microsoft.com/en-us/azure/search/search-how-to-create-search-index?tabs=index-other-sdks)"
490 | ]
491 | },
492 | {
493 | "cell_type": "code",
494 | "execution_count": 16,
495 | "metadata": {},
496 | "outputs": [
497 | {
498 | "name": "stdout",
499 | "output_type": "stream",
500 | "text": [
501 | "amazon-review-jordan-v1 created\n"
502 | ]
503 | }
504 | ],
505 | "source": [
506 | "# Create a search index\n",
507 | "index_client = SearchIndexClient(\n",
508 | " endpoint=service_endpoint, credential=cogsearch_credential)\n",
509 | "\n",
510 | "fields = [\n",
511 | " # Properties of individual chunk\n",
512 | " SearchField(name=\"Id\", type=SearchFieldDataType.String, key=True,\n",
513 | " sortable=True, filterable=True, facetable=True, analyzer_name=\"keyword\"),\n",
514 | " SearchField(name=\"chunk\", type=SearchFieldDataType.String, sortable=False, filterable=False, facetable=False),\n",
515 | " SearchField(name=\"vector\", type=SearchFieldDataType.Collection(SearchFieldDataType.Single), \n",
516 | " vector_search_dimensions=EMBEDDING_LENGTH, vector_search_profile_name=\"my-vector-search-profile\"),\n",
517 | " # Properties of original row in DB that the chunk belonged to\n",
518 | " SearchField(name=\"parent_id\", type=SearchFieldDataType.String, sortable=True, filterable=True, facetable=True),\n",
519 | " SearchField(name=\"parent_product_id\", type=SearchFieldDataType.String, sortable=True, filterable=True, facetable=True),\n",
520 | " SearchField(name=\"parent_text\", type=SearchFieldDataType.String, sortable=True, filterable=True, facetable=True),\n",
521 | " SearchField(name=\"parent_summary\", type=SearchFieldDataType.String, sortable=True, filterable=True, facetable=True),\n",
522 | " SearchField(name=\"parent_score\", type=SearchFieldDataType.Int64, sortable=True, filterable=True, facetable=True)\n",
523 | "]\n",
524 | "\n",
525 | "# Configure the vector search configuration \n",
526 | "vector_search = VectorSearch(\n",
527 | " algorithms=[\n",
528 | " HnswAlgorithmConfiguration(\n",
529 | " name=\"my-hnsw-config\",\n",
530 | " kind=VectorSearchAlgorithmKind.HNSW\n",
531 | " )\n",
532 | " ],\n",
533 | " profiles=[\n",
534 | " VectorSearchProfile(\n",
535 | " name=\"my-vector-search-profile\",\n",
536 | " algorithm_configuration_name=\"my-hnsw-config\",\n",
537 | " vectorizer=\"my-openai\"\n",
538 | " )\n",
539 | " ],\n",
540 | " vectorizers=[\n",
541 | " AzureOpenAIVectorizer(\n",
542 | " name=\"my-openai\",\n",
543 | " kind=\"azureOpenAI\",\n",
544 | " azure_open_ai_parameters=AzureOpenAIParameters(\n",
545 | " resource_uri=openai.api_base,\n",
546 | " deployment_id=openai_deployment_embedding,\n",
547 | " api_key=openai.api_key,\n",
548 | " model_name=openai_model_embedding\n",
549 | " )\n",
550 | " ) \n",
551 | " ] \n",
552 | ")\n",
553 | "\n",
554 | "semantic_config = SemanticConfiguration(\n",
555 | " name=\"my-semantic-config\",\n",
556 | " prioritized_fields=SemanticPrioritizedFields(\n",
557 | " content_fields=[SemanticField(field_name=\"Id\")]\n",
558 | " )\n",
559 | ")\n",
560 | "\n",
561 | "# Create the semantic search with the configuration above\n",
562 | "semantic_search = SemanticSearch(configurations=[semantic_config])\n",
563 | "\n",
564 | "# Create the search index\n",
565 | "index = SearchIndex(name=index_name, fields=fields,\n",
566 | " vector_search=vector_search, semantic_search=semantic_search)\n",
567 | "result = index_client.create_or_update_index(index)\n",
568 | "print(f'{result.name} created')\n"
569 | ]
570 | },
571 | {
572 | "cell_type": "markdown",
573 | "metadata": {},
574 | "source": [
575 | "## Create skillset\n",
576 | "\n",
577 | "We use two pre-built skills:\n",
578 | "1. The Split Skill takes the concatenated text and divides it into chunks (to stay within the token limits for the OpenAI embedding service).\n",
579 | "2. The Azure OpenAI Embedding Skill takes the outputs of the Split Skill and vectorizes them individually.\n",
580 | "\n",
581 | "Afterwards, we apply an Index Projector to make it so that our final index has one item for every chunk of text (rather than one item for every original row in the DB).\n",
582 | "\n",
583 | "We recommend the following resources to learn more about the process and how one can adapt it to different applications:\n",
584 | "* [Overview of indexers](https://learn.microsoft.com/en-us/azure/search/search-indexer-overview)\n",
585 | "* [Skill context and input annotation language](https://learn.microsoft.com/en-us/azure/search/cognitive-search-skill-annotation-language)\n",
586 | "* [Reference inputs and outputs in skillsets](https://learn.microsoft.com/en-us/azure/search/cognitive-search-concept-annotations-syntax)"
587 | ]
588 | },
589 | {
590 | "cell_type": "code",
591 | "execution_count": 17,
592 | "metadata": {},
593 | "outputs": [
594 | {
595 | "name": "stdout",
596 | "output_type": "stream",
597 | "text": [
598 | " amazon-review-jordan-v1-skillset created\n"
599 | ]
600 | }
601 | ],
602 | "source": [
603 | "# Create a skillset \n",
604 | "skillset_name = f\"{index_name}-skillset\"\n",
605 | "\n",
606 | "split_skill = SplitSkill( \n",
607 | " description=\"Split skill to chunk documents\", \n",
608 | " text_split_mode=\"pages\", \n",
609 | " context=\"/document\", \n",
610 | " maximum_page_length=300, \n",
611 | " page_overlap_length=20, \n",
612 | " inputs=[ \n",
613 | " InputFieldMappingEntry(name=\"text\", source=\"/document/TextConcat\"), \n",
614 | " ], \n",
615 | " outputs=[ \n",
616 | " OutputFieldMappingEntry(name=\"textItems\", target_name=\"pages\") \n",
617 | " ] \n",
618 | ")\n",
619 | "\n",
620 | "embedding_skill = AzureOpenAIEmbeddingSkill( \n",
621 | " description=\"Skill to generate embeddings via Azure OpenAI\", \n",
622 | " context=\"/document/pages/*\", \n",
623 | " resource_uri=openai.api_base, \n",
624 | " deployment_id=openai_deployment_embedding, \n",
625 | " api_key=openai.api_key,\n",
626 | " model_name=openai_model_embedding,\n",
627 | " inputs=[ \n",
628 | " InputFieldMappingEntry(name=\"text\", source=\"/document/pages/*\"), \n",
629 | " ], \n",
630 | " outputs=[ \n",
631 | " OutputFieldMappingEntry(name=\"embedding\", target_name=\"vector\") \n",
632 | " ] \n",
633 | ") \n",
634 | "\n",
635 | "index_projections = SearchIndexerIndexProjections( \n",
636 | " selectors=[ \n",
637 | " SearchIndexerIndexProjectionSelector( \n",
638 | " target_index_name=index_name, \n",
639 | " parent_key_field_name=\"parent_id\", # Note: this populates the \"parent_id\" search field\n",
640 | " source_context=\"/document/pages/*\", \n",
641 | " mappings=[ \n",
642 | " InputFieldMappingEntry(name=\"chunk\", source=\"/document/pages/*\"),\n",
643 | " InputFieldMappingEntry(name=\"vector\", source=\"/document/pages/*/vector\"),\n",
644 | " InputFieldMappingEntry(name=\"parent_product_id\", source=\"/document/ProductId\"),\n",
645 | " InputFieldMappingEntry(name=\"parent_text\", source=\"/document/Text\"),\n",
646 | " InputFieldMappingEntry(name=\"parent_summary\", source=\"/document/Summary\"),\n",
647 | " InputFieldMappingEntry(name=\"parent_score\", source=\"/document/Score\")\n",
648 | " ], \n",
649 | " ), \n",
650 | " ],\n",
651 | ") \n",
652 | "\n",
653 | "skillset = SearchIndexerSkillset( \n",
654 | " name=skillset_name, \n",
655 | " description=\"Skillset to chunk documents and generating embeddings\", \n",
656 | " skills=[split_skill, embedding_skill],\n",
657 | " index_projections=index_projections \n",
658 | ")\n",
659 | " \n",
660 | "client = SearchIndexerClient(service_endpoint, cogsearch_credential) \n",
661 | "client.create_or_update_skillset(skillset) \n",
662 | "print(f' {skillset.name} created')"
663 | ]
664 | },
665 | {
666 | "cell_type": "markdown",
667 | "metadata": {},
668 | "source": [
669 | "## Create indexer"
670 | ]
671 | },
672 | {
673 | "cell_type": "code",
674 | "execution_count": 18,
675 | "metadata": {},
676 | "outputs": [
677 | {
678 | "name": "stdout",
679 | "output_type": "stream",
680 | "text": [
681 | " amazon-review-jordan-v1-indexer created\n"
682 | ]
683 | }
684 | ],
685 | "source": [
686 | "# Create an indexer \n",
687 | "indexer_name = f\"{index_name}-indexer\" \n",
688 | "\n",
689 | "indexer = SearchIndexer( \n",
690 | " name=indexer_name, \n",
691 | " description=\"Indexer to chunk documents and generate embeddings\", \n",
692 | " skillset_name=skillset_name, \n",
693 | " target_index_name=index_name, \n",
694 | " data_source_name=data_source.name\n",
695 | ") \n",
696 | " \n",
697 | "indexer_client = SearchIndexerClient(service_endpoint, cogsearch_credential)\n",
698 | "indexer_result = indexer_client.create_or_update_indexer(indexer) \n",
699 | "\n",
700 | "# Run the indexer \n",
701 | "indexer_client.run_indexer(indexer_name)\n",
702 | "print(f' {indexer_name} created')"
703 | ]
704 | },
705 | {
706 | "cell_type": "code",
707 | "execution_count": 19,
708 | "metadata": {},
709 | "outputs": [
710 | {
711 | "name": "stdout",
712 | "output_type": "stream",
713 | "text": [
714 | "Indexer status: running\n"
715 | ]
716 | }
717 | ],
718 | "source": [
719 | "# Get the status of the indexer \n",
720 | "indexer_status = indexer_client.get_indexer_status(indexer_name)\n",
721 | "print(f\"Indexer status: {indexer_status.status}\")"
722 | ]
723 | },
724 | {
725 | "cell_type": "code",
726 | "execution_count": 20,
727 | "metadata": {},
728 | "outputs": [],
729 | "source": [
730 | "# Allow some time for the indexer to process the data\n",
731 | "import time\n",
732 | "time.sleep(30)"
733 | ]
734 | },
735 | {
736 | "cell_type": "markdown",
737 | "metadata": {},
738 | "source": [
739 | "# Use vector search for sample application"
740 | ]
741 | },
742 | {
743 | "cell_type": "markdown",
744 | "metadata": {},
745 | "source": [
746 | "## Perform queries"
747 | ]
748 | },
749 | {
750 | "cell_type": "code",
751 | "execution_count": 21,
752 | "metadata": {},
753 | "outputs": [],
754 | "source": [
755 | "user_query = \"Canned dog food\""
756 | ]
757 | },
758 | {
759 | "cell_type": "markdown",
760 | "metadata": {},
761 | "source": [
762 | "In the following output, we find the top 3 chunks that are most relevant to the user's query.\n",
763 | "\n",
764 | "Feel free to retry the following cell in case of an empty response or a 429 error. An empty response probably indicates that the chunking/embedding process has not finished yet. A 429 error means there have been too many requests to the OpenAI embedding service and should go away on retrying."
765 | ]
766 | },
767 | {
768 | "cell_type": "code",
769 | "execution_count": 27,
770 | "metadata": {},
771 | "outputs": [
772 | {
773 | "name": "stdout",
774 | "output_type": "stream",
775 | "text": [
776 | "Search score: 0.88524085\n",
777 | "Parent Id: 1 | Chunk id: 703f51d51de7_1_pages_0\n",
778 | "Product Id: B001E4KFG0\n",
779 | "Text chunk: Summary: Good Quality Dog Food | Review: I have bought several of the Vitality canned dog food products and have found them all to be of good quality. The product looks more like a stew than a processed meat and it smells better.\n",
780 | "Review summary: Good Quality Dog Food\n",
781 | "Review text: I have bought several of the Vitality canned dog food products and have found them all to be of good quality. The product looks more like a stew than a processed meat and it smells better. My Labrador is finicky and she appreciates this product better than most.\n",
782 | "Review score: 5\n",
783 | "-----\n",
784 | "Search score: 0.87025785\n",
785 | "Parent Id: 94 | Chunk id: 703f51d51de7_94_pages_3\n",
786 | "Product Id: B0019CW0HE\n",
787 | "Text chunk: a couple of cans. I came home and to my surprise realized that I could save $20 each time I bought dog food if I just buy it off Amazon.
All in all, I definitely recommend and give my stamp of approval to natural balance dog food. While I have never eaten it, my dog seems to love it.\n",
788 | "Review summary: Great Dog Food!\n",
789 | "Review text: My golden retriever is one of the most picky dogs I've ever met. After experimenting with various types of food, I have found she loves natural balance. What I really like about natural balance is the fact that it has multiple flavors in dry and wet varieties. I mix her dry food with a little wet food and my golden loves it. Furthermore, I do like mixing up the flavors each time as I think the same meal day over day might get a little boring, so I figured why not. I tend to stay away from the fish type though as it smells...
Additionally, I started purchasing off Amazon because Petco didn't have the wet food box and only had a couple of cans. I came home and to my surprise realized that I could save $20 each time I bought dog food if I just buy it off Amazon.
All in all, I definitely recommend and give my stamp of approval to natural balance dog food. While I have never eaten it, my dog seems to love it.\n",
790 | "Review score: 5\n",
791 | "-----\n",
792 | "Search score: 0.8640232\n",
793 | "Parent Id: 98 | Chunk id: 703f51d51de7_98_pages_0\n",
794 | "Product Id: B0019CW0HE\n",
795 | "Text chunk: Summary: Great allergy sensitive dog food, dogs love it | Review: Our pup has experienced allergies in forms of hotspots and itching from other dog foods. The cheap 'you can buy it anywhere' food not only have crazy preservatives in them but can cause health problems for your pets.\n",
796 | "Review summary: Great allergy sensitive dog food, dogs love it\n",
797 | "Review text: Our pup has experienced allergies in forms of hotspots and itching from other dog foods. The cheap 'you can buy it anywhere' food not only have crazy preservatives in them but can cause health problems for your pets. This food works wonders on reducing allergies and our dog loves the food.
This message is RAMSEY FrAnkenSteiN approved.\n",
798 | "Review score: 5\n",
799 | "-----\n"
800 | ]
801 | }
802 | ],
803 | "source": [
804 | "search_client = SearchClient(service_endpoint, index_name, credential=cogsearch_credential)\n",
805 | "vector_query = VectorizableTextQuery(text=user_query, fields=\"vector\", exhaustive=True)\n",
806 | "# Use the query below to pass in the raw vector query instead of the query vectorization\n",
807 | "# vector_query = RawVectorQuery(vector=generate_embeddings(user_query), k=3, fields=\"vector\")\n",
808 | " \n",
809 | "results = search_client.search(\n",
810 | " search_text=None, \n",
811 | " vector_queries= [vector_query],\n",
812 | " select=[\"Id\", \"parent_id\", \"chunk\", \"parent_product_id\", \"parent_text\", \"parent_summary\", \"parent_score\"],\n",
813 | " top=3\n",
814 | ")\n",
815 | "\n",
816 | "for result in results:\n",
817 | " print(f\"Search score: {result['@search.score']}\")\n",
818 | " print(f\"Parent Id: {result['parent_id']} | Chunk id: {result['Id']}\")\n",
819 | " print(f\"Product Id: {result['parent_product_id']}\")\n",
820 | " print(f\"Text chunk: {result['chunk']}\") \n",
821 | " print(f\"Review summary: {result['parent_summary']}\")\n",
822 | " print(f\"Review text: {result['parent_text']}\")\n",
823 | " print(f\"Review score: {result['parent_score']}\")\n",
824 | " print(\"-----\")\n"
825 | ]
826 | },
827 | {
828 | "cell_type": "markdown",
829 | "metadata": {},
830 | "source": [
831 | "## Generate GPT Response"
832 | ]
833 | },
834 | {
835 | "cell_type": "markdown",
836 | "metadata": {},
837 | "source": [
838 | "### Prompt creation"
839 | ]
840 | },
841 | {
842 | "cell_type": "code",
843 | "execution_count": 28,
844 | "metadata": {},
845 | "outputs": [],
846 | "source": [
847 | "# create a prompt template \n",
848 | "template = \"\"\"\n",
849 | " The user's query is: {query}\n",
850 | " The most relevant product review is: {context}\n",
851 | " The user is searching for a product matching their query. \n",
852 | " Tell the user that after searching through our product database, you recommend the product described in the provided product review. \n",
853 | " Your answer should summarize the review text,\n",
854 | " include the product ID, and mention the score given in the review.\n",
855 | " \"\"\""
856 | ]
857 | },
858 | {
859 | "cell_type": "code",
860 | "execution_count": 29,
861 | "metadata": {},
862 | "outputs": [
863 | {
864 | "name": "stdout",
865 | "output_type": "stream",
866 | "text": [
867 | "Product id: B001E4KFG0. Review text: I have bought several of the Vitality canned dog food products and have found them all to be of good quality. The product looks more like a stew than a processed meat and it smells better. My Labrador is finicky and she appreciates this product better than most.. Review score: 5\n"
868 | ]
869 | }
870 | ],
871 | "source": [
872 | "# create the context from the search response (requires regenerating results)\n",
873 | "results = search_client.search(\n",
874 | " search_text=None, \n",
875 | " vector_queries= [vector_query],\n",
876 | " select=[\"Id\", \"chunk\", \"parent_product_id\", \"parent_text\", \"parent_score\"],\n",
877 | " top=1\n",
878 | ")\n",
879 | "\n",
880 | "context = \"\"\n",
881 | "for result in results:\n",
882 | " context += f\"Product id: {result['parent_product_id']}. Review text: {result['parent_text']}. Review score: {result['parent_score']}\"\n",
883 | " \n",
884 | "print(context)"
885 | ]
886 | },
887 | {
888 | "cell_type": "code",
889 | "execution_count": 30,
890 | "metadata": {},
891 | "outputs": [
892 | {
893 | "name": "stdout",
894 | "output_type": "stream",
895 | "text": [
896 | "\n",
897 | " The user's query is: Canned dog food\n",
898 | " The most relevant product review is: Product id: B001E4KFG0. Review text: I have bought several of the Vitality canned dog food products and have found them all to be of good quality. The product looks more like a stew than a processed meat and it smells better. My Labrador is finicky and she appreciates this product better than most.. Review score: 5\n",
899 | " The user is searching for a product matching their query. \n",
900 | " Tell the user that after searching through our product database, you recommend the product described in the provided product review. \n",
901 | " Your answer should summarize the review text,\n",
902 | " include the product ID, and mention the score given in the review.\n",
903 | " \n"
904 | ]
905 | }
906 | ],
907 | "source": [
908 | "prompt = template.format(context=context, query=user_query)\n",
909 | "print(prompt)"
910 | ]
911 | },
912 | {
913 | "cell_type": "markdown",
914 | "metadata": {},
915 | "source": [
916 | "### Call to OpenAI"
917 | ]
918 | },
919 | {
920 | "cell_type": "code",
921 | "execution_count": 31,
922 | "metadata": {},
923 | "outputs": [
924 | {
925 | "name": "stdout",
926 | "output_type": "stream",
927 | "text": [
928 | "Based on your query for canned dog food, we have searched through our product database and recommend product ID B001E4KFG0. This product has received a review score of 5 and the reviewer found it to be of good quality, with a stew-like appearance and better smell than processed meat. The reviewer's Labrador, who is finicky, also appreciated this product more than most. We believe this product would be a great fit for your needs.\n"
929 | ]
930 | }
931 | ],
932 | "source": [
933 | "client = openai.AzureOpenAI(\n",
934 | " azure_endpoint=openai.api_base, \n",
935 | " api_key=openai.api_key, \n",
936 | " api_version=openai.api_version\n",
937 | ")\n",
938 | "response = client.chat.completions.create( \n",
939 | " model=openai_deployment_completion,\n",
940 | " messages = [{'role':'system','content':prompt}],\n",
941 | " temperature=0, \n",
942 | " max_tokens=600,\n",
943 | " stream=False)\n",
944 | "print(response.choices[0].message.content)"
945 | ]
946 | },
947 | {
948 | "cell_type": "markdown",
949 | "metadata": {},
950 | "source": [
951 | "# How to use the index in Azure OpenAI Studio Chat Playground\n",
952 | "1. In Azure OpenAI Studio, open Chat and make sure your `completions` model is selected\n",
953 | "1. Select **Add your data** and set fields to:\n",
954 | " - Select your AI Search as data source\n",
955 | " - Select deployed resource and index named `sql-customer-index`\n",
956 | " - Check `Add vector search...`\n",
957 | "1. Select next and in Data management and set fields:\n",
958 | " - Search type `Vector`\n",
959 | "1. Select next and select `API`\n",
960 | "1. Select **Review** and **Finish** > **Save** and **Close**\n"
961 | ]
962 | },
963 | {
964 | "cell_type": "markdown",
965 | "metadata": {},
966 | "source": [
967 | "# Notes\n",
968 | "\n",
969 | "After finishing the sample, remember to delete unneeded resources:\n",
970 | "* Table created within existing SQL DB\n",
971 | "* Within the Search Service resource:\n",
972 | " * Data source connection\n",
973 | " * Index\n",
974 | " * Skillset\n",
975 | " * Indexer\n",
976 | "\n",
977 | "These can always be recreated by rerunning the notebook."
978 | ]
979 | }
980 | ],
981 | "metadata": {
982 | "kernelspec": {
983 | "display_name": "Python 3",
984 | "language": "python",
985 | "name": "python3"
986 | },
987 | "language_info": {
988 | "codemirror_mode": {
989 | "name": "ipython",
990 | "version": 3
991 | },
992 | "file_extension": ".py",
993 | "mimetype": "text/x-python",
994 | "name": "python",
995 | "nbconvert_exporter": "python",
996 | "pygments_lexer": "ipython3",
997 | "version": "3.10.14"
998 | }
999 | },
1000 | "nbformat": 4,
1001 | "nbformat_minor": 2
1002 | }
1003 |
--------------------------------------------------------------------------------
/session-delivery-resources/3-azure-sql-ai-search/src/README.md:
--------------------------------------------------------------------------------
1 | ## Setup
2 |
3 | ### 1. Create Azure Resources
4 |
5 | Create the following resources:
6 | - Resource group:
7 | - Azure SQL server and database, basic tier and be sure to `allow all azure services` to access the database in network settings.
8 | - Azure AI Search resource
9 | - Azure Open AI Service with
10 | - Deployed `GPT 3.5 Turbo` model named `completions`
11 | - Deployed `text-embedding-ada-002` model named `embeddings`
12 |
13 | ### 2. Add data and configure services
14 |
15 | -
16 | - pip install -r requirements.txt
17 | - Add resource keys to .env file
18 |
19 | Run the python script to:
20 | - Populate the `reviews_demo` database with a table named `customer_reviews` with 99 records.
21 | - Enable change tracking on the database
22 | - Set `customer_reviews` as AI Search datasource with fields configured
23 | - Create an index named `sql-customer-index` with 2 skillsets: chunking data and vectorization
24 | - Indexer for the data
25 |
26 | Alternatively, you can do this in the notebook and test it out.
27 |
28 | ### 3. Chat with data in Azure OpenAI Studio Chat Playground
29 |
30 | 1. In Azure OpenAI Studio, open Chat and make sure your `completions` model is selected
31 | 1. Select Add your data and set fields to:
32 | - Select your AI Search as data source
33 | - Select deployed resource and index named `sql-customer-index`
34 | - Check `Add vector search...`
35 | 1. Select next and in Data management and set fields:
36 | - Search type `Vector`
37 | 1. Select next and select `API`
38 | 1. Select Review and Finish > Save and Close
39 |
40 |
41 | **NOTE**: The system message will reset when you refresh the page. Consider adding the system message right before you deliver the session.
42 |
43 | Add the system message:
44 |
45 | ```
46 | The user is searching for a product matching their query. Tell the user that after searching through our product database, you recommend the product described in the provided product review. Your answer should summarize the review text, include the product ID, and mention the score given in the review. Present the answer in a readable format that clearly lists the products.
47 | ```
--------------------------------------------------------------------------------
/session-delivery-resources/3-azure-sql-ai-search/src/customer_reviews.csv:
--------------------------------------------------------------------------------
1 | ,Id,ProductId,UserId,ProfileName,HelpfulnessNumerator,HelpfulnessDenominator,Score,Time,Summary,Text,TextConcat
2 | 0,1,B001E4KFG0,A3SGXH7AUHU8GW,delmartian,1,1,5,1303862400,Good Quality Dog Food,I have bought several of the Vitality canned dog food products and have found them all to be of good quality. The product looks more like a stew than a processed meat and it smells better. My Labrador is finicky and she appreciates this product better than most.,Summary: Good Quality Dog Food | Review: I have bought several of the Vitality canned dog food products and have found them all to be of good quality. The product looks more like a stew than a processed meat and it smells better. My Labrador is finicky and she appreciates this product better than most.
3 | 1,2,B00813GRG4,A1D87F6ZCVE5NK,dll pa,0,0,1,1346976000,Not as Advertised,"Product arrived labeled as Jumbo Salted Peanuts...the peanuts were actually small sized unsalted. Not sure if this was an error or if the vendor intended to represent the product as ""Jumbo"".","Summary: Not as Advertised | Review: Product arrived labeled as Jumbo Salted Peanuts...the peanuts were actually small sized unsalted. Not sure if this was an error or if the vendor intended to represent the product as ""Jumbo""."
4 | 2,3,B000LQOCH0,ABXLMWJIXXAIN,"Natalia Corres ""Natalia Corres""",1,1,4,1219017600,"""Delight"" says it all","This is a confection that has been around a few centuries. It is a light, pillowy citrus gelatin with nuts - in this case Filberts. And it is cut into tiny squares and then liberally coated with powdered sugar. And it is a tiny mouthful of heaven. Not too chewy, and very flavorful. I highly recommend this yummy treat. If you are familiar with the story of C.S. Lewis' ""The Lion, The Witch, and The Wardrobe"" - this is the treat that seduces Edmund into selling out his Brother and Sisters to the Witch.","Summary: ""Delight"" says it all | Review: This is a confection that has been around a few centuries. It is a light, pillowy citrus gelatin with nuts - in this case Filberts. And it is cut into tiny squares and then liberally coated with powdered sugar. And it is a tiny mouthful of heaven. Not too chewy, and very flavorful. I highly recommend this yummy treat. If you are familiar with the story of C.S. Lewis' ""The Lion, The Witch, and The Wardrobe"" - this is the treat that seduces Edmund into selling out his Brother and Sisters to the Witch."
5 | 3,4,B000UA0QIQ,A395BORC6FGVXV,Karl,3,3,2,1307923200,Cough Medicine,If you are looking for the secret ingredient in Robitussin I believe I have found it. I got this in addition to the Root Beer Extract I ordered (which was good) and made some cherry soda. The flavor is very medicinal.,Summary: Cough Medicine | Review: If you are looking for the secret ingredient in Robitussin I believe I have found it. I got this in addition to the Root Beer Extract I ordered (which was good) and made some cherry soda. The flavor is very medicinal.
6 | 4,5,B006K2ZZ7K,A1UQRSCLF8GW1T,"Michael D. Bigham ""M. Wassir""",0,0,5,1350777600,Great taffy,"Great taffy at a great price. There was a wide assortment of yummy taffy. Delivery was very quick. If your a taffy lover, this is a deal.","Summary: Great taffy | Review: Great taffy at a great price. There was a wide assortment of yummy taffy. Delivery was very quick. If your a taffy lover, this is a deal."
7 | 5,6,B006K2ZZ7K,ADT0SRK1MGOEU,Twoapennything,0,0,4,1342051200,Nice Taffy,"I got a wild hair for taffy and ordered this five pound bag. The taffy was all very enjoyable with many flavors: watermelon, root beer, melon, peppermint, grape, etc. My only complaint is there was a bit too much red/black licorice-flavored pieces (just not my particular favorites). Between me, my kids, and my husband, this lasted only two weeks! I would recommend this brand of taffy -- it was a delightful treat.","Summary: Nice Taffy | Review: I got a wild hair for taffy and ordered this five pound bag. The taffy was all very enjoyable with many flavors: watermelon, root beer, melon, peppermint, grape, etc. My only complaint is there was a bit too much red/black licorice-flavored pieces (just not my particular favorites). Between me, my kids, and my husband, this lasted only two weeks! I would recommend this brand of taffy -- it was a delightful treat."
8 | 6,7,B006K2ZZ7K,A1SP2KVKFXXRU1,David C. Sullivan,0,0,5,1340150400,Great! Just as good as the expensive brands!,"This saltwater taffy had great flavors and was very soft and chewy. Each candy was individually wrapped well. None of the candies were stuck together, which did happen in the expensive version, Fralinger's. Would highly recommend this candy! I served it at a beach-themed party and everyone loved it!","Summary: Great! Just as good as the expensive brands! | Review: This saltwater taffy had great flavors and was very soft and chewy. Each candy was individually wrapped well. None of the candies were stuck together, which did happen in the expensive version, Fralinger's. Would highly recommend this candy! I served it at a beach-themed party and everyone loved it!"
9 | 7,8,B006K2ZZ7K,A3JRGQVEQN31IQ,Pamela G. Williams,0,0,5,1336003200,"Wonderful, tasty taffy",This taffy is so good. It is very soft and chewy. The flavors are amazing. I would definitely recommend you buying it. Very satisfying!!,"Summary: Wonderful, tasty taffy | Review: This taffy is so good. It is very soft and chewy. The flavors are amazing. I would definitely recommend you buying it. Very satisfying!!"
10 | 8,9,B000E7L2R4,A1MZYO9TZK0BBI,R. James,1,1,5,1322006400,Yay Barley,Right now I'm mostly just sprouting this so my cats can eat the grass. They love it. I rotate it around with Wheatgrass and Rye too,Summary: Yay Barley | Review: Right now I'm mostly just sprouting this so my cats can eat the grass. They love it. I rotate it around with Wheatgrass and Rye too
11 | 9,10,B00171APVA,A21BT40VZCCYT4,Carol A. Reed,0,0,5,1351209600,Healthy Dog Food,This is a very healthy dog food. Good for their digestion. Also good for small puppies. My dog eats her required amount at every feeding.,Summary: Healthy Dog Food | Review: This is a very healthy dog food. Good for their digestion. Also good for small puppies. My dog eats her required amount at every feeding.
12 | 10,11,B0001PB9FE,A3HDKO7OW0QNK4,Canadian Fan,1,1,5,1107820800,The Best Hot Sauce in the World,"I don't know if it's the cactus or the tequila or just the unique combination of ingredients, but the flavour of this hot sauce makes it one of a kind! We picked up a bottle once on a trip we were on and brought it back home with us and were totally blown away! When we realized that we simply couldn't find it anywhere in our city we were bummed.
Now, because of the magic of the internet, we have a case of the sauce and are ecstatic because of it.
If you love hot sauce..I mean really love hot sauce, but don't want a sauce that tastelessly burns your throat, grab a bottle of Tequila Picante Gourmet de Inclan. Just realize that once you taste it, you will never want to use any other sauce.
Thank you for the personal, incredible service!","Summary: The Best Hot Sauce in the World | Review: I don't know if it's the cactus or the tequila or just the unique combination of ingredients, but the flavour of this hot sauce makes it one of a kind! We picked up a bottle once on a trip we were on and brought it back home with us and were totally blown away! When we realized that we simply couldn't find it anywhere in our city we were bummed.
Now, because of the magic of the internet, we have a case of the sauce and are ecstatic because of it.
If you love hot sauce..I mean really love hot sauce, but don't want a sauce that tastelessly burns your throat, grab a bottle of Tequila Picante Gourmet de Inclan. Just realize that once you taste it, you will never want to use any other sauce.
Thank you for the personal, incredible service!"
13 | 11,12,B0009XLVG0,A2725IB4YY9JEB,"A Poeng ""SparkyGoHome""",4,4,5,1282867200,"My cats LOVE this ""diet"" food better than their regular food","One of my boys needed to lose some weight and the other didn't. I put this food on the floor for the chubby guy, and the protein-rich, no by-product food up higher where only my skinny boy can jump. The higher food sits going stale. They both really go for this food. And my chubby boy has been losing about an ounce a week.","Summary: My cats LOVE this ""diet"" food better than their regular food | Review: One of my boys needed to lose some weight and the other didn't. I put this food on the floor for the chubby guy, and the protein-rich, no by-product food up higher where only my skinny boy can jump. The higher food sits going stale. They both really go for this food. And my chubby boy has been losing about an ounce a week."
14 | 12,13,B0009XLVG0,A327PCT23YH90,LT,1,1,1,1339545600,My Cats Are Not Fans of the New Food,"My cats have been happily eating Felidae Platinum for more than two years. I just got a new bag and the shape of the food is different. They tried the new food when I first put it in their bowls and now the bowls sit full and the kitties will not touch the food. I've noticed similar reviews related to formula changes in the past. Unfortunately, I now need to find a new food that my cats will eat.","Summary: My Cats Are Not Fans of the New Food | Review: My cats have been happily eating Felidae Platinum for more than two years. I just got a new bag and the shape of the food is different. They tried the new food when I first put it in their bowls and now the bowls sit full and the kitties will not touch the food. I've noticed similar reviews related to formula changes in the past. Unfortunately, I now need to find a new food that my cats will eat."
15 | 13,14,B001GVISJM,A18ECVX2RJ7HUE,"willie ""roadie""",2,2,4,1288915200,fresh and greasy!,good flavor! these came securely packed... they were fresh and delicious! i love these Twizzlers!,Summary: fresh and greasy! | Review: good flavor! these came securely packed... they were fresh and delicious! i love these Twizzlers!
16 | 14,15,B001GVISJM,A2MUGFV2TDQ47K,"Lynrie ""Oh HELL no""",4,5,5,1268352000,Strawberry Twizzlers - Yummy,The Strawberry Twizzlers are my guilty pleasure - yummy. Six pounds will be around for a while with my son and I.,Summary: Strawberry Twizzlers - Yummy | Review: The Strawberry Twizzlers are my guilty pleasure - yummy. Six pounds will be around for a while with my son and I.
17 | 15,16,B001GVISJM,A1CZX3CP8IKQIJ,Brian A. Lee,4,5,5,1262044800,"Lots of twizzlers, just what you expect.",My daughter loves twizzlers and this shipment of six pounds really hit the spot. It's exactly what you would expect...six packages of strawberry twizzlers.,"Summary: Lots of twizzlers, just what you expect. | Review: My daughter loves twizzlers and this shipment of six pounds really hit the spot. It's exactly what you would expect...six packages of strawberry twizzlers."
18 | 16,17,B001GVISJM,A3KLWF6WQ5BNYO,Erica Neathery,0,0,2,1348099200,poor taste,I love eating them and they are good for watching TV and looking at movies! It is not too sweet. I like to transfer them to a zip lock baggie so they stay fresh so I can take my time eating them.,Summary: poor taste | Review: I love eating them and they are good for watching TV and looking at movies! It is not too sweet. I like to transfer them to a zip lock baggie so they stay fresh so I can take my time eating them.
19 | 17,18,B001GVISJM,AFKW14U97Z6QO,Becca,0,0,5,1345075200,Love it!,I am very satisfied with my Twizzler purchase. I shared these with others and we have all enjoyed them. I will definitely be ordering more.,Summary: Love it! | Review: I am very satisfied with my Twizzler purchase. I shared these with others and we have all enjoyed them. I will definitely be ordering more.
20 | 18,19,B001GVISJM,A2A9X58G2GTBLP,Wolfee1,0,0,5,1324598400,GREAT SWEET CANDY!,"Twizzlers, Strawberry my childhood favorite candy, made in Lancaster Pennsylvania by Y & S Candies, Inc. one of the oldest confectionery Firms in the United States, now a Subsidiary of the Hershey Company, the Company was established in 1845 as Young and Smylie, they also make Apple Licorice Twists, Green Color and Blue Raspberry Licorice Twists, I like them all
I keep it in a dry cool place because is not recommended it to put it in the fridge. According to the Guinness Book of Records, the longest Licorice Twist ever made measured 1.200 Feet (370 M) and weighted 100 Pounds (45 Kg) and was made by Y & S Candies, Inc. This Record-Breaking Twist became a Guinness World Record on July 19, 1998. This Product is Kosher! Thank You","Summary: GREAT SWEET CANDY! | Review: Twizzlers, Strawberry my childhood favorite candy, made in Lancaster Pennsylvania by Y & S Candies, Inc. one of the oldest confectionery Firms in the United States, now a Subsidiary of the Hershey Company, the Company was established in 1845 as Young and Smylie, they also make Apple Licorice Twists, Green Color and Blue Raspberry Licorice Twists, I like them all
I keep it in a dry cool place because is not recommended it to put it in the fridge. According to the Guinness Book of Records, the longest Licorice Twist ever made measured 1.200 Feet (370 M) and weighted 100 Pounds (45 Kg) and was made by Y & S Candies, Inc. This Record-Breaking Twist became a Guinness World Record on July 19, 1998. This Product is Kosher! Thank You"
21 | 19,20,B001GVISJM,A3IV7CL2C13K2U,Greg,0,0,5,1318032000,Home delivered twizlers,Candy was delivered very fast and was purchased at a reasonable price. I was home bound and unable to get to a store so this was perfect for me.,Summary: Home delivered twizlers | Review: Candy was delivered very fast and was purchased at a reasonable price. I was home bound and unable to get to a store so this was perfect for me.
22 | 20,21,B001GVISJM,A1WO0KGLPR5PV6,mom2emma,0,0,5,1313452800,Always fresh,"My husband is a Twizzlers addict. We've bought these many times from Amazon because we're government employees living overseas and can't get them in the country we are assigned to. They've always been fresh and tasty, packed well and arrive in a timely manner.","Summary: Always fresh | Review: My husband is a Twizzlers addict. We've bought these many times from Amazon because we're government employees living overseas and can't get them in the country we are assigned to. They've always been fresh and tasty, packed well and arrive in a timely manner."
23 | 21,22,B001GVISJM,AZOF9E17RGZH8,Tammy Anderson,0,0,5,1308960000,TWIZZLERS,"I bought these for my husband who is currently overseas. He loves these, and apparently his staff likes them also.
There are generous amounts of Twizzlers in each 16-ounce bag, and this was well worth the price. Twizzlers, Strawberry, 16-Ounce Bags (Pack of 6)","Summary: TWIZZLERS | Review: I bought these for my husband who is currently overseas. He loves these, and apparently his staff likes them also.
There are generous amounts of Twizzlers in each 16-ounce bag, and this was well worth the price. Twizzlers, Strawberry, 16-Ounce Bags (Pack of 6)"
24 | 22,23,B001GVISJM,ARYVQL4N737A1,Charles Brown,0,0,5,1304899200,Delicious product!,I can remember buying this candy as a kid and the quality hasn't dropped in all these years. Still a superb product you won't be disappointed with.,Summary: Delicious product! | Review: I can remember buying this candy as a kid and the quality hasn't dropped in all these years. Still a superb product you won't be disappointed with.
25 | 23,24,B001GVISJM,AJ613OLZZUG7V,Mare's,0,0,5,1304467200,Twizzlers,I love this candy. After weight watchers I had to cut back but still have a craving for it.,Summary: Twizzlers | Review: I love this candy. After weight watchers I had to cut back but still have a craving for it.
26 | 24,25,B001GVISJM,A22P2J09NJ9HKE,"S. Cabanaugh ""jilly pepper""",0,0,5,1295481600,Please sell these in Mexico!!,"I have lived out of the US for over 7 yrs now, and I so miss my Twizzlers!! When I go back to visit or someone visits me, I always stock up. All I can say is YUM!
Sell these in Mexico and you will have a faithful buyer, more often than I'm able to buy them right now.","Summary: Please sell these in Mexico!! | Review: I have lived out of the US for over 7 yrs now, and I so miss my Twizzlers!! When I go back to visit or someone visits me, I always stock up. All I can say is YUM!
Sell these in Mexico and you will have a faithful buyer, more often than I'm able to buy them right now."
27 | 25,26,B001GVISJM,A3FONPR03H3PJS,"Deborah S. Linzer ""Cat Lady""",0,0,5,1288310400,Twizzlers - Strawberry,"Product received is as advertised.
Twizzlers, Strawberry, 16-Ounce Bags (Pack of 6)","Summary: Twizzlers - Strawberry | Review: Product received is as advertised.
Twizzlers, Strawberry, 16-Ounce Bags (Pack of 6)"
28 | 26,27,B001GVISJM,A3RXAU2N8KV45G,lady21,0,1,1,1332633600,Nasty No flavor,"The candy is just red , No flavor . Just plan and chewy . I would never buy them again","Summary: Nasty No flavor | Review: The candy is just red , No flavor . Just plan and chewy . I would never buy them again"
29 | 27,28,B001GVISJM,AAAS38B98HMIK,Heather Dube,0,1,4,1331856000,Great Bargain for the Price,I was so glad Amazon carried these batteries. I have a hard time finding them elsewhere because they are such a unique size. I need them for my garage door opener.
Great deal for the price.,Summary: Great Bargain for the Price | Review: I was so glad Amazon carried these batteries. I have a hard time finding them elsewhere because they are such a unique size. I need them for my garage door opener.
Great deal for the price.
30 | 28,29,B00144C10S,A2F4LZVGFLD1OB,DaisyH,0,0,5,1338854400,YUMMY!,"I got this for my Mum who is not diabetic but needs to watch her sugar intake, and my father who simply chooses to limit unnecessary sugar intake - she's the one with the sweet tooth - they both LOVED these toffees, you would never guess that they're sugar-free and it's so great that you can eat them pretty much guilt free! i was so impressed that i've ordered some for myself (w dark chocolate) to take to the office so i'll eat them instead of snacking on sugary sweets.
These are just EXCELLENT!","Summary: YUMMY! | Review: I got this for my Mum who is not diabetic but needs to watch her sugar intake, and my father who simply chooses to limit unnecessary sugar intake - she's the one with the sweet tooth - they both LOVED these toffees, you would never guess that they're sugar-free and it's so great that you can eat them pretty much guilt free! i was so impressed that i've ordered some for myself (w dark chocolate) to take to the office so i'll eat them instead of snacking on sugary sweets.
These are just EXCELLENT!"
31 | 29,30,B0001PB9FY,A3HDKO7OW0QNK4,Canadian Fan,1,1,5,1107820800,The Best Hot Sauce in the World,"I don't know if it's the cactus or the tequila or just the unique combination of ingredients, but the flavour of this hot sauce makes it one of a kind! We picked up a bottle once on a trip we were on and brought it back home with us and were totally blown away! When we realized that we simply couldn't find it anywhere in our city we were bummed.
Now, because of the magic of the internet, we have a case of the sauce and are ecstatic because of it.
If you love hot sauce..I mean really love hot sauce, but don't want a sauce that tastelessly burns your throat, grab a bottle of Tequila Picante Gourmet de Inclan. Just realize that once you taste it, you will never want to use any other sauce.
Thank you for the personal, incredible service!","Summary: The Best Hot Sauce in the World | Review: I don't know if it's the cactus or the tequila or just the unique combination of ingredients, but the flavour of this hot sauce makes it one of a kind! We picked up a bottle once on a trip we were on and brought it back home with us and were totally blown away! When we realized that we simply couldn't find it anywhere in our city we were bummed.
Now, because of the magic of the internet, we have a case of the sauce and are ecstatic because of it.
If you love hot sauce..I mean really love hot sauce, but don't want a sauce that tastelessly burns your throat, grab a bottle of Tequila Picante Gourmet de Inclan. Just realize that once you taste it, you will never want to use any other sauce.
Thank you for the personal, incredible service!"
32 | 30,31,B003F6UO7K,AFM0O9480F04W,Sherril,0,0,5,1297641600,Great machine!,"I have never been a huge coffee fan. However, my mother purchased this little machine and talked me into trying the Latte Macciato. No Coffee Shop has a better one and I like most of the other products, too (as a usually non-coffee drinker!).
The little Dolche Guesto Machine is super easy to use and prepares a really good Coffee/Latte/Cappuccino/etc in less than a minute (if water is heated up). I would recommend the Dolce Gusto to anyone. Too good for the price and I'am getting one myself! :)","Summary: Great machine! | Review: I have never been a huge coffee fan. However, my mother purchased this little machine and talked me into trying the Latte Macciato. No Coffee Shop has a better one and I like most of the other products, too (as a usually non-coffee drinker!).
The little Dolche Guesto Machine is super easy to use and prepares a really good Coffee/Latte/Cappuccino/etc in less than a minute (if water is heated up). I would recommend the Dolce Gusto to anyone. Too good for the price and I'am getting one myself! :)"
33 | 31,32,B003F6UO7K,A31OQO709M20Y7,"Molly V. Smith ""staral""",0,1,5,1288310400,THIS IS MY TASTE...,"This offer is a great price and a great taste, thanks Amazon for selling this product.
Staral","Summary: THIS IS MY TASTE... | Review: This offer is a great price and a great taste, thanks Amazon for selling this product.
Staral"
34 | 32,33,B001EO5QW8,AOVROBZ8BNTP7,S. Potter,19,19,4,1163376000,Best of the Instant Oatmeals,"McCann's Instant Oatmeal is great if you must have your oatmeal but can only scrape together two or three minutes to prepare it. There is no escaping the fact, however, that even the best instant oatmeal is nowhere near as good as even a store brand of oatmeal requiring stovetop preparation. Still, the McCann's is as good as it gets for instant oatmeal. It's even better than the organic, all-natural brands I have tried. All the varieties in the McCann's variety pack taste good. It can be prepared in the microwave or by adding boiling water so it is convenient in the extreme when time is an issue.
McCann's use of actual cane sugar instead of high fructose corn syrup helped me decide to buy this product. Real sugar tastes better and is not as harmful as the other stuff. One thing I do not like, though, is McCann's use of thickeners. Oats plus water plus heat should make a creamy, tasty oatmeal without the need for guar gum. But this is a convenience product. Maybe the guar gum is why, after sitting in the bowl a while, the instant McCann's becomes too thick and gluey.","Summary: Best of the Instant Oatmeals | Review: McCann's Instant Oatmeal is great if you must have your oatmeal but can only scrape together two or three minutes to prepare it. There is no escaping the fact, however, that even the best instant oatmeal is nowhere near as good as even a store brand of oatmeal requiring stovetop preparation. Still, the McCann's is as good as it gets for instant oatmeal. It's even better than the organic, all-natural brands I have tried. All the varieties in the McCann's variety pack taste good. It can be prepared in the microwave or by adding boiling water so it is convenient in the extreme when time is an issue.
McCann's use of actual cane sugar instead of high fructose corn syrup helped me decide to buy this product. Real sugar tastes better and is not as harmful as the other stuff. One thing I do not like, though, is McCann's use of thickeners. Oats plus water plus heat should make a creamy, tasty oatmeal without the need for guar gum. But this is a convenience product. Maybe the guar gum is why, after sitting in the bowl a while, the instant McCann's becomes too thick and gluey."
35 | 33,34,B001EO5QW8,A3PMM0NFVEJGK9,"Megan ""Bad at Nicknames""",13,13,4,1166313600,Good Instant,"This is a good instant oatmeal from the best oatmeal brand. It uses cane sugar instead of high fructouse corn syrup, so not only does it have a better sweetness, but some doctors now say that this form of sugar is better for you. Great on a cold morning when you don't have time to make McCann's Steel Cut Oats. The apple cinnamon is the best but the maple and brown sugar or the regular are good too. Plus they don't require doctoring to actually tell the three flavors apart.","Summary: Good Instant | Review: This is a good instant oatmeal from the best oatmeal brand. It uses cane sugar instead of high fructouse corn syrup, so not only does it have a better sweetness, but some doctors now say that this form of sugar is better for you. Great on a cold morning when you don't have time to make McCann's Steel Cut Oats. The apple cinnamon is the best but the maple and brown sugar or the regular are good too. Plus they don't require doctoring to actually tell the three flavors apart."
36 | 34,35,B001EO5QW8,A2EB6OGOWCRU5H,CorbyJames,9,9,5,1175212800,Great Irish oatmeal for those in a hurry!,"Instant oatmeal can become soggy the minute the water hits the bowl. McCann's Instant Oatmeal holds its texture, has excellent flavor, and is good for you all at the same time. McCann's regular oat meal is excellent, too, but may take a bit longer to prepare than most have time for in the morning. This is the best instant brand I've ever eaten, and a very close second to the non-instant variety.
McCann's Instant Irish Oatmeal, Variety Pack of Regular, Apples & Cinnamon, and Maple & Brown Sugar, 10-Count Boxes (Pack of 6)","Summary: Great Irish oatmeal for those in a hurry! | Review: Instant oatmeal can become soggy the minute the water hits the bowl. McCann's Instant Oatmeal holds its texture, has excellent flavor, and is good for you all at the same time. McCann's regular oat meal is excellent, too, but may take a bit longer to prepare than most have time for in the morning. This is the best instant brand I've ever eaten, and a very close second to the non-instant variety.
McCann's Instant Irish Oatmeal, Variety Pack of Regular, Apples & Cinnamon, and Maple & Brown Sugar, 10-Count Boxes (Pack of 6)"
37 | 35,36,B001EO5QW8,A2CI0RLADCRKPF,T. J. Ryan,3,3,4,1210464000,satisfying,"McCann's Instant Irish Oatmeal, Variety Pack of Regular, Apples & Cinnamon, and Maple & Brown Sugar, 10-Count Boxes (Pack of 6)
I'm a fan of the McCann's steel-cut oats, so I thought I'd give the instant variety a try. I found it to be a hardy meal, not too sweet, and great for folks like me (post-bariatric surgery) who need food that is palatable, easily digestible, with fiber but won't make you bloat.","Summary: satisfying | Review: McCann's Instant Irish Oatmeal, Variety Pack of Regular, Apples & Cinnamon, and Maple & Brown Sugar, 10-Count Boxes (Pack of 6)
I'm a fan of the McCann's steel-cut oats, so I thought I'd give the instant variety a try. I found it to be a hardy meal, not too sweet, and great for folks like me (post-bariatric surgery) who need food that is palatable, easily digestible, with fiber but won't make you bloat."
38 | 36,37,B001EO5QW8,A1MYS9LFFBIYKM,"Abby Chase ""gluten free""",2,2,5,1190851200,Love Gluten Free Oatmeal!!!,"For those of us with celiac disease this product is a lifesaver and what could be better than getting it at almost half the price of the grocery or health food store! I love McCann's instant oatmeal - all flavors!!!
Thanks,
Abby","Summary: Love Gluten Free Oatmeal!!! | Review: For those of us with celiac disease this product is a lifesaver and what could be better than getting it at almost half the price of the grocery or health food store! I love McCann's instant oatmeal - all flavors!!!
Thanks,
Abby"
39 | 37,38,B001EO5QW8,A3MGP2E1ZZ6GRB,"Zardoz ""focuspuller""",1,1,5,1238457600,it's oatmeal,"What else do you need to know? Oatmeal, instant (make it with a half cup of low-fat milk and add raisins;nuke for 90 seconds). More expensive than Kroger store brand oatmeal and maybe a little tastier or better texture or something. It's still just oatmeal. Mmm, convenient!","Summary: it's oatmeal | Review: What else do you need to know? Oatmeal, instant (make it with a half cup of low-fat milk and add raisins;nuke for 90 seconds). More expensive than Kroger store brand oatmeal and maybe a little tastier or better texture or something. It's still just oatmeal. Mmm, convenient!"
40 | 38,39,B001EO5QW8,A2GHZ2UTV2B0CD,JERRY REITH,0,0,4,1350777600,GOOD WAY TO START THE DAY....,"I WAS VISITING MY FRIEND NATE THE OTHER MORNING FOR COFFEE , HE CAME OUT OF HIS STORAGE ROOM WITH ( A PACKET OF McCANNS INSTANT IRISH OATMEAL .) HE SUGGESTED THAT I TRY IT FOR MY OWN USE ,IN MY STASH . SOMETIMES NATE DOSE NOT GIVE YOU A CHANCE TO SAY NO , SO I ENDED UP TRYING THE APPLE AND CINN . FOUND IT TO BE VERY TASTEFULL WHEN MADE WITH WATER OR POWDERED MILK . IT GOES GOOD WITH O.J. AND COFFEE AND A SLICE OF TOAST AND YOUR READY TO TAKE ON THE WORLD...OR THE DAY AT LEAST.. JERRY REITH...","Summary: GOOD WAY TO START THE DAY.... | Review: I WAS VISITING MY FRIEND NATE THE OTHER MORNING FOR COFFEE , HE CAME OUT OF HIS STORAGE ROOM WITH ( A PACKET OF McCANNS INSTANT IRISH OATMEAL .) HE SUGGESTED THAT I TRY IT FOR MY OWN USE ,IN MY STASH . SOMETIMES NATE DOSE NOT GIVE YOU A CHANCE TO SAY NO , SO I ENDED UP TRYING THE APPLE AND CINN . FOUND IT TO BE VERY TASTEFULL WHEN MADE WITH WATER OR POWDERED MILK . IT GOES GOOD WITH O.J. AND COFFEE AND A SLICE OF TOAST AND YOUR READY TO TAKE ON THE WORLD...OR THE DAY AT LEAST.. JERRY REITH..."
41 | 39,40,B001EO5QW8,AO80AC8313NIZ,kYpondman,0,0,5,1317168000,Wife's favorite Breakfast,"I ordered this for my wife as it was reccomended by our daughter. She has this almost every morning and likes all flavors. She's happy, I'm happy!!!
McCANN'S Instant Irish Oatmeal, Variety Pack of Regular, Apples & Cinnamon, and Maple & Brown Sugar, 10-Count Boxes (Pack of 6)","Summary: Wife's favorite Breakfast | Review: I ordered this for my wife as it was reccomended by our daughter. She has this almost every morning and likes all flavors. She's happy, I'm happy!!!
McCANN'S Instant Irish Oatmeal, Variety Pack of Regular, Apples & Cinnamon, and Maple & Brown Sugar, 10-Count Boxes (Pack of 6)"
42 | 40,41,B001EO5QW8,AQCY5KRO7489S,Garrett,0,0,5,1303430400,Why wouldn't you buy oatmeal from Mcanns? Tastes great!,"The variety packs taste great!
I have them every morning. At $0.30 cents per meal, I don't understand why everyone on earth isn't buying this stuff up.
Maple and brown sugar is terrific, followed by apples and cinnamon, followed by regular. You don't get tired of the same ole thing, and they taste great.
I just boil water from a small pot, empty the packet or 2 in a bowl, pour in boiling water, and watch it expand to 2x its size!
Taste really good and takes minutes to prepare.
Not sure why everyone on earth isn't this. Convenient, healthy, very quick, excellent quality, and extremely cheap...","Summary: Why wouldn't you buy oatmeal from Mcanns? Tastes great! | Review: The variety packs taste great!
I have them every morning. At $0.30 cents per meal, I don't understand why everyone on earth isn't buying this stuff up.
Maple and brown sugar is terrific, followed by apples and cinnamon, followed by regular. You don't get tired of the same ole thing, and they taste great.
I just boil water from a small pot, empty the packet or 2 in a bowl, pour in boiling water, and watch it expand to 2x its size!
Taste really good and takes minutes to prepare.
Not sure why everyone on earth isn't this. Convenient, healthy, very quick, excellent quality, and extremely cheap..."
43 | 41,42,B001EO5QW8,A1WK4ALVZDYPUE,"Dick Baldwin ""christobe""",0,0,5,1302134400,Oatmeal For Oatmeal Lovers,"McCann's makes oatmeal for every oatmeal connoisseur, whether one likes it from the raw pellet state that cooks for half an hour, to the sloth addled instant, which can be done in the microwave for under three minutes. It's all good, that's for sure, and the beauty of the instant variety is that it is available in different flavors as well as regular.
This variety pack allows different tastes to be explored, as well as giving you a chance to experience the difference between McCann's and other well-known oatmeals. What I personally like about McCann's is that it cooks up thicker and with more body than the top brand here in America. The Apples & Cinnamon, though, tends to be a little liquidy so you may want to experiment with the amount of water you add. In my 1300watt microwave the oatmeal cooks up in about one minute and twenty-seven seconds, so you should also watch that to get a handle on how much time and water to use.
The only bad thing -- if you can consider it a bad thing -- about this offering is that you have to buy in lot so you'll end up with six ten-count boxes. This is good if you have a whole family of oatmeal-eaters, but if you're a single person alone -- well, love oatmeal.","Summary: Oatmeal For Oatmeal Lovers | Review: McCann's makes oatmeal for every oatmeal connoisseur, whether one likes it from the raw pellet state that cooks for half an hour, to the sloth addled instant, which can be done in the microwave for under three minutes. It's all good, that's for sure, and the beauty of the instant variety is that it is available in different flavors as well as regular.
This variety pack allows different tastes to be explored, as well as giving you a chance to experience the difference between McCann's and other well-known oatmeals. What I personally like about McCann's is that it cooks up thicker and with more body than the top brand here in America. The Apples & Cinnamon, though, tends to be a little liquidy so you may want to experiment with the amount of water you add. In my 1300watt microwave the oatmeal cooks up in about one minute and twenty-seven seconds, so you should also watch that to get a handle on how much time and water to use.
The only bad thing -- if you can consider it a bad thing -- about this offering is that you have to buy in lot so you'll end up with six ten-count boxes. This is good if you have a whole family of oatmeal-eaters, but if you're a single person alone -- well, love oatmeal."
44 | 42,43,B001EO5QW8,A16XFOYQSJREL7,Roger Pugliese,0,0,5,1287014400,Food-Great,I have McCann's Oatmeal every morning and by ordering it from Amazon I am able to save almost $3.00 per box.
It is a great product. Tastes great and very healthy,Summary: Food-Great | Review: I have McCann's Oatmeal every morning and by ordering it from Amazon I am able to save almost $3.00 per box.
It is a great product. Tastes great and very healthy
45 | 43,44,B001EO5QW8,A17DW6SUOC70DJ,Mother of 9,0,0,5,1255392000,Good Hot Breakfast,"McCann's Oatmeal is a good quality choice. Our favorite is the Apples and Cinnamon, but we find that none of these are overly sugary. For a good hot breakfast in 2 minutes, this is excellent.","Summary: Good Hot Breakfast | Review: McCann's Oatmeal is a good quality choice. Our favorite is the Apples and Cinnamon, but we find that none of these are overly sugary. For a good hot breakfast in 2 minutes, this is excellent."
46 | 44,45,B001EO5QW8,A2G7B7FKP2O2PU,D. Leschke,0,0,5,1209686400,Great taste and convenience,We really like the McCann's steel cut oats but find we don't cook it up too often.
This tastes much better to me than the grocery store brands and is just as convenient.
Anything that keeps me eating oatmeal regularly is a good thing.,Summary: Great taste and convenience | Review: We really like the McCann's steel cut oats but find we don't cook it up too often.
This tastes much better to me than the grocery store brands and is just as convenient.
Anything that keeps me eating oatmeal regularly is a good thing.
47 | 45,46,B001EO5QW8,A39Z97950MCTQE,K. A. Freel,0,0,3,1205193600,Hearty Oatmeal,"This seems a little more wholesome than some of the supermarket brands, but it is somewhat mushy and doesn't have quite as much flavor either. It didn't pass muster with my kids, so I probably won't buy it again.","Summary: Hearty Oatmeal | Review: This seems a little more wholesome than some of the supermarket brands, but it is somewhat mushy and doesn't have quite as much flavor either. It didn't pass muster with my kids, so I probably won't buy it again."
48 | 46,47,B001EO5QW8,AQLL2R1PPR46X,grumpyrainbow,0,0,5,1192752000,good,Good oatmeal. I like the apple cinnamon the best. Though I wouldn't follow the directions on the package since it always comes out too soupy for my taste. That could just be me since I like my oatmeal really thick to add some milk on top of.,Summary: good | Review: Good oatmeal. I like the apple cinnamon the best. Though I wouldn't follow the directions on the package since it always comes out too soupy for my taste. That could just be me since I like my oatmeal really thick to add some milk on top of.
49 | 47,48,B001EO5QW8,A26AY1TFK8BQXQ,"kbogo ""shoelover""",1,2,3,1200096000,Mushy,"The flavors are good. However, I do not see any differce between this and Oaker Oats brand - they are both mushy.","Summary: Mushy | Review: The flavors are good. However, I do not see any differce between this and Oaker Oats brand - they are both mushy."
50 | 48,49,B001EO5QW8,ALOR97KTZTK1P,knitty pants,1,2,4,1191715200,Very good but next time I won't order the Variety Pack,"I really like the Maple and Brown Sugar flavor. The regular is fine with brown sugar added. The Apples and Cinnamon flavor is OK. This is a very quick, easy and satisfying breakfast and I'll order this brand again, but not the variety. I'll get all Maple and Brown Sugar.","Summary: Very good but next time I won't order the Variety Pack | Review: I really like the Maple and Brown Sugar flavor. The regular is fine with brown sugar added. The Apples and Cinnamon flavor is OK. This is a very quick, easy and satisfying breakfast and I'll order this brand again, but not the variety. I'll get all Maple and Brown Sugar."
51 | 49,50,B001EO5QW8,A276999Y6VRSCQ,JMay,0,1,3,1334016000,Same stuff,This is the same stuff you can buy at the big box stores. There is nothing healthy about it. It is just carbs and sugars. Save your money and get something that at least has some taste.,Summary: Same stuff | Review: This is the same stuff you can buy at the big box stores. There is nothing healthy about it. It is just carbs and sugars. Save your money and get something that at least has some taste.
52 | 50,51,B001EO5QW8,A108P30XVUFKXY,Roberto A,0,7,1,1203379200,Don't like it,"This oatmeal is not good. Its mushy, soft, I don't like it. Quaker Oats is the way to go.","Summary: Don't like it | Review: This oatmeal is not good. Its mushy, soft, I don't like it. Quaker Oats is the way to go."
53 | 51,52,B000G6RPMY,A3S5KJDA6ED2PS,Mike Kaser,4,4,5,1243900800,HOT! And good! Came back for more :),"Got a free package of these with a bottle of bloody mary mix I bought from the seller, and the advertising worked..lol, I tried them, and shared them with 2 buddies, and we all loved them... So im here to buy more, and noticed there were no reviews yet,... well now there is. They are Hot, but not ""burn your mouth forever hot"" its a nice temp... Perfect for us..","Summary: HOT! And good! Came back for more :) | Review: Got a free package of these with a bottle of bloody mary mix I bought from the seller, and the advertising worked..lol, I tried them, and shared them with 2 buddies, and we all loved them... So im here to buy more, and noticed there were no reviews yet,... well now there is. They are Hot, but not ""burn your mouth forever hot"" its a nice temp... Perfect for us.."
54 | 52,53,B000G6RPMY,A9L6L5H9BPEBO,Edwin C. Pauzer,1,1,4,1348876800,You'll go nuts over Ass-Kickin' Peanuts.,"This wasn't in stock the last time I looked. I had to go to the Vermont Country Store in Weston to find it along with a jaw harp, Cranberry Horseradish Sauce, Fartless Black Bean Salsa, Apple Cider Jelly, Newton's Cradle Art in Motion and the staple Vermont Maple Syrup.
Back to the Ass Kickin Peanuts. They are hot. They will activate the perspiration glands behind your ears and under your arms. It requires a beverage as advertised, a glass of very cold milk, and a box of Kleenex since it will make your nose run. They look like ordinary peanuts which is already giving me ideas for work. I suspect that some people have been hitting my goodies in my absence, especially my colleague Greg. I'm going to take this to work at earliest opportunity and empty the contents of this can into an ordinary Planters Peanuts can, and then see whose crying or whose nose is running when I return.
The can should be shaken to ensure the spices are evenly distributed. It is important to wash your hands after consumption and not touch the eyes.
You'll go nuts over these Ass-Kickin' Peanuts.
P.S. I'm not sharing the peanuts, not deliberately, and I'll probably give Greg the jaw harp for Christmas. He'll be so insulted.","Summary: You'll go nuts over Ass-Kickin' Peanuts. | Review: This wasn't in stock the last time I looked. I had to go to the Vermont Country Store in Weston to find it along with a jaw harp, Cranberry Horseradish Sauce, Fartless Black Bean Salsa, Apple Cider Jelly, Newton's Cradle Art in Motion and the staple Vermont Maple Syrup.
Back to the Ass Kickin Peanuts. They are hot. They will activate the perspiration glands behind your ears and under your arms. It requires a beverage as advertised, a glass of very cold milk, and a box of Kleenex since it will make your nose run. They look like ordinary peanuts which is already giving me ideas for work. I suspect that some people have been hitting my goodies in my absence, especially my colleague Greg. I'm going to take this to work at earliest opportunity and empty the contents of this can into an ordinary Planters Peanuts can, and then see whose crying or whose nose is running when I return.
The can should be shaken to ensure the spices are evenly distributed. It is important to wash your hands after consumption and not touch the eyes.
You'll go nuts over these Ass-Kickin' Peanuts.
P.S. I'm not sharing the peanuts, not deliberately, and I'll probably give Greg the jaw harp for Christmas. He'll be so insulted."
55 | 53,54,B000G6RPMY,AQ9DWWYP2KJCQ,"Roel Trevino ""protomex""",0,0,3,1278028800,not ass kickin,we're used to spicy foods down here in south texas and these are not at all spicy. doubt very much habanero is used at all. could take it up a notch or two.,Summary: not ass kickin | Review: we're used to spicy foods down here in south texas and these are not at all spicy. doubt very much habanero is used at all. could take it up a notch or two.
56 | 54,55,B002GWHC0G,A1ND7WC5LXOU48,"David Belton ""Proteus 1""",2,2,4,1322438400,Roasts up a smooth brew,"I roast at home with a stove-top popcorn popper (but I do it outside, of course). These beans (Coffee Bean Direct Green Mexican Altura) seem to be well-suited for this method. The first and second cracks are distinct, and I've roasted the beans from medium to slightly dark with great results every time. The aroma is strong and persistent. The taste is smooth, velvety, yet lively.","Summary: Roasts up a smooth brew | Review: I roast at home with a stove-top popcorn popper (but I do it outside, of course). These beans (Coffee Bean Direct Green Mexican Altura) seem to be well-suited for this method. The first and second cracks are distinct, and I've roasted the beans from medium to slightly dark with great results every time. The aroma is strong and persistent. The taste is smooth, velvety, yet lively."
57 | 55,56,B002GWHC0G,A2EFAW1P3DRXWO,TJ Fairfax,0,0,5,1349395200,Our guests love it!,"We roast these in a large cast iron pan on the grill (about 1/3 of the bag at a time). The smell is wonderful and the roasted beans taste delicious too. More importantly, the coffee is smooth; no bitter aftertaste. On numerous occasions, we've had to send the roasted beans home with friends because they like it so much.","Summary: Our guests love it! | Review: We roast these in a large cast iron pan on the grill (about 1/3 of the bag at a time). The smell is wonderful and the roasted beans taste delicious too. More importantly, the coffee is smooth; no bitter aftertaste. On numerous occasions, we've had to send the roasted beans home with friends because they like it so much."
58 | 56,57,B004N5KULM,A202WR509428VF,amateur amazon shopper,2,2,5,1322438400,Awesome Deal!,Deal was awesome! Arrived before Halloween as indicated and was enough to satisfy trick or treaters. I love the quality of this product and it was much less expensive than the local store's candy.,Summary: Awesome Deal! | Review: Deal was awesome! Arrived before Halloween as indicated and was enough to satisfy trick or treaters. I love the quality of this product and it was much less expensive than the local store's candy.
59 | 57,58,B004N5KULM,ASCNNAJU6SXF8,S. Beck,1,1,5,1336176000,How can you go wrong!,"It is chocolate, what can I say. Great variety of everything our family loves. With a family of six it goes fast here. Perfect variety. Kit Kat, Reeses, take five and more.","Summary: How can you go wrong! | Review: It is chocolate, what can I say. Great variety of everything our family loves. With a family of six it goes fast here. Perfect variety. Kit Kat, Reeses, take five and more."
60 | 58,59,B004N5KULM,A2A7KXM9B4XW90,"P. Kelso ""Amazon all the way!""",0,0,5,1320364800,Awsome - Kids in neighborhood loved us!,"Great product, nice combination of chocolates and perfect size! The bags had plenty, and they were shipped promptly. The kids in the neighborhood liked our candies!","Summary: Awsome - Kids in neighborhood loved us! | Review: Great product, nice combination of chocolates and perfect size! The bags had plenty, and they were shipped promptly. The kids in the neighborhood liked our candies!"
61 | 59,60,B004N5KULM,A2QOGOXPOVKAJG,mimimc,0,0,5,1320105600,great deal.,"Halloween is over but, I sent a bag to my daughters class for her share. The chocolate was fresh and enjoyed by many.","Summary: great deal. | Review: Halloween is over but, I sent a bag to my daughters class for her share. The chocolate was fresh and enjoyed by many."
62 | 60,61,B004N5KULM,A1ZR8O62VSU4OK,"Lisa J. Szlosek ""lisa""",2,4,3,1318723200,Better price for this at Target,"Watch your prices with this. While the assortment was good, and I did get this on a gold box purchase, the price for this was
$3-4 less at Target.","Summary: Better price for this at Target | Review: Watch your prices with this. While the assortment was good, and I did get this on a gold box purchase, the price for this was
$3-4 less at Target."
63 | 61,62,B004N5KULM,A7ZK2A3VIW7X9,Peggy,0,2,5,1319414400,pretty expensive,"This bag of candy online is pretty expensive, it should be cheaper in order to compete with grocery stores, other than that, its a good combination of my favorite candy","Summary: pretty expensive | Review: This bag of candy online is pretty expensive, it should be cheaper in order to compete with grocery stores, other than that, its a good combination of my favorite candy"
64 | 62,63,B001EO5TPM,A1E09XGZUR78C6,gary sturrock,2,2,1,1215302400,stale product.,Arrived in 6 days and were so stale i could not eat any of the 6 bags!!,Summary: stale product. | Review: Arrived in 6 days and were so stale i could not eat any of the 6 bags!!
65 | 63,64,B005DUM9UQ,A3HR0ZZOFKQ97N,RLC,3,3,5,1333497600,Hammer Nutrition 's Fizz Rocks!,"I have used the endurolyte product for several years in both pill and powder form. Long desert rides on the dirt bike always found my camelbak water heavily laced with the endurolyte powder, not overly tasty, but quite effective, as I never got a cramp on these several hundred mile rides. Same for desert racing in the buggy, the camelbaks were always laced with the powder. Now we have the Fizz...what a great product! Firstly, its Hammer's endurolyte product so it's great, endurance athlete's the world over use their products. Second its convenient, handly tablets that dissovle in a fizz. Third it tastes great! Imagine getting a nice cool drink when your body is starving for hydration and electrolytes and rather than getting a ""salty"" taste, you get a refreshing lemon-lime or mango! The camelbaks always get the Fizz now. I also drop a tablet in my bottled water whenever I exercise and have a nice flavored water chock full of electrolytes. I cannot recommend this product or any hammer product highly enough.","Summary: Hammer Nutrition 's Fizz Rocks! | Review: I have used the endurolyte product for several years in both pill and powder form. Long desert rides on the dirt bike always found my camelbak water heavily laced with the endurolyte powder, not overly tasty, but quite effective, as I never got a cramp on these several hundred mile rides. Same for desert racing in the buggy, the camelbaks were always laced with the powder. Now we have the Fizz...what a great product! Firstly, its Hammer's endurolyte product so it's great, endurance athlete's the world over use their products. Second its convenient, handly tablets that dissovle in a fizz. Third it tastes great! Imagine getting a nice cool drink when your body is starving for hydration and electrolytes and rather than getting a ""salty"" taste, you get a refreshing lemon-lime or mango! The camelbaks always get the Fizz now. I also drop a tablet in my bottled water whenever I exercise and have a nice flavored water chock full of electrolytes. I cannot recommend this product or any hammer product highly enough."
66 | 64,65,B005DUM9UQ,A2XIHNXODNZGV4,"ChemProf ""chem professor""",1,1,5,1333584000,great source of electrolytes,This product serves me well as a source of electrolytes during and after a long run or bike ride.
I have tried all of the flavors but really do like the grapefruit flavor... no after-taste and I actually like the slight carbonation.
I use other Hammer products and really like their whole product line.,Summary: great source of electrolytes | Review: This product serves me well as a source of electrolytes during and after a long run or bike ride.
I have tried all of the flavors but really do like the grapefruit flavor... no after-taste and I actually like the slight carbonation.
I use other Hammer products and really like their whole product line.
67 | 65,66,B005DUM9UQ,A3TWF9DQ6MU87E,dhy4b,1,1,5,1331510400,Great for preventing cramps,This stuff really works for preventing cramping during the middle to latter stages of your rides. Pop 1 into each water bottle and you're set. Flavor is fine and goes down easy.,Summary: Great for preventing cramps | Review: This stuff really works for preventing cramping during the middle to latter stages of your rides. Pop 1 into each water bottle and you're set. Flavor is fine and goes down easy.
68 | 66,67,B005DUM9UQ,AEFIZIJ1FK1BK,Doug,0,0,5,1345161600,Low Carb Alternative to Gatorade,"For those of us on a low carb diet these little tablets are just the thing.
Two years ago I started cycling again after many years but was having heart arrhythmia after longer rides in high heat. I was drinking plain water but did a little research and thought electrolytes might be the issue. Gatorade wasn't an option because it is so loaded with carbohydrates so I looked around for a low-carb alternative. The ""zero carb"" sports drinks didn't help so what to do? One day I ran across these at my bike shop so tried a tube of them.....voila!...problem solved!!
I've shared them with two friends in particular whose problems with leg cramps were resolved while using these.
These guys got it right -- they are superbly formulated and simply work.....","Summary: Low Carb Alternative to Gatorade | Review: For those of us on a low carb diet these little tablets are just the thing.
Two years ago I started cycling again after many years but was having heart arrhythmia after longer rides in high heat. I was drinking plain water but did a little research and thought electrolytes might be the issue. Gatorade wasn't an option because it is so loaded with carbohydrates so I looked around for a low-carb alternative. The ""zero carb"" sports drinks didn't help so what to do? One day I ran across these at my bike shop so tried a tube of them.....voila!...problem solved!!
I've shared them with two friends in particular whose problems with leg cramps were resolved while using these.
These guys got it right -- they are superbly formulated and simply work....."
69 | 67,68,B005DUM9UQ,A8OFFIAL6XTOH,Bill Shirer,0,1,2,1338422400,Taste is not so good.,"I purchased the Mango flavor, and to me it doesn't take like Mango at all. There is no hint of sweetness, and unfortunately there is a hint or aftertaste almost like licorice. I've been consuming various sports nutrition products for decades, so I'm familiar and have come to like the taste of the most of the products I've tried. The mango flavor is one of the least appealing I've tasted. It's not terrible, but it's bad enough that I notice the bad taste every sip I take.","Summary: Taste is not so good. | Review: I purchased the Mango flavor, and to me it doesn't take like Mango at all. There is no hint of sweetness, and unfortunately there is a hint or aftertaste almost like licorice. I've been consuming various sports nutrition products for decades, so I'm familiar and have come to like the taste of the most of the products I've tried. The mango flavor is one of the least appealing I've tasted. It's not terrible, but it's bad enough that I notice the bad taste every sip I take."
70 | 68,69,B000E7VI7S,A1KL2LAW08X6UQ,calmnsense,0,0,3,1169251200,How much would you pay for a bag of chocolate pretzels?,"If you're impulsive like me, then $6 is ok. Don't get me wrong, the quality of these babies is very good and I have no complaints. But in retrospect, the price is a little ridiculous (esp. when you add on the shipping).","Summary: How much would you pay for a bag of chocolate pretzels? | Review: If you're impulsive like me, then $6 is ok. Don't get me wrong, the quality of these babies is very good and I have no complaints. But in retrospect, the price is a little ridiculous (esp. when you add on the shipping)."
71 | 69,70,B000E7VI7S,AWCBF2ZWIN57F,C. Salcido,0,2,5,1185753600,pretzel haven!,this was sooooo deliscious but too bad i ate em too fast and gained 2 pds! my fault,Summary: pretzel haven! | Review: this was sooooo deliscious but too bad i ate em too fast and gained 2 pds! my fault
72 | 70,71,B001GVISJC,A27TKQHFW0FB5N,Chet,2,2,5,1254355200,Great Gummi!,"These Albanese gummi bears and rings and so on are very good and tasty and high quality. The bears even have little faces. At my local candy store this type of gummi stuff (bears, rings, snakes, balls, worms, whatever) are about $10/lb. These twin packs of 4.5 or 5 pound bags is a screaming deal as far as I'm concerned. I'm probably 50 pounds deep in these friggin' things. Consumed!","Summary: Great Gummi! | Review: These Albanese gummi bears and rings and so on are very good and tasty and high quality. The bears even have little faces. At my local candy store this type of gummi stuff (bears, rings, snakes, balls, worms, whatever) are about $10/lb. These twin packs of 4.5 or 5 pound bags is a screaming deal as far as I'm concerned. I'm probably 50 pounds deep in these friggin' things. Consumed!"
73 | 71,72,B001GVISJC,A3BDOAPSF96WGQ,2tall,1,1,5,1289260800,Bigger then other brands,"Grape gummy bears are hard to find in my area. In fact pretty much anyone I talk to about grape gummy bears they think I'm lying. So I bought 10lbs... : ) These bears are a little bit bigger then the other brands and have kind of sour kick, but nothing to strong. I love grape flavored candy/soda and these are pretty good. There is another company that makes grape gummy bears that are a little bit better in my opinion, but these are well worth it for the price. I like to use the gummy bears in home made Popsicles with flavored sports drink. The salt in the sports drink makes for softer popsicles, and the gummy bears are awesome frozen. They are delicious!","Summary: Bigger then other brands | Review: Grape gummy bears are hard to find in my area. In fact pretty much anyone I talk to about grape gummy bears they think I'm lying. So I bought 10lbs... : ) These bears are a little bit bigger then the other brands and have kind of sour kick, but nothing to strong. I love grape flavored candy/soda and these are pretty good. There is another company that makes grape gummy bears that are a little bit better in my opinion, but these are well worth it for the price. I like to use the gummy bears in home made Popsicles with flavored sports drink. The salt in the sports drink makes for softer popsicles, and the gummy bears are awesome frozen. They are delicious!"
74 | 72,73,B006SQBRMA,ATYMT48R62ENE,Marie,0,0,5,1327017600,Best ever latice tart,"I ordered two of these and two of raspberry latice tarts directly from FantasiCakes website for a dinner party I was hosting. It arrived fresh and intact. Very good size. I froze half for later use. I am a pastry lover and these were the best I've ever tasted. The pastry was soft, the jam was really good and the taste was great. They were gone in no time. My guests were really impressed.","Summary: Best ever latice tart | Review: I ordered two of these and two of raspberry latice tarts directly from FantasiCakes website for a dinner party I was hosting. It arrived fresh and intact. Very good size. I froze half for later use. I am a pastry lover and these were the best I've ever tasted. The pastry was soft, the jam was really good and the taste was great. They were gone in no time. My guests were really impressed."
75 | 73,74,B0059WXJKM,A25VFHVGI4CFTP,Diana Robinson,0,1,1,1335744000,Warning! WARNING! -ALCOHOL SUGARS!,"Buyer Beware Please! This sweetener is not for everybody. Maltitol is an alcohol sugar and can be undigestible in the body. You will know a short time after consuming it if you are one of the unsuspecting many who cannot digest it by the extreme intestinal bloating and cramping and massive amounts of gas a person can experience. Nausea, diarrhea & headaches can also be experienced. I learned my lesson the hard way years ago when I fell in love with the sugar-free chocolates suzanne sommers used to sell. I thought I'd found sugar-free chocolate nirvana at first taste but the bliss was short lived when the terrible side effects of maltitol kicked in. The discomfort was unlike anything I had ever felt before. I blew up like a balloon and had very painful abdominal cramping. As the symptoms passed, this too was very unpleasant. Though hard for me to believe a low calorie sweetener could be the culprit, all symptoms were gone when I stopped eating the chocolate. My hunch it had something to do with the maltitol were unfortunately confirmed for me about a year later when I purchased some delicious sugar-free popcorn at my local market. The taste was amazing and while I was looking at the label wondering what could possibly make this yummy, new sugarfree treat taste so good, my heart sank when I followed the little asterisk next to sugarfree sweetener* down to the very bottom of the label and read ""maltitol"" in tiny little letters! Thank goodness I'd eaten only a little. I still ended up with all the same side-effects but for a much shorter duration. Some people can use maltitol to their heart's content but others, like me, can have a bad reaction to it. In case you're like me, ... it's not you ...it's the maltitol!","Summary: Warning! WARNING! -ALCOHOL SUGARS! | Review: Buyer Beware Please! This sweetener is not for everybody. Maltitol is an alcohol sugar and can be undigestible in the body. You will know a short time after consuming it if you are one of the unsuspecting many who cannot digest it by the extreme intestinal bloating and cramping and massive amounts of gas a person can experience. Nausea, diarrhea & headaches can also be experienced. I learned my lesson the hard way years ago when I fell in love with the sugar-free chocolates suzanne sommers used to sell. I thought I'd found sugar-free chocolate nirvana at first taste but the bliss was short lived when the terrible side effects of maltitol kicked in. The discomfort was unlike anything I had ever felt before. I blew up like a balloon and had very painful abdominal cramping. As the symptoms passed, this too was very unpleasant. Though hard for me to believe a low calorie sweetener could be the culprit, all symptoms were gone when I stopped eating the chocolate. My hunch it had something to do with the maltitol were unfortunately confirmed for me about a year later when I purchased some delicious sugar-free popcorn at my local market. The taste was amazing and while I was looking at the label wondering what could possibly make this yummy, new sugarfree treat taste so good, my heart sank when I followed the little asterisk next to sugarfree sweetener* down to the very bottom of the label and read ""maltitol"" in tiny little letters! Thank goodness I'd eaten only a little. I still ended up with all the same side-effects but for a much shorter duration. Some people can use maltitol to their heart's content but others, like me, can have a bad reaction to it. In case you're like me, ... it's not you ...it's the maltitol!"
76 | 74,75,B001EPPI84,A3Q0IDQ03S0158,Jen,0,0,2,1287705600,nothing special,It is okay. I would not go out of my way to buy it again,Summary: nothing special | Review: It is okay. I would not go out of my way to buy it again
77 | 75,76,B001EPPI84,A27TZ4WBU7N0YF,I. So,0,0,1,1275004800,No Tea Flavor,No tea flavor at all. Just whole brunch of artifial flavors. It is not returnable. I wasted 20+ bucks.,Summary: No Tea Flavor | Review: No tea flavor at all. Just whole brunch of artifial flavors. It is not returnable. I wasted 20+ bucks.
78 | 76,77,B004X2KR36,A2W3ABLWMJ84NS,Jessica Snyder,0,0,5,1348444800,Good,"These looked like a perfect snack to through in with my trail mix. Unfortunately, they arrived in a solid mass of melted chocolate. I left them in my pantry for a few days, and when I opened them at room temperature they were still gooey. I through them in the fridge and I've been breaking off hunks ever since. They taste good to me, but the chocolate is all grainy after melting and then solidifying again. I won't order them online again, but if I see them in a store I would pick them up.","Summary: Good | Review: These looked like a perfect snack to through in with my trail mix. Unfortunately, they arrived in a solid mass of melted chocolate. I left them in my pantry for a few days, and when I opened them at room temperature they were still gooey. I through them in the fridge and I've been breaking off hunks ever since. They taste good to me, but the chocolate is all grainy after melting and then solidifying again. I won't order them online again, but if I see them in a store I would pick them up."
79 | 77,78,B004X2KR36,A26M5O53PHZTKN,"Debs ""peanut""",0,0,5,1348185600,Taste great,These taste really good. I have been purchasing a different brand and these are very similar in taste and texture. I agree with the other reviewer regarding ordering in the summer. There is no insulating packaging with ice packs so they will melt in warm weather like all chocolate food items. Order in cold weather and buy enough to last!!!,Summary: Taste great | Review: These taste really good. I have been purchasing a different brand and these are very similar in taste and texture. I agree with the other reviewer regarding ordering in the summer. There is no insulating packaging with ice packs so they will melt in warm weather like all chocolate food items. Order in cold weather and buy enough to last!!!
80 | 78,79,B004X2KR36,A2AB7M9UCNBVN7,sharonh4,0,0,3,1346976000,Order only in cold weather,"The taste was great, but the berries had melted. May order again in winter. If you order in cold weather you should enjoy flavor.","Summary: Order only in cold weather | Review: The taste was great, but the berries had melted. May order again in winter. If you order in cold weather you should enjoy flavor."
81 | 79,80,B005R8JE8O,A3H1EQD2PBC085,jmc,0,0,5,1344902400,this is the best,"i know i cannot make tea this good. granted, i am not from the south but i know i have never enjoyed tea that was this sweet without being too sweet. it tastes crisp.","Summary: this is the best | Review: i know i cannot make tea this good. granted, i am not from the south but i know i have never enjoyed tea that was this sweet without being too sweet. it tastes crisp."
82 | 80,81,B0066DMI6Y,AB30HQTI5VOLR,Melinda Bishop,1,1,5,1325116800,Delicious!,This peppermint stick is delicious and fun to eat. My dad got me one for Christmas because he remembered me having a similar one when I was a little girl. I'm 30 now and I love it!,Summary: Delicious! | Review: This peppermint stick is delicious and fun to eat. My dad got me one for Christmas because he remembered me having a similar one when I was a little girl. I'm 30 now and I love it!
83 | 81,82,B0066DMI6Y,AZLONLC8OZPEC,John W. Hollis,1,1,4,1324598400,Great,"Great gift for all ages! I purchased these giant canes before and the recipients loved them so much, they kept them and would not eat them.","Summary: Great | Review: Great gift for all ages! I purchased these giant canes before and the recipients loved them so much, they kept them and would not eat them."
84 | 82,83,B003ZFRKGO,A2VOZX7YBT0D6D,"Johnnycakes ""Johnnycakes""",15,15,5,1325635200,Forget Molecular Gastronomy - this stuff rockes a coffee creamer!,"I know the product title says Molecular Gastronomy, but don't let that scare you off. I have been looking for this for a while now, not for food science, but for something more down to earth. I use it to make my own coffee creamer.
I have to have my coffee blonde and sweet - but the flavored creamers are full of the bad kinds of fat, and honestly, I hate to use manufactured ""food"" items. I really don't think they are good for the body. On the other hand, I hate using cold milk or cream, because I like HOT coffee.
I stumbled across this on Amazon one day and got the idea of making my own creamer. I also bought low-fat (non-instant) milk powder and regular milk powder. The non-instant lowfat milk is a little sweeter and tastes fresher than regular instant low-fat milk, but does not dissolve good in cold water - which is not a problem for hot coffee. You will have to play with the ratios - I would not do just the heavy cream, it made the coffee too rich. Also, I think the powder is too expensive to just use on it's own. I like mixing 1/3 of each together.
For flavoring, I bough cocoa bean powder, vanilla bean powder, and caster (superfine) sugar. I mix up small batches along with spices like cinnamon and nutmeg to make my own flavored creamers. If you wanted, you could use a fake sweetner powder instead. I make up small amounts that I store in jelly canning jars. I also use my little food chopper/food processor to blend everything, so the sugar is not heavier and sinks to the bottom. Let it settle for a bit before opening the top though.
This stuff tastes WAY better than the storebought creamers and it is fun to experiment and come up with your own flavors. I am going to try using some essential oils next and see if I can get a good chocolate/orange mix.
All of the ingredients I mentioned are here online. Take the time to experiment. Maybe you don't use any low-fat milk. Or don't add any flavorings. It is up to you. Also, would make great housewarming/host(ess) gifts.
I am sure other molecular people will be able to tell you more of what you can do with it, and I am sure I will experiment with it in cooking - but the main reason I bought it was to make my own creamer and it worked out great.","Summary: Forget Molecular Gastronomy - this stuff rockes a coffee creamer! | Review: I know the product title says Molecular Gastronomy, but don't let that scare you off. I have been looking for this for a while now, not for food science, but for something more down to earth. I use it to make my own coffee creamer.
I have to have my coffee blonde and sweet - but the flavored creamers are full of the bad kinds of fat, and honestly, I hate to use manufactured ""food"" items. I really don't think they are good for the body. On the other hand, I hate using cold milk or cream, because I like HOT coffee.
I stumbled across this on Amazon one day and got the idea of making my own creamer. I also bought low-fat (non-instant) milk powder and regular milk powder. The non-instant lowfat milk is a little sweeter and tastes fresher than regular instant low-fat milk, but does not dissolve good in cold water - which is not a problem for hot coffee. You will have to play with the ratios - I would not do just the heavy cream, it made the coffee too rich. Also, I think the powder is too expensive to just use on it's own. I like mixing 1/3 of each together.
For flavoring, I bough cocoa bean powder, vanilla bean powder, and caster (superfine) sugar. I mix up small batches along with spices like cinnamon and nutmeg to make my own flavored creamers. If you wanted, you could use a fake sweetner powder instead. I make up small amounts that I store in jelly canning jars. I also use my little food chopper/food processor to blend everything, so the sugar is not heavier and sinks to the bottom. Let it settle for a bit before opening the top though.
This stuff tastes WAY better than the storebought creamers and it is fun to experiment and come up with your own flavors. I am going to try using some essential oils next and see if I can get a good chocolate/orange mix.
All of the ingredients I mentioned are here online. Take the time to experiment. Maybe you don't use any low-fat milk. Or don't add any flavorings. It is up to you. Also, would make great housewarming/host(ess) gifts.
I am sure other molecular people will be able to tell you more of what you can do with it, and I am sure I will experiment with it in cooking - but the main reason I bought it was to make my own creamer and it worked out great."
85 | 83,84,B0019CW0HE,A1FD9E5C06UB6B,BRENDA DEMERS,5,5,3,1301011200,Natural Balance Lamb and Rice,"While my dogs like all of the flavors that we have tried of this dog food, for some reason their itching increased when I tried the lamb and rice. I have some very itchy dogs and am giving them a limited ingredient dog food to try to help. The duck and sweet potato cut down on the itching significantly, but when we tried lamb and rice they started itching more once again. I like Natural Balance for the quality ingredients.","Summary: Natural Balance Lamb and Rice | Review: While my dogs like all of the flavors that we have tried of this dog food, for some reason their itching increased when I tried the lamb and rice. I have some very itchy dogs and am giving them a limited ingredient dog food to try to help. The duck and sweet potato cut down on the itching significantly, but when we tried lamb and rice they started itching more once again. I like Natural Balance for the quality ingredients."
86 | 84,85,B0019CW0HE,AK2CXHH9VRZ2A,I. GLENN,4,4,3,1313193600,INCREASED MY DOGS ITCHING,"Awesome dog food. However, when given to my ""Boston"", who has severe reactions to some food ingredients; his itching increased to violent jumping out of bed at night, scratching. As soon as I changed to a different formula, the scratching stopped. So glad Natural Balance has other choices. I guess you have to try each, until you find what's best for your pet.","Summary: INCREASED MY DOGS ITCHING | Review: Awesome dog food. However, when given to my ""Boston"", who has severe reactions to some food ingredients; his itching increased to violent jumping out of bed at night, scratching. As soon as I changed to a different formula, the scratching stopped. So glad Natural Balance has other choices. I guess you have to try each, until you find what's best for your pet."
87 | 85,86,B0019CW0HE,A25BGFRHYHEZKK,Toby's mom,4,4,5,1292889600,Great food!,"We have three dogs and all of them love this food! We bought it specifically for one of our dogs who has food allergies and it works great for him, no more hot spots or tummy problems.
I LOVE that it ships right to our door with free shipping.","Summary: Great food! | Review: We have three dogs and all of them love this food! We bought it specifically for one of our dogs who has food allergies and it works great for him, no more hot spots or tummy problems.
I LOVE that it ships right to our door with free shipping."
88 | 86,87,B0019CW0HE,A37N9XZBB8JYOF,Ash52,1,1,5,1333670400,Great for my dogs allergies,"My dog has a ton of allergies both environmental and food. She was on a prescription dog food before we had her tested to see what allergies she has. After we got the test back, we learned she was allergic to something in the prescription brand. So I finally found this dog food and she has done so well on this! She still has her environmental triggers, but I am happy she can finally eat something I know won't cause her pain.","Summary: Great for my dogs allergies | Review: My dog has a ton of allergies both environmental and food. She was on a prescription dog food before we had her tested to see what allergies she has. After we got the test back, we learned she was allergic to something in the prescription brand. So I finally found this dog food and she has done so well on this! She still has her environmental triggers, but I am happy she can finally eat something I know won't cause her pain."
89 | 87,88,B0019CW0HE,A1T4L0Q47OZ9N,Wendy,1,1,5,1320883200,Great for stomach problems!,My shepherd/collie mix has IBS. Our vet recommended a limited ingredient food. This has really helped her symptoms and she likes it. I will always buy it from Amazon...it's $10 cheaper and free shipping!,Summary: Great for stomach problems! | Review: My shepherd/collie mix has IBS. Our vet recommended a limited ingredient food. This has really helped her symptoms and she likes it. I will always buy it from Amazon...it's $10 cheaper and free shipping!
90 | 88,89,B0019CW0HE,A3IMXZE9FCUNOC,Dana,1,1,5,1311638400,Better life for you dog!,Natural Balance Dry Dog Food Lamb Meal and Brown Rice Recipe did wonders for my Jack Russell. She has awful food allergy's and this food was our last hope because it was the last food we could find that didn't have SOMETHING in it that she was allergic to. She has no problem eating it dry but normally I mix the Natural Balance Dry Lamb and Brown Rice with the Natural Balance Wet Lamb and Brown Rice.. she seems to like that better. We started feeding it to our other dog (a Bichon) too and she loves it. If your dog has allergy's or stomach issue.. or if you want your dog to eat better food-- this is it! You will see a difference in your pet.,Summary: Better life for you dog! | Review: Natural Balance Dry Dog Food Lamb Meal and Brown Rice Recipe did wonders for my Jack Russell. She has awful food allergy's and this food was our last hope because it was the last food we could find that didn't have SOMETHING in it that she was allergic to. She has no problem eating it dry but normally I mix the Natural Balance Dry Lamb and Brown Rice with the Natural Balance Wet Lamb and Brown Rice.. she seems to like that better. We started feeding it to our other dog (a Bichon) too and she loves it. If your dog has allergy's or stomach issue.. or if you want your dog to eat better food-- this is it! You will see a difference in your pet.
91 | 89,90,B0019CW0HE,A1EC57S6C2VLTL,"Lorraine ""Agelechio""",0,0,5,1347408000,Great Food,"Great food! I love the idea of one food for all ages & breeds. Ît's a real convenience as well as a really good product. My 3 dogs eat less, have almost no gas, their poop is regular and a perfect consistency, what else can a mom ask for!!","Summary: Great Food | Review: Great food! I love the idea of one food for all ages & breeds. Ît's a real convenience as well as a really good product. My 3 dogs eat less, have almost no gas, their poop is regular and a perfect consistency, what else can a mom ask for!!"
92 | 90,91,B0019CW0HE,A1OGD72Y2Y26CF,Lisas201,0,0,5,1335398400,Great food for my my dog who has a sensitive stomach.,I have a standard poodle and pomeranian who both do wonderful on this food. I have switched them to a different food (due to price) a couple of times and end up going right back to natural balance.,Summary: Great food for my my dog who has a sensitive stomach. | Review: I have a standard poodle and pomeranian who both do wonderful on this food. I have switched them to a different food (due to price) a couple of times and end up going right back to natural balance.
93 | 91,92,B0019CW0HE,A7JWCYVPF7KCO,gare,0,0,5,1334966400,Great dog food,"This is great dog food, my dog has severs allergies and this brand is the only one that we can feed him.","Summary: Great dog food | Review: This is great dog food, my dog has severs allergies and this brand is the only one that we can feed him."
94 | 92,93,B0019CW0HE,ABG53EBZBKD23,"J. Romagnoli ""*jroma""",0,0,5,1333929600,Mmmmm Mmmmm good.,This food is great - all ages dogs. I have a 3 year old and a puppy. They are both so soft and hardly ever get sick. The food is good especially when you have Amazon Prime shipping :),Summary: Mmmmm Mmmmm good. | Review: This food is great - all ages dogs. I have a 3 year old and a puppy. They are both so soft and hardly ever get sick. The food is good especially when you have Amazon Prime shipping :)
95 | 93,94,B0019CW0HE,A3AF72GP4GVRY1,John D. Meara,0,0,5,1330041600,Great Dog Food!,"My golden retriever is one of the most picky dogs I've ever met. After experimenting with various types of food, I have found she loves natural balance. What I really like about natural balance is the fact that it has multiple flavors in dry and wet varieties. I mix her dry food with a little wet food and my golden loves it. Furthermore, I do like mixing up the flavors each time as I think the same meal day over day might get a little boring, so I figured why not. I tend to stay away from the fish type though as it smells...
Additionally, I started purchasing off Amazon because Petco didn't have the wet food box and only had a couple of cans. I came home and to my surprise realized that I could save $20 each time I bought dog food if I just buy it off Amazon.
All in all, I definitely recommend and give my stamp of approval to natural balance dog food. While I have never eaten it, my dog seems to love it.","Summary: Great Dog Food! | Review: My golden retriever is one of the most picky dogs I've ever met. After experimenting with various types of food, I have found she loves natural balance. What I really like about natural balance is the fact that it has multiple flavors in dry and wet varieties. I mix her dry food with a little wet food and my golden loves it. Furthermore, I do like mixing up the flavors each time as I think the same meal day over day might get a little boring, so I figured why not. I tend to stay away from the fish type though as it smells...
Additionally, I started purchasing off Amazon because Petco didn't have the wet food box and only had a couple of cans. I came home and to my surprise realized that I could save $20 each time I bought dog food if I just buy it off Amazon.
All in all, I definitely recommend and give my stamp of approval to natural balance dog food. While I have never eaten it, my dog seems to love it."
96 | 94,95,B0019CW0HE,A1DJAAKLPCJRZD,wendy,0,0,5,1329609600,So convenient,This is the same food we get at pet store. But it's delivered to my door! And for the same price or slightly less.,Summary: So convenient | Review: This is the same food we get at pet store. But it's delivered to my door! And for the same price or slightly less.
97 | 95,96,B0019CW0HE,A1BFNM27629VAV,E. Triebe,0,0,5,1320105600,Good healthy dog food,I've been very pleased with the Natural Balance dog food. Our dogs have had issues with other dog foods in the past and I had someone recommend Natural Balance grain free since it is possible they were allergic to grains. Since switching I haven't had any issues. It is also helpful that have have different kibble size for larger/smaller sized dogs.,Summary: Good healthy dog food | Review: I've been very pleased with the Natural Balance dog food. Our dogs have had issues with other dog foods in the past and I had someone recommend Natural Balance grain free since it is possible they were allergic to grains. Since switching I haven't had any issues. It is also helpful that have have different kibble size for larger/smaller sized dogs.
98 | 96,97,B0019CW0HE,A18AAABCIJKC5Q,Rhiever,0,0,5,1303776000,Great dog food,"My 1-1/2 year old basenji/jack russell mix loves this dog food. He's been noticeably healthier and more energetic since I switched him over from the standard dog foods earlier this year. Despite the higher cost of natural dog foods, I find that he eats significantly less of the Natural Balance dog foods and still stays happy and full. On the normal dog foods, he'd eat up to 3 cups of dog food a day (the recommended serving for his size), whereas he only eats about 1 cup to 1-1/2 cup of the Natural Balance dog food a day. When you take this into account, you're actually getting more ""bang for your buck"" with the natural dog foods since you don't have to buy as much to last just as long as the normal dog foods... and a healthier, happier dog, to boot! Add in the fact that you can get free, 2-day shipping with Amazon Prime... I'm sold!!","Summary: Great dog food | Review: My 1-1/2 year old basenji/jack russell mix loves this dog food. He's been noticeably healthier and more energetic since I switched him over from the standard dog foods earlier this year. Despite the higher cost of natural dog foods, I find that he eats significantly less of the Natural Balance dog foods and still stays happy and full. On the normal dog foods, he'd eat up to 3 cups of dog food a day (the recommended serving for his size), whereas he only eats about 1 cup to 1-1/2 cup of the Natural Balance dog food a day. When you take this into account, you're actually getting more ""bang for your buck"" with the natural dog foods since you don't have to buy as much to last just as long as the normal dog foods... and a healthier, happier dog, to boot! Add in the fact that you can get free, 2-day shipping with Amazon Prime... I'm sold!!"
99 | 97,98,B0019CW0HE,A3UII2114114PI,"FuNky Faja ""SiLkk""",0,0,5,1297296000,"Great allergy sensitive dog food, dogs love it",Our pup has experienced allergies in forms of hotspots and itching from other dog foods. The cheap 'you can buy it anywhere' food not only have crazy preservatives in them but can cause health problems for your pets. This food works wonders on reducing allergies and our dog loves the food.
This message is RAMSEY FrAnkenSteiN approved.,"Summary: Great allergy sensitive dog food, dogs love it | Review: Our pup has experienced allergies in forms of hotspots and itching from other dog foods. The cheap 'you can buy it anywhere' food not only have crazy preservatives in them but can cause health problems for your pets. This food works wonders on reducing allergies and our dog loves the food.
This message is RAMSEY FrAnkenSteiN approved."
100 | 98,99,B0019CW0HE,ABZ9F0D94YK45,Amazon-tron 3000,0,0,5,1295308800,Perfect for our English Bulldog with Allergies,"My English Bulldog had skin allergies the summer we got him at age 3. The vet recommended we wean him off the food his previous owner gave him (Iams Lamb and Rice) and onto a new kind. This was the second one we tried, and it has been working ever since. It's for dogs that need a limited diet who can be sensitive to additives and proteins commonly found in commercial dog food (like chicken or beef).","Summary: Perfect for our English Bulldog with Allergies | Review: My English Bulldog had skin allergies the summer we got him at age 3. The vet recommended we wean him off the food his previous owner gave him (Iams Lamb and Rice) and onto a new kind. This was the second one we tried, and it has been working ever since. It's for dogs that need a limited diet who can be sensitive to additives and proteins commonly found in commercial dog food (like chicken or beef)."
101 |
--------------------------------------------------------------------------------
/session-delivery-resources/3-azure-sql-ai-search/src/example.env:
--------------------------------------------------------------------------------
1 | # Azure SQL database connection details
2 | server = ''
3 | database = ''
4 | username = ''
5 | password = ''
6 |
7 | # azure open ai
8 | openai_api_base=""
9 | openai_api_type="azure"
10 | openai_api_key=""
11 | openai_deployment_embedding="embeddings"
12 | openai_model_embedding="text-embedding-ada-002"
13 | openai_deployment_completion="completions"
14 | openai_model_completion="gpt-35-turbo"
15 | openai_api_version="2024-02-01"
16 |
17 | # azure cognitive services
18 | cogsearch_name=""
19 | cogsearch_index_name="sql-customer-index"
20 | cogsearch_api_key=""
21 | cogsearch_endpoint=""
22 |
--------------------------------------------------------------------------------
/session-delivery-resources/3-azure-sql-ai-search/src/requirements.txt:
--------------------------------------------------------------------------------
1 | pyodbc==5.1.0
2 | python-dotenv==1.0.1
3 | pandas==2.2.2
4 | openai==1.34.0
5 | jupyter==1.0.0
6 | requests==2.32.3
7 | azure-core==1.30.2
8 | azure-search-documents==11.6.0b4
--------------------------------------------------------------------------------
/session-delivery-resources/README.md:
--------------------------------------------------------------------------------
1 | # Session delivery resources
2 |
3 | The following resources are intended for a presenter to learn and deliver the session.
4 |
5 | ## How To Use
6 |
7 | Welcome,
8 |
9 | We're glad you are here and look forward to your delivery of this amazing content! As an experienced presenter, we know you know HOW to present so this guide will focus on WHAT you need to present. It will provide you a full run-through of the presentation created by the presentation design team.
10 |
11 | Along with the video of the presentation, this document will link to all the assets you need to successfully present including PowerPoint slides and demo instructions &
12 | code.
13 |
14 | 1. Read document in its entirety
15 | 2. Familiarize with the Session Delivery Resources PowerPoint
16 | 3. Watch the Session Delivery Resources PPT Recording
17 | 4. Familiarize with the Session Power Point
18 | 5. Watch the Session PPT Recording
19 | 6. Watch the Session PPT Recording with Commentary
20 | 7. Ask questions to the lead presenters
21 |
22 | | Resources | Links | Description |
23 | |-------------------|----------------------------------|-------------------|
24 | | PowerPoint | - [Presentation](https://aka.ms/AAs6qfn) | Slides, [Additional Languages](https://github.com/microsoft/aitour-ai-apps-with-scalable-database/tree/main/session-delivery-resources#slides-in-additional-languages) |
25 | | PPT Recording | - [Presentation](https://aka.ms/AAs5507) | Video Recording of the PowerPoint slides |
26 | | Demos | - [Links to demos](#demos) | Additional Demo Content |
27 | | Demo Recording for Cosmos DB | - [RAG with Azure Cosmos DB](https://aka.ms/AAs4l8v) | Recording of Demo 1 |
28 | | Demo Recording for PostgreSQL | - [RAG with Azure Database for PostgreSQL](https://aka.ms/AAs4plk) | Recording of Demo 2 |
29 | | Demo Recording for Azure SQL | - [Integrated RAG with Azure SQL Database](https://aka.ms/AAs50ne) | Recording of Demo 3 |
30 |
31 |
32 |
33 | ## Get Started
34 |
35 | This collection of Session Delivery Resources is divided in to the following sections:
36 |
37 | | [Slides](#slides) | [Timing](#timing) | [Demos](#demos) |
38 | |-------------------|---------------------------|--------------------------------------
39 | | ~61 slides - 45 minutes delivery time | Timing breakdown for all presentation topics | Demo notes
40 |
41 |
42 | ## Slides
43 |
44 | The presentation slides for this session have presenter notes in each part of the session. We recommend to refer to these during your preparation and you can also refer to the notes using a second monitor during your live delivery of the presentation at AI Tour.
45 |
46 | ### Timing
47 |
48 | | Time | Description
49 | --------------|-------------
50 | 0:00 - 1:00 | Introduction: Data is the fuel that powers AI
51 | 2:00 - 3:00 | Introduction to the Microsoft Intelligent Data Platform
52 | 3:00 - 5:00 | Intelligent
53 | 5:00 - 15:00 | Azure Cosmos DB (5) & Demo (5)
54 | 15:00 - 25:00 | Azure Database for PostgreSQL (5) & Demo (5)
55 | 25:00 - 30:00 | Integrated & Integrations in Microsoft Fabric (5)
56 | 30:00 - 40:00 | Azure SQL Database (5) & Demo (5)
57 | 40:00 - 42:00 | Trusted
58 | 42:00 - 45:00 | Closing
59 |
60 | ### Slides in additional languages
61 | | Language | Last updated |
62 | |------------------- | ---- |
63 | | [Spanish](https://aka.ms/AAs8rcg) | 2024.09.16 |
64 | | [Portuguese](https://aka.ms/AAs96i5) | 2024.09.16|
65 |
66 | ## Demos
67 |
68 | >**What's Here?** Deploying the demo environment on Azure - including the prerequisites.
69 |
70 | Instructions and prerequisites are outlined in each demo:
71 | - [Azure Cosmos DB](1-cosmos-db-nosql)
72 | - [Azure Database for PostgreSQL](2-postgres-rag)
73 | - [Azure SQL Database](3-azure-sql-ai-search)
74 |
75 | All demos are also provided as recordings inside the presentation deck.
76 |
77 | ## Change Log
78 | Here is a log of the changes made to this file:
79 |
80 | | Date | Changes |
81 | |------------|---------|
82 | | 2024.09.16 | Added Change log, Additional language section with Spanish and Portuguese PowerPoint slides |
--------------------------------------------------------------------------------