Creating an Automated Summarizer Bot with Azure and GitHub
Written on
Chapter 1: Introduction
A friend of mine recently requested that I set up a Telegram channel to share my articles (which I did! You can find it here). While the idea was appealing, the thought of writing a brief summary for each article felt tedious. Given my forgetfulness, I was bound to miss posting on the channel altogether.
The solution? I decided to automate the entire process using GitHub Actions, Azure Functions, and Azure OpenAI, all while having some fun and learning along the way. Let's delve into the design phase!
Architecture Overview
The architecture for this solution is straightforward. Here are the key components involved:
- A GitHub Action that triggers whenever I publish a new article on my personal blog.
- An LLM model, specifically GPT-4, hosted via Azure OpenAI, to summarize the content.
- An Azure Function that acts as a bridge, connecting the LLM to the Telegram API and GitHub Actions.
Here's a visual representation of the REST calls involved:
- The GitHub Action activates the Azure Function (1).
- The function retrieves the raw markdown of the article from my GitHub repository (2).
- The text is sent to the LLM for summarization (3).
- Finally, the summary is posted to the Telegram API (4).
I will start by refining the existing YAML workflow that builds my blog before coding the integration function.
Section 1.1: GitHub Action Configuration
I prefer to keep things simple, so I designed the function app to trigger only when I commit with a message starting with "article:"—a style reminiscent of Conventional Commits. I also specify the folder containing the article to pass it to the Azure Function later.
💡 Note: I adopted a bottom-up approach, beginning with the GitHub Action because I already had a plan in mind. The integration requires minimal data (just the article folder name), making it easier to conceptualize.
I quickly consulted GPT-4 to generate a GitHub Action, which I then modified to create the following job:
Copy trigger-summarizer:
runs-on: ubuntu-latest
if: startsWith(github.event.head_commit.message, 'article:')
needs: deploy
steps:
name: Call Summarizer
env:
FUNCTION_URL: ${{ secrets.LOGIC_APP_URL }}
run: |
COMMIT_MESSAGE="${{ github.event.head_commit.message }}"
ARTICLE_NAME=$(echo $COMMIT_MESSAGE | awk '{print $2}')
curl -X POST $FUNCTION_URL
-H "Content-Type: application/json"
—data "{"articleName": "$ARTICLE_NAME"}"
This snippet checks if the commit message begins with "article:", extracts the second word (the article name), and sends a POST request to the Azure Function.
I integrated this job into my existing workflow for building my Hugo-based blog. You can check the code for the integration with the preexisting workflow logic.
Section 1.2: Developing the Azure Function
Now, let's move on to the Azure Function. I won't delve into the Azure OpenAI setup here, as I have a separate article on that topic.
💡 Ensure that your GPT-4 deployment is properly configured to avoid throttling issues!
For our Azure Functions, we will use the V2 Python programming model, which is more efficient than V1, allowing inline trigger and binding definitions via Python decorators.
To get started, follow these commands:
mkdir summarizer_bot_function
cd ./summarizer_bot_function/
func init --model V2 --python
func new --name SummarizerFunction --template "HTTP trigger" --authlevel "function"
At this stage, you should have a new folder created. We also need to install a couple of libraries (requests and openai) and update the requirements.txt file:
pip install requests openai
pip freeze > requirements.txt
To avoid potential library conflicts in future projects, consider using a Python virtual environment.
Next, we can launch Visual Studio Code with code . (if you're in the same terminal directory) and begin developing our function. Replace the content in function_app.py with the following code:
import azure.functions as func
import logging
import os
from openai import AzureOpenAI
import requests
azure_endpoint = os.getenv('AZURE_OPENAI_ENDPOINT')
azure_key = os.getenv('AZURE_OPENAI_KEY')
telegram_bot_token = os.getenv('TELEGRAM_BOT_TOKEN')
telegram_channel_id = os.getenv('TELEGRAM_CHANNEL_ID')
client = AzureOpenAI(
azure_endpoint=azure_endpoint,
api_key=azure_key,
api_version="2023-05-15"
)
app = func.FunctionApp()
@app.route(route="SummarizerFunction", auth_level=func.AuthLevel.FUNCTION, methods=["POST"])
def summarizer(req: func.HttpRequest) -> func.HttpResponse:
logging.info('Python HTTP trigger function processed a request.')
# Deserialize article name from request body
req_body = req.get_json()
article_name = req_body.get('articleName')
# Retrieve article raw markdown content from GitHub
raw_md_content = requests.get(
response = client.chat.completions.create(
model="gpt4_turbo",
messages=[
{"role": "system", "content": "You are a skilled copywriter. Summarize the following article in 50 words."},
{"role": "user", "content": raw_md_content}
]
)
# Prepare the Telegram message text
# Post message to Telegram channel
"chat_id": telegram_channel_id, "text": telegram_message_text, "parse_mode": "Markdown"})
return func.HttpResponse(f"Telegram responded with: {telegram_response}", status_code=telegram_response.status_code)
To ensure everything functions correctly, set the following environmental variables:
- AZURE_OPENAI_ENDPOINT: Your Azure OpenAI service endpoint
- AZURE_OPENAI_KEY: Your Azure OpenAI service key
- TELEGRAM_BOT_TOKEN: The token for your Telegram bot
- TELEGRAM_CHANNEL_ID: The ID of your Telegram channel
💡 Remember to grant your bot sufficient permissions to post in your channel. After creating the channel, refer to the walkthrough to obtain a token and add your bot to the channel.
Assuming all parameters are correctly set, you can test your Azure Function by running func start. The function will be ready for input. You can use curl or a graphical tool like Insomnia to send a request:
curl -X POST http://localhost:7071/api/SummarizerFunction -H 'Content-Type: application/json' -d '{"articleName" : "diy-copilot-phi"}'
If successful, you should see a new post in your Telegram channel!
Chapter 2: Deployment and Testing
Now that the function works as expected, it's time to deploy it to Azure. Begin by creating a new serverless Function App in your Azure subscription. You can follow the instructions for using either the Azure CLI or the Azure Portal.
Take note of your Function App's name (e.g., summarizer-bot-fap). Next, deploy it using the Azure Functions Core Tools:
func azure functionapp publish
💡 Don’t forget to set the App Settings for the Function App in the portal or via command line. For enhanced security, consider using Key Vault references.
Once the publish step is successful, you should see the function listed in the Functions tab of your Function App. Click on your Azure Function name and then select the "Get Function Url" button. This URL will contain the default Host key required for authenticating with your Function App, so handle it securely.
Next, navigate to GitHub and add the FUNCTION_URL to your repository settings. Check the guide if you need assistance. You should see this in your repository's Secrets and Variables/Action Secrets section.
Now, let's test the deployment by committing to the repository with the message: "article: diy-copilot-phi test function app." After a moment, the trigger summarizer job should show as successful! Check your Telegram channel, and you should see the summary along with the article link.
In conclusion, we have successfully created an automated summarization solution using Azure OpenAI, Azure Functions, and GitHub Actions. Future enhancements could include a review step for summaries before publication, possibly through a secondary private channel for approving or modifying them. I might explore this in a future article, but for now, this implementation meets my needs perfectly.
Thank you for following along—here's to the power of technology!
References
- Conventional Commits
- AWK command in Unix/Linux with examples — GeeksforGeeks
- Deploying Azure OpenAI Service using OpenTofu | by Tommaso Colella | Feb, 2024 | Medium
- Create a Python function from the command line — Azure Functions | Microsoft Learn
- requests · PyPI
- openai · PyPI
- venv — Creation of virtual environments — Python 3.11.8 documentation
- From BotFather to 'Hello World' (telegram.org)
- Create a serverless function app using the Azure CLI | Microsoft Learn
- Use Key Vault references — Azure App Service | Microsoft Learn
- Using secrets in GitHub Actions — GitHub Docs