Blog Post

Educator Developer Blog
16 MIN READ

Transforming Static Learning into Interactive AI Experiences with Azure Prompt Flow & Flask

PascalBurume08's avatar
PascalBurume08
Copper Contributor
Feb 24, 2025

 

 

Large Language Models (LLMs) like GPT-4 have revolutionized AI, but their static knowledge cutoff limits their utility in dynamic fields like education. Retrieval-augmented generation (RAG) bridges this gap by grounding AI responses in real-time data. 

Why RAG?

RAG combines the power of LLMs with domain-specific data retrieval, enabling:

  1. Dynamic Knowledge Updates: Pulling from sources like PDF textbooks or research papers.
  2. Context-Aware Responses: Using hybrid search (vector + keyword) to fetch relevant content
  3. Reduced Hallucinations: Cross-referencing facts against indexed data.

For educators, this means students get responses derived from trusted sources rather than generic online content. In the realm of GRE prep, this marks the first copilot preview powered by RAG.

  I.  Architecture Overview

 

The architecture includes:

  1. User Interaction (Frontend)
    • Component: The user browser represents the chat interface where users interact with the system.
    • Functionality: Users type their queries into the chat interface.
    • Communication: These interactions are sent via HTTPS to the backend server.
  1. Flask Web Server (Backend)
    • Component: The Flask Web Server acts as the intermediary between the frontend and Azure AI services.
    • Functionality:
      • Receives user inputs via HTTP requests.
      • Processes these requests and forwards them to Azure AI.
      • Returns AI-generated responses back to the frontend for display.
    • Endpoints: The diagram highlights Chat Endpoints, which handle API calls from the frontend.
  1. Azure Prompt Flow (Processing Layer)
    • Component: Azure Prompt Flow  handles AI-powered text processing and retrieval-augmented generation (RAG).
    • Functionality:
      • Processes user input using Azure OpenAI models (GPT-4o) to generate AI-driven responses.
      • Uses a Text Embedding Model to convert user text into vector representations.
      • Performs Azure AI Search to retrieve relevant domain-specific data.
  1. Internal API Calls & AI Model Integration
    • Component: The Flask backend makes internal API calls to Azure AI services.
    • Functionality:
      • Queries are enriched using Azure AI Search to fetch relevant documents.
      • The GPT-4o model generates responses based on retrieved data and chat history.
      • The system returns structured responses to the Flask backend, which relays them to the user.

  II. Step-by-Step Implementation

  1. Create an Azure AI Search resource

The custom data will be integrated into the prompt flow of your generative AI application. In order to ensure successful integration, it is essential to employ an Azure AI Search resource for the purposes of data indexing.

    1. In a web browser, open the Azure portal at https://portal.azure.com and sign in using your Azure credentials.
    2. On the home page, select + Create a resource and search for Azure AI Search. Then create a new Azure AI Search resource with the following settings:
      • Subscription: Select your Azure subscription
      • Resource group: Select or create a resource group
      • Service name: Enter a unique service name
      • Location: Make a random choice from any of the following regions*
      • Pricing tier: Standard

Later, you'll create an Azure AI Hub (including Azure OpenAI) in the same region as your Azure AI Search resource.

                3. Wait for your Azure AI Search resource deployment to be completed.

  1. Create an Azure AI project

Now you’re ready to create an Azure AI Studio project and the Azure AI resources to support it.

                4. In a web browser, open Azure AI Studio portal at https://ai.azure.com and sign in                      using your Azure credentials.

                5. In the home page, select + Create project.

               6. In the Create a project wizard you can see all the Azure resources that will be automatically created with your project. Select Customize and connect to your                             Azure AI Search resource:

      • Hub name: A unique name
      • Azure Subscription: Your Azure subscription
      • Resource group: Select the resource group containing your Azure AI Search resource
      • Location: The same location as your Azure AI Search resource
      • Connect Azure AI Services or Azure OpenAI: (New) Autofills with your selected hub name
      • Connect Azure AI Search: Select your Azure AI Search resource
  •  
  •     7. Select Next and review your configuration.
  •     8. Select Create and wait for the process to complete.
  •  
  • Deploy models

    You need two models to implement your solution:

      • An embedding model to vectorize text data for efficient indexing and processing.
      • A model that can generate natural language responses to questions based on your data.

    • 9. In the Azure AI Studio portal, in your project, in the navigation pane on the left, under My assets, select the Models + endpoints page.
    •  
    • 10. Create a new deployment of the text-embedding-ada-002 model with the following settings by selecting Customize in the Deploy model wizard:
          • Deployment name: text-embedding-ada-002
          • Deployment type: Standard
          • Model version: Select the default version
          • AI resource: Select the resource created previously
          • Tokens per Minute Rate Limit (thousands): 5K
          • Content filter: DefaultV2
          • Enable dynamic quota: Disabled

If your current AI resource location doesn’t have quota available for the model you want to deploy, you will be asked to choose a different location where a new AI resource will be created and connected to your project.

            11. Repeat the previous steps to deploy a gpt-4o model with the deployment name
                 gpt-4o.

Add data to your project

The data for your copilot consists of a set of travel brochures in PDF format from the fictitious travel agency Margie’s Travel. Let’s add them to the project.

          12. In Azure AI Studio portal, in your project, in the navigation pane on the left, under                    My assets, select the Data + indexes page.

          13. Select + New data.

          14. In the Add your data wizard, expand the drop-down menu to select Upload                               files/folders.

          15. Select Upload folder and select the file folder.

          16. Select Next and set the data name to brochures.

          17. Wait for the pdf file to be uploaded.

Create an index for your data

Now that you’ve added a data source to your project, you can use it to create an index in your Azure AI Search resource.

   18. In Azure AI Studio portal, in your project, in the navigation pane on the left, under               My assets, select the Data + indexes page.

    19. In the Indexes tab, add a new index with the following settings:

      • Source location:
        • Data source: Data in Azure AI Studio portal
          • Select the pdf data source
      • Index configuration:
        • Select Azure AI Search service: Select the AzureAISearch connection to your Azure AI Search resource
        • Vector index: greverb-index
        • Virtual machine: Auto select
      • Search settings:
        • Vector settings: Add vector search to this search resource
        • Azure OpenAI connection: Select the default Azure OpenAI resource for your hub.
  •  
  •    20. Wait for the indexing process to be completed, which can take several minutes. The             index creation operation consists of the following jobs:
      • Crack, chunk, and embed the text tokens in your pdf data.
      • Create the Azure AI Search index.
      • Register the index asset.

Some users are finding newly created indexes unavailable right away. Refreshing the browser usually helps, but if you’re still experiencing the issue where it can’t find the index you may need to wait until the index is recognized.

   21. After the index has been added and the chat session has restarted, resubmit the                     prompt What can you recommend beginners?

   22. Review the response, which should be based on data in the index.

 

Use the index in a prompt flow

Your vector index has been saved in your Azure AI Studio project, enabling you to use it easily in a prompt flow.

  23. In Azure AI Studio portal, in your project, in the navigation pane on the left, under              Build and customize, select the Prompt flow page.

  24. Create a new prompt flow by cloning the Multi-Round Q&A on Your Data sample in          the gallery. Save your clone of this sample in a folder named brochure-flow.

  25. When the prompt flow designer page opens, review GRE-Verbal-reasoning. Its graph          should resemble the following image:

The sample prompt flow you are using implements the prompt logic for a chat application in which the user can iteratively submit text input to chat interface. The conversational history is retained and included in the context for each iteration. The prompt flow orchestrate a sequence of tools to:

      • Append the history to the chat input to define a prompt in the form of a contextualized form of a question.
      • Retrieve the context using your index and a query type of your own choice based on the question.
      • Generate prompt context by using the retrieved data from the index to augment the question.
      • Create prompt variants by adding a system message and structuring the chat history.
      • Submit the prompt to a language model to generate a natural language response.

  26. Use the Start compute session button to start the runtime compute for the flow.

Wait for the runtime to start. This provides a compute context for the prompt flow. While you’re waiting, in the Flow tab, review the sections for the tools in the flow.

  27 .In the Inputs section, ensure the inputs include:

      • chat_history
      • chat_input

  28. In the Outputs section, ensure that the output includes:

      • chat_output with value ${chat_with_context.output}

  29. In the modify_query_with_history section, select the following settings (leaving                    others as they are):

      • Connection: The default Azure OpenAI resource for your AI hub
      • Api: chat
      • deployment_name: gpt-4o
      • response_format: {“type”:”text”}

  30. Wait for the compute session to start, then in the lookup section, set the following               parameter values:

      • mlindex_content: Select the empty field to open the Generate pane
        • index_type: Registered Index
        • mlindex_asset_id: brochures-index:1
      • queries: ${modify_query_with_history.output}
      • query_type: Hybrid (vector + keyword)
      • top_k: 2

   31. In the generate_prompt_context section, review the Python script and ensure that               the inputs for this tool include the following parameter:

      • search_result (object): ${lookup.output}

   32. In the Prompt_variants section, review the Python script and ensure that the inputs             for this tool include the following parameters:

      • contexts (string): ${generate_prompt_context.output}
      • chat_history (string): ${inputs.chat_history}
      • chat_input (string): ${inputs.chat_input}

   33. In the chat_with_context section, select the following settings (leaving others as they           are):

      • Connection: Default_AzureOpenAI
      • Api: Chat
      • deployment_name: gpt-4o
      • response_format: {“type”:”text”}

           Then ensure that the inputs for this tool include the following parameters:

      • prompt_text (string): ${Prompt_variants.output}

  34. On the toolbar, use the Save button to save the changes you’ve made to the tools in              the prompt flow.

  35. On the toolbar, select Chat. A chat pane opens with the sample conversation history              and the input already filled in based on the sample values. You can ignore these.

36. In the chat pane, replace the default input with the question What can you                            recommend for beginners? and submit it.

  37. Review the response, which should be based on data in the index.

  38. Review the outputs for each tool in the flow.

  39. In the chat pane, enter the question Propose me something

  40. Review the response, which should be based on data in the index, and take into                      account  the chat history.

  41. Review the outputs for each tool in the flow, noting how each tool in the flow                        operated on its inputs to prepare a contextualized prompt and get an appropriate                response.

Deploy the flow

Now that you have a working flow that uses your indexed data, you can deploy it as a service to be consumed by a copilot application

  42. Save your configuration Once your testing is complete and the prompt flow meets                your requirements.

  43. Look for a “Deploy” button or option. This will typically package your prompt flow                and create an endpoint or API that your applications can call.

Obtain the Endpoint/Integration Details

After deployment, you should receive an endpoint URL and any required keys or connection strings.

  44. in the navigation pane on the left, under My assets, select the Models + endpoints              page.

  45. Select your deployment and review the details about it deployment.

Test Your Prompt Flow

  1. Use the built-in testing interface to run sample inputs through your flow.

Integrate with Your Application

  • API Calls: Use the provided endpoint and the key in your application code to send requests to your prompt flow.

III. Building the Custom Web Interface

Modern educational experiences benefit from interactivity and real-time feedback. In this section, we’ll build a custom web interface that brings together Azure’s powerful AI models with a flexible, user-friendly design. We’ll break the solution into two main parts:

  • Backend with Flask: This will manage API requests, connect to Azure AI services, and handle error cases.
  • Frontend with HTML, CSS, and JavaScript: This will create an interactive chat interface that captures user inputs, displays messages, and updates dynamically based on the AI responses.
  1. Backend with Flask

The Flask backend is the heart of the application. It receives user input from the web interface, forwards it to the Azure AI endpoint, and returns the generated response. This decoupling lets you modify or upgrade any part of the system independently.

    • Setting Up the Flask Application

Create a Python file (e.g., app.py) and configure it as follows:

from flask import Flask, render_template, request, jsonify, abort import requests import json import os import ssl import config app = Flask(__name__) # Allow self-signed HTTPS certificates (if needed during development) def allowSelfSignedHttps(allowed): if allowed and not os.environ.get('PYTHONHTTPSVERIFY', '') and getattr(ssl, '_create_unverified_context', None): ssl._create_default_https_context = ssl._create_unverified_context allowSelfSignedHttps(True) # --------------------------- # Chat Functionality Endpoints # --------------------------- @app.route("/") def index(): # Renders the chat interface (see the template section below) return render_template("index.html") @app.route("/get", methods=["GET"]) def get_bot_response(): """ This endpoint receives a user query from the frontend, forwards the query (along with any chat history) to the Azure AI endpoint, and returns the generated response. """ try: # Get the user message from the query string user_text = request.args.get('msg') # In a real application, you might track conversation history here. chat_history = [] # Prepare the payload for Azure payload = { "chat_history": chat_history, "chat_input": user_text } body = json.dumps(payload).encode('utf-8') # Prepare the headers with your Azure credentials headers = { 'Content-Type': 'application/json', 'Authorization': f'Bearer {config.AZURE_ENDPOINT_KEY}', 'azureml-model-deployment': config.MODEL_DEPLOYMENT_NAME } # Forward the request to the Azure AI endpoint response = requests.post(config.AZURE_ENDPOINT_URL, data=body, headers=headers) response_data = response.json() # Check if the response is correctly formatted if 'chat_output' in response_data: return jsonify({ "response": response_data['chat_output'], "type": "analysis", "components": { "score": 4.5, "feedback": ["Good thesis statement", "Improve conclusion"] } }) else: return jsonify({ "response": "Error: Invalid response format from API", "type": "error" }) except requests.exceptions.HTTPError as error: print(f"HTTP Error: {error.response.status_code}") return jsonify({ "response": "Sorry, I'm experiencing technical difficulties. Please try again later.", "type": "error" }) except Exception as e: print(f"General Error: {str(e)}") return jsonify({ "response": "An unexpected error occurred. Please try again.", "type": "error" }) if __name__ == "__main__": # Run the Flask app in debug mode during development app.run(debug=True)
    • Configuration File

Make sure to create a config.py file to hold your Azure endpoint settings:

# config.py AZURE_ENDPOINT_KEY = '' # Replace with your actual key AZURE_ENDPOINT_URL = '' # Replace with your EndPoint Url MODEL_DEPLOYMENT_NAME = '' # Replace with your Deployment Name

In a production environment, secure your keys and sensitive information using environment variables or a secrets manager

  1. Frontend with HTML, CSS, and JavaScript

The frontend is designed to create a seamless chat experience. It captures user inputs, shows conversation history, and dynamically updates the chat window when responses are received.

    • HTML Template

Create a template (e.g., templates/index.html) to define the structure of the chat interface. In this example, we include a navigation bar so users can easily switch between chat and blog sections:

<!DOCTYPE html> <html> <head> <title>Coach AI Prep Chat</title> <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='style.css') }}"> </head> <body> <!-- Navigation for switching between the chat and blog sections --> <nav> <a href="{{ url_for('index') }}">Chat</a> <a href="{{ url_for('blog') }}">Blog</a> </nav> <!-- Top bar with additional actions --> <div class="top-bar"> <button id="clear-button">Clear Chat</button> </div> <!-- Main container for the chat interface --> <div class="container"> <div class="header"> <div class="title-section"> <span class="emoji">📝</span> <h1 class="title">Master Your GRE Study Material</h1> </div> <h2 class="subtitle">AI-Powered Analysis for Analytical Writing Excellence</h2> </div> <!-- Suggestion buttons to pre-populate common queries --> <div class="suggestion-buttons"> <button class="suggestion-button">Insert your essay here for analysis and feedback to improve your analytical writing skills.</button> <button class="suggestion-button">How is the Analytical Writing section of the GRE scored?</button> <button class="suggestion-button">What are some practice questions for Text Completion?</button> </div> <!-- Chat area to display conversation history --> <div class="chat-area"> <div id="chatbox"> <!-- Initial bot message --> <div class="bot-message"> <div class="avatar">B</div> <div class="message-content"> Hello! I'm Coach AI Prep, your analytical writing assistant. Please write down your input message, and I'll help you analyze and improve it. You can share an essay, argument, or any piece of writing you'd like to work on. </div> </div> </div> </div> <!-- Input area for user messages --> <div id="input-area"> <input type="text" id="user-input" placeholder="Get ready for your GRE preparation..."> <button id="send-button">Send</button> </div> </div> <script src="{{ url_for('static', filename='script.js') }}"></script> </body> </html>
    • CSS Styling

Create a CSS file (e.g., static/style.css) to style the interface. This example covers basic layout and component styling:

/* Base styling */ body { font-family: 'Arial', sans-serif; background-color: #f2f6fa; margin: 0; padding: 0; display: flex; flex-direction: column; align-items: center; } /* Navigation styles */ nav { width: 100%; background: #663399; padding: 10px; text-align: center; } nav a { color: #fff; margin: 0 15px; text-decoration: none; font-weight: bold; } /* Container for chat and blog */ .container { width: 90%; max-width: 800px; background-color: #fff; border-radius: 20px; box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2); padding: 30px; margin-top: 20px; } /* Top bar styling */ .top-bar { position: absolute; top: 10px; right: 10px; } #clear-button { background-color: #f44336; color: #fff; border: none; padding: 8px 15px; border-radius: 20px; font-size: 13px; cursor: pointer; } /* Chat area styling */ .chat-area { margin-bottom: 20px; height: 55vh; border-radius: 20px; background-color: #f9f9f9; overflow-y: auto; padding: 15px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); } /* Message bubble styling */ .bot-message, .user-message { display: flex; margin: 15px 0; align-items: flex-start; } .message-content { max-width: 70%; min-width: 120px; padding: 12px 15px; border-radius: 20px; font-size: 14px; line-height: 1.5; box-shadow: 0 1px 3px rgba(0,0,0,0.1); white-space: pre-wrap; } .bot-message .message-content { background: #fff; margin-left: 10px; color: #333; } .user-message .message-content { background: #663399; color: #fff; margin-right: 10px; } /* Input area styling */ #input-area { display: flex; align-items: center; margin-top: 30px; } #user-input { flex-grow: 1; padding: 18px; border: none; border-radius: 30px; font-size: 15px; background-color: #f5f5f5; box-shadow: inset 0 2px 4px rgba(0,0,0,0.1); } #send-button { background-color: #663399; color: #fff; border: none; padding: 15px 25px; border-radius: 30px; cursor: pointer; font-size: 15px; }
    • JavaScript for Interactivity

Create a JavaScript file (e.g., static/script.js) to handle sending messages, updating the chat, and integrating with the backend API:

// Get references to key DOM elements const chatbox = document.getElementById("chatbox"); const userInput = document.getElementById("user-input"); const sendButton = document.getElementById("send-button"); const clearButton = document.getElementById("clear-button"); const suggestionButtons = document.querySelectorAll(".suggestion-button"); // Helper: Append a new message to the chatbox function appendMessage(sender, message) { const messageContainer = document.createElement("div"); messageContainer.className = sender + "-message"; const avatar = document.createElement("div"); avatar.className = "avatar"; avatar.textContent = sender === "user" ? "U" : "B"; const messageContent = document.createElement("div"); messageContent.className = "message-content"; messageContent.innerHTML = formatResponse(message); messageContainer.appendChild(avatar); messageContainer.appendChild(messageContent); chatbox.appendChild(messageContainer); maintainScrollPosition(); } // Helper: Scroll the chatbox to the bottom function maintainScrollPosition() { setTimeout(() => { chatbox.scrollTop = chatbox.scrollHeight; }, 50); } // Basic text formatting: converts newlines, markdown-like syntax, etc. function formatResponse(text) { let formatted = text.replace(/\n/g, "<br>") .replace(/\*(.*?)\*/g, "<strong>$1</strong>") .replace(/_(.*?)_/g, "<em>$1</em>"); return formatted; } // Display a temporary typing indicator function showTyping() { const typing = document.createElement("div"); typing.className = "bot-message"; const avatar = document.createElement("div"); avatar.className = "avatar"; avatar.textContent = "B"; const typingContent = document.createElement("div"); typingContent.className = "message-content"; typingContent.textContent = "…"; typing.appendChild(avatar); typing.appendChild(typingContent); chatbox.appendChild(typing); maintainScrollPosition(); return typing; } // Send the user message to the backend and display the bot's response function getBotResponse(userText) { // Display a typing indicator while waiting for a response const typingIndicator = showTyping(); fetch(`/get?msg=${encodeURIComponent(userText)}`) .then(response => { if (!response.ok) throw new Error('Network error'); return response.json(); }) .then(data => { typingIndicator.remove(); appendMessage("bot", data.response); }) .catch(error => { console.error("Error:", error); typingIndicator.remove(); appendMessage("bot", "Sorry, I'm having trouble connecting. Please try again."); }); } // Event handler for sending a message function sendMessage() { const text = userInput.value.trim(); if (text !== "") { appendMessage("user", text); userInput.value = ""; getBotResponse(text); } } // Clear the chatbox and reinitialize with the default bot greeting function clearChat() { chatbox.innerHTML = ""; // Optionally, re-add the initial bot message: appendMessage("bot", "Hello! I'm Coach AI Prep, your analytical writing assistant. Please write down your input message, and I'll help you analyze and improve it."); } // Event listeners for button clicks and key presses sendButton.addEventListener("click", sendMessage); userInput.addEventListener("keyup", (event) => { if (event.key === "Enter") sendMessage(); }); clearButton.addEventListener("click", clearChat); // Attach event listeners to suggestion buttons to auto-fill the input suggestionButtons.forEach(button => { button.addEventListener("click", () => { userInput.value = button.textContent; sendMessage(); }); });

3. Running and Extending Your Application

    1. Install Flask and Requests: pip install flask requests
    2. Run Your Flask App: python app.py
    3. Open your browser and navigate to http://localhost:5000 to test the chat interface.     Alternatively, you can test the online platform here: GRE Verbal Reasoning Practice.

IV. Conclusion

By building this custom web interface, you’ve decoupled the AI logic from the user experience. The Flask backend handles all communication with Azure’s AI services, while the dynamic frontend provides real-time, interactive feedback. This flexible and scalable solution not only enhances the learning experience but also sets the stage for future.

V. Ressources

 

Updated Feb 19, 2025
Version 1.0
No CommentsBe the first to comment