Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
97 commits
Select commit Hold shift + click to select a range
8388c41
Merge pull request #7 from bradlab/feat-telegram-bot
bradlab May 24, 2025
64f1aea
Merge pull request #8 from bradlab/persist-data-with-dynamodb
bradlab May 25, 2025
7ff5259
Merge pull request #10 from bradlab/persist-data-with-dynamodb
bradlab May 31, 2025
85898db
Refactor DynamoDB key attributes and update message saving parameters…
mbradiouf May 31, 2025
bce11a4
Merge pull request #11 from bradlab/persist-data-with-dynamodb
bradlab May 31, 2025
bbe471b
Update environment variable credentials and default values in Jenkins…
mbradiouf Jun 1, 2025
af8417f
Merge pull request #12 from bradlab/persist-data-with-dynamodb
bradlab Jun 1, 2025
4555559
Merge pull request #13 from bradlab/matbradiouf
bradlab Jun 1, 2025
d22ac6d
Add environment variables for Lambda function configuration in templa…
mbradiouf Jun 1, 2025
7c387dc
Add .prod.env to .gitignore and comment out sensitive environment var…
mbradiouf Jun 1, 2025
f9457df
Merge pull request #14 from bradlab/persist-data-with-dynamodb
bradlab Jun 1, 2025
4c6bfd1
Update API_WEBHOOK_URL construction to include TELEGRAM_BOT_TOKEN for…
mbradiouf Jun 1, 2025
29be23a
Merge pull request #15 from bradlab/persist-data-with-dynamodb
bradlab Jun 1, 2025
121ac87
Comment out TELEGRAM_API_URL and WEBHOOK_URL in template.yaml for sen…
mbradiouf Jun 1, 2025
f5c3ff2
Merge pull request #16 from bradlab/persist-data-with-dynamodb
bradlab Jun 1, 2025
f105079
Comment out environment variables in template.yaml for sensitive info…
mbradiouf Jun 1, 2025
22d462e
Update environment variables in template.yaml for proper configuration
mbradiouf Jun 1, 2025
3ebb69a
Comment out WEBHOOK_URL in template.yaml for sensitive information ha…
mbradiouf Jun 1, 2025
d51afef
Comment out environment variables in template.yaml for sensitive info…
mbradiouf Jun 1, 2025
8d1a842
Refactor environment variable handling in template.yaml for improved …
mbradiouf Jun 1, 2025
aa0c990
Add AWS_PROFILE variable to Settings class for enhanced configuration
mbradiouf Jun 1, 2025
6c2a361
Add DynamoDB CRUD policies to Lambda function for enhanced permissions
mbradiouf Jun 1, 2025
ede488e
Update ApiWebhookUrl parameter to hide default value and fix Api even…
mbradiouf Jun 1, 2025
ac27922
Comment out NoEcho for sensitive parameters in template.yaml for impr…
mbradiouf Jun 1, 2025
0f40c9d
Enable NoEcho for sensitive parameters in template.yaml and implement…
mbradiouf Jun 1, 2025
69332f4
Update ApiWebhookUrl parameter to use a default value and add Webhook…
mbradiouf Jun 1, 2025
c7213f4
Add default values for DynamoTable, MistralApiKey, and TelegramBotTok…
mbradiouf Jun 1, 2025
6e2c630
Refactor environment variables in .example.env and template.yaml for …
mbradiouf Jun 2, 2025
6b801ef
Remove AWS_PROFILE from config and update environment files; add Tele…
mbradiouf Jun 2, 2025
90abc47
Update .gitignore to include .env file for environment variable manag…
mbradiouf Jun 2, 2025
b725401
Remove .env file and update template.yaml to define parameters for AW…
mbradiouf Jun 2, 2025
cddc6c5
Add DynamoDB policies and improve error handling in Telegram bot
mbradiouf Jun 2, 2025
fc39014
Improve Telegram webhook configuration to avoid unnecessary updates
mbradiouf Jun 2, 2025
a2dc8f0
Add UUID generation for message IDs and include 'id' attribute in Dyn…
mbradiouf Jun 2, 2025
623019a
Remove 'id' attribute from DynamoDB index projection in template.yaml
mbradiouf Jun 2, 2025
9052c05
Refactor logging methods in Utils class to use a centralized logger i…
mbradiouf Jun 2, 2025
2b50d4a
Refactor chat response handling to remove asyncio timeout and simplif…
mbradiouf Jun 2, 2025
63e5cf9
Refactor logging configuration in Utils class and enhance error handl…
mbradiouf Jun 2, 2025
a3ab661
Fix error logging in start_command and add webhook connection log in …
mbradiouf Jun 2, 2025
f2e8919
Enhance Jenkinsfile to use credentials for Telegram bot and Mistral A…
mbradiouf Jun 2, 2025
d40ecb8
Update webhook configuration in Jenkinsfile and enhance FastAPI webho…
mbradiouf Jun 3, 2025
4d57d68
Enhance .dockerignore to include .dev.env and update template.yaml to…
mbradiouf Jun 3, 2025
12cfb6e
Add warning log for user messages in handle_message function
mbradiouf Jun 3, 2025
ee10705
Refactor .dockerignore and .gitignore to manage environment files, re…
mbradiouf Jun 3, 2025
5472ca0
Refactor handle_message function for improved error logging and add g…
mbradiouf Jun 3, 2025
372c157
Comment out UUID generation in save_message method of DynamoDBRepository
mbradiouf Jun 3, 2025
7ff8030
Uncomment UUID generation in save_message method and enhance webhook …
mbradiouf Jun 3, 2025
c838ce2
Improve webhook error logging by including the webhook URL in the err…
mbradiouf Jun 3, 2025
f3866a9
Refactor start_command response text for improved user engagement and…
mbradiouf Jun 3, 2025
199b8ee
Log warning message before configuring Telegram webhook and await the…
mbradiouf Jun 3, 2025
b8fe596
Update webhook logging to show new and old URLs, and change log level…
mbradiouf Jun 3, 2025
366ffcf
Fix webhook URL formatting in Jenkinsfile and ensure proper shutdown …
mbradiouf Jun 3, 2025
846504a
Comment out database save operations in start_command for debugging p…
mbradiouf Jun 3, 2025
0d7ec55
Refactor log messages in start_command and configure_telegram_webhook…
mbradiouf Jun 3, 2025
d6a5328
Comment out database save operations in handle_message for debugging …
mbradiouf Jun 3, 2025
801e4fb
Refactor message handling in start_command and handle_message for imp…
mbradiouf Jun 3, 2025
6450a1a
Translate welcome message and error responses to English for better u…
mbradiouf Jun 3, 2025
05305bb
Enable database message saving in handle_message and add logging for …
mbradiouf Jun 3, 2025
b4349ed
Enable logging of user messages in handle_message for better traceabi…
mbradiouf Jun 3, 2025
5516eb3
Add logging for message responses and conditional database saving in …
mbradiouf Jun 3, 2025
593f3f4
Add logging for Mistral response retrieval and conditional message sa…
mbradiouf Jun 3, 2025
6d317ed
Refactor Mistral response retrieval to use synchronous call in handle…
mbradiouf Jun 3, 2025
5c49efe
Add help and clear commands to handle_message for user assistance
mbradiouf Jun 3, 2025
f287cf1
Add reply keyboard markup to start command for improved user interaction
mbradiouf Jun 3, 2025
acc4f9a
Add error logging in handle_message for better debugging
mbradiouf Jun 3, 2025
029c4e1
Remove clear command from reply keyboard in start command for streaml…
mbradiouf Jun 3, 2025
56566ba
Comment out message saving in handle_message for debugging purposes
mbradiouf Jun 3, 2025
0a183ff
Refactor handle_message to enable message saving and improve response…
mbradiouf Jun 3, 2025
d0fdf62
Comment out message saving in handle_message for debugging purposes
mbradiouf Jun 3, 2025
4f9d061
Refactor handle_message to enable message saving in DynamoDB and impr…
mbradiouf Jun 3, 2025
016360f
Refactor handle_message to restore message saving in DynamoDB and imp…
mbradiouf Jun 3, 2025
f777be4
Restore message saving in DynamoDB for start_command and improve erro…
mbradiouf Jun 3, 2025
1caedc6
Update DynamoDB permissions to allow all actions for the chatbot func…
mbradiouf Jun 3, 2025
851df5b
Change logger name to standardize logging format
mbradiouf Jun 3, 2025
a6b848c
Update DynamoDB permissions to specify allowed actions and comment ou…
mbradiouf Jun 3, 2025
ad30e4c
Refactor message handling to improve user message logging and bot res…
mbradiouf Jun 4, 2025
2df0f93
Refactor Telegram handler to improve structure and logging; consolida…
mbradiouf Jun 5, 2025
fd0053d
Initialize setup of PTB handlers in TelegramHandler constructor
mbradiouf Jun 5, 2025
36da2ca
Enable setup of PTB handlers in application lifespan and comment out …
mbradiouf Jun 5, 2025
bdd4f49
Refactor test fixtures to improve mocking of environment variables an…
mbradiouf Jun 5, 2025
0e1b282
Refactor tests to enhance Telegram command handling and improve webho…
mbradiouf Jun 5, 2025
9bdc8fc
Refactor test setup to include TestClient fixture and improve structu…
mbradiouf Jun 5, 2025
dba4fd7
Refactor test setup to include mocking of telegram_handler singleton …
mbradiouf Jun 5, 2025
106b501
Refactor test cases to improve structure and enhance mocking of Teleg…
mbradiouf Jun 5, 2025
46a6a5b
Refactor tests to use setattr for mocking send_message and ensure ori…
mbradiouf Jun 5, 2025
8618170
Refactor tests to simplify mocking of send_message and improve code r…
mbradiouf Jun 5, 2025
c844042
Refactor tests to improve structure and enhance mocking for Telegram …
mbradiouf Jun 5, 2025
711349b
Refactor test setup to enhance mocking and improve test isolation for…
mbradiouf Jun 5, 2025
940218b
Refactor TelegramHandler to comment out message saving logic and remo…
mbradiouf Jun 5, 2025
2223c4f
Fix error handling in save_message to raise exceptions instead of ret…
mbradiouf Jun 6, 2025
f0eba18
Refactor DynamoDB message saving logic to use attribute value format …
mbradiouf Jun 7, 2025
26ee937
Comment out message saving logic in handle_message and chat completio…
mbradiouf Jun 7, 2025
6bb8fa3
Refactor DynamoDB interactions in Utils and TelegramHandler; implemen…
mbradiouf Jun 8, 2025
ac04828
Refactor DynamoDBRepository to restore table initialization logic and…
mbradiouf Jun 8, 2025
302de1d
Add API Gateway permissions for POST and GET methods; enable DynamoDB…
mbradiouf Jun 8, 2025
28614fc
Refactor save_message method to use simplified item structure and imp…
mbradiouf Jun 8, 2025
babba81
Comment out the asynchronous put_item operation in save_message to te…
mbradiouf Jun 8, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .example.env
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,5 @@ MISTRAL_API_KEY=votre-clé-mistral

# TELEGRAM BOT
TELEGRAM_BOT_TOKEN=votre-token-bot-telegram
TELEGRAM_CHAT_ID=votre-id-chat-telegram
TELEGRAM_API_URL=https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}
TELEGRAM_API_URL=https://api.telegram.org/bot
WEBHOOK_URL=https://6cc5-102-64-223-197.ngrok-free.app/webhook
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ celerybeat.pid

# Environments
.env
.prod.env
.dev.env
.venv
env/
venv/
Expand Down
68 changes: 65 additions & 3 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ pipeline {
environment {
// Define environment variables here
BOT_NAME = 'awesome-bot'
// BOT_TOKEN = credentials('telegram-bot-token')
TELEGRAM_BOT_TOKEN = credentials('telegram-bot-token')
MISTRAL_API_KEY = credentials('mistral-api-key')
}

stages {
Expand All @@ -22,7 +23,7 @@ pipeline {
stage('Environment variable injection') {
steps {
script {
withCredentials([file(credentialsId: 'matbradiouf-chatbot-env-file', variable: 'ENV_FILE')]) {
withCredentials([file(credentialsId: 'bradlab-chatbot-env-file', variable: 'ENV_FILE')]) {
// Load the environment variables from the file
echo "Loading environment variables from ${ENV_FILE}"
sh "cat ${ENV_FILE} > .env"
Expand Down Expand Up @@ -53,16 +54,77 @@ pipeline {
}

stage('Deploy') {
when {
anyOf {
branch 'bradlab'
branch 'dev'
branch 'preprod'
branch 'prod'
}
}
steps {
script {
// Add your deployment commands here
echo "Deploying the project..."
sh "make deploy env=${BRANCH_NAME}"
withCredentials([
string(credentialsId: 'telegram-bot-token', variable: 'TELEGRAM_BOT_TOKEN'),
string(credentialsId: 'mistral-api-key', variable: 'MISTRAL_API_KEY')
]) {
sh """
make deploy env=${BRANCH_NAME} \
TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN} \
MISTRAL_API_KEY=${MISTRAL_API_KEY}
"""
}
}
}
}

stage('Configure Webhook') {
when {
anyOf {
branch 'bradlab'
branch 'dev'
branch 'preprod'
branch 'prod'
}
}
steps {
script {
// Get the API URL from CloudFormation outputs
def apiUrl = sh(
script: """
aws cloudformation describe-stacks \
--stack-name multi-stack-${BRANCH_NAME} \
--region eu-west-3 \
--query "Stacks[0].Outputs[?OutputKey=='ApiUrl'].OutputValue" \
--output text
""",
returnStdout: true
).trim()

// Configure the webhook
withCredentials([string(credentialsId: 'telegram-bot-token', variable: 'TELEGRAM_BOT_TOKEN')]) {
sh """
curl -X POST "${apiUrl}set-webhook" \\
-H "Authorization: Bearer ${TELEGRAM_BOT_TOKEN}" \\
-H "Content-Type: application/json" \\
-d '{ "url": "${apiUrl}webhook" }'
"""
}
}
}
}

stage('Test endpoint'){
when {
anyOf {
branch 'bradlab'
branch 'dev'
branch 'preprod'
branch 'prod'
}
}
steps {
script {
// Add your endpoint testing commands here
Expand Down
1 change: 0 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@

# by default, we settle down in this region
AWS_REGION ?= eu-west-3
AWS_PROFILE ?= "esgis_profile"

clean:
rm -rf venv
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ Une API de chatbot développée avec FastAPI, conçue pour être déployée sur
DYNAMO_TABLE=votre-table-dynamo
AWS_PROFILE=votre-profil-aws
MISTRAL_API_KEY=votre-clé-mistral
TELEGRAM_BOT_TOKEN=votre-token-bot-telegram
TELEGRAM_API_URL=https://api.telegram.org/bot
WEBHOOK_URL=votre-api-url/webhook
```

## ▶️ Exécution
Expand Down
72 changes: 65 additions & 7 deletions infrastructure/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,42 @@ Parameters:
Description: Environment name for the application dev/staging/production
Type: String
AllowedValues:
- matbradiouf
- bradlab
- dev
- preprod
- prod
Default: matbradiouf
Default: bradlab
###############################################################################

AWSRegionName:
Description: AWS region where resources will be deployed (e.g. eu-west-3)
Type: String
Default: eu-west-3
DynamoTable:
Description: Name of the DynamoDB table used to persist chatbot conversations
Type: String
Default: ""
NoEcho: true
AwsProfile:
Description: AWS CLI profile name used for deployment (for local/devops usage)
Type: String
Default: esgis_profile
MistralApiKey:
Description: API key for accessing the Mistral AI service
Type: String
Default: ""
NoEcho: true
TelegramBotToken:
Description: Telegram bot token for authenticating with the Telegram API
Type: String
Default: ""
NoEcho: true
ApiWehookUrl:
Type: String
Default: ""
TelegramApiBotUrl:
Type: String
Default: https://api.telegram.org/bot
###############################################################################
Resources:
###############################################################################
Expand All @@ -23,15 +54,15 @@ Resources:
TableName: !Sub "chatbot-dbtable-${EnvironmentName}"
# Définition des attributs utilisés comme clés pour la table principale et les GSI
AttributeDefinitions:
- AttributeName: "id"
- AttributeName: "chat_id"
AttributeType: "S"
- AttributeName: "timestamp"
AttributeType: "S"
- AttributeName: "user_id" # Attribut nécessaire pour UserIndex
AttributeType: "S"
# Schéma de la clé primaire de la table principale
KeySchema:
- AttributeName: "id"
- AttributeName: "chat_id"
KeyType: "HASH"
- AttributeName: "timestamp"
KeyType: "RANGE"
Expand All @@ -51,7 +82,7 @@ Resources:
Projection:
ProjectionType: "INCLUDE"
NonKeyAttributes: # Attributs à projeter en plus des clés de l'index et de la table
- "id"
- "chat_id"
- "message_id"
- "role"
- "text"
Expand All @@ -67,6 +98,33 @@ Resources:
CodeUri: ../
Handler: src/main.handler
Runtime: python3.12
Environment:
Variables:
ENV_NAME: !Ref EnvironmentName
AWS_REGION_NAME: !Ref AWSRegionName
DYNAMO_TABLE: !Ref DynamoDBTable
MISTRAL_API_KEY: !Ref MistralApiKey
TELEGRAM_BOT_TOKEN: !Ref TelegramBotToken
TELEGRAM_API_URL: !Ref TelegramApiBotUrl
WEBHOOK_URL: !Ref ApiWehookUrl
Policies:
- DynamoDBCrudPolicy:
TableName: !Ref DynamoDBTable
- Statement:
- Effect: Allow
Action:
- dynamodb:GetItem
- dynamodb:DeleteItem
- dynamodb:PutItem
- dynamodb:Query
- dynamodb:UpdateItem
- dynamodb:BatchWriteItem
- dynamodb:BatchGetItem
- dynamodb:DescribeTable
- dynamodb:ConditionCheckItem
- apigateway:POST
- apigateway:GET
Resource: "*"
Events:
Api:
Type: HttpApi
Expand All @@ -83,6 +141,6 @@ Outputs:
DynamoDBTableName:
Value: !Ref DynamoDBTable
ApiUrl:
Description: URL of your API
Description: URL of our API
Value:
Fn::Sub: 'https://${Api}.execute-api.${AWS::Region}.${AWS::URLSuffix}/'
Fn::Sub: 'https://${Api}.execute-api.${AWS::Region}.${AWS::URLSuffix}/'
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ mangum
httpx
mistralai
python-telegram-bot
slowapi
34 changes: 25 additions & 9 deletions src/dynamodb_repository.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import boto3
import datetime
import asyncio
import datetime, asyncio, uuid

from botocore.exceptions import ClientError
from boto3.dynamodb.conditions import Key, Attr
Expand Down Expand Up @@ -44,9 +43,20 @@ async def save_message(
Sauvegarde un message (utilisateur ou bot) dans la table DynamoDB.
"""
try:

id = str(uuid.uuid4()) # Génère un UUID
# item = {
# "id": {"S": str(id)},
# "chat_id": {"S": str(chat_id)},
# "timestamp": {"S": datetime.datetime.now(datetime.timezone.utc).isoformat()},
# "message_id": {"S": str(message_id)},
# "user_id": {"S": str(user_id)},
# "user_name": {"S": user_name},
# "text": {"S": text},
# "role": {"S": role},
# }
item = {
'id': str(chat_id),
'id': id,
'chat_id': str(chat_id),
'timestamp': datetime.datetime.now(datetime.timezone.utc).isoformat(),
'message_id': str(message_id),
'user_id': str(user_id),
Expand All @@ -55,29 +65,34 @@ async def save_message(
'role': role,
}
if ai_model:
item['ai_model'] = ai_model
item["ai_model"] = str(ai_model)
# item["ai_model"] = {"S": ai_model}

# Utils.insert_data(item)

# Exécute l'opération put_item (synchrone) dans un thread séparé
await asyncio.to_thread(self.table.put_item, Item=item)
Utils.log_info(f"Message enregistré dans DynamoDB: chat_id={chat_id}, role={role}")
# await asyncio.to_thread(self.table.put_item, Item=item)
return True
except Exception as e:
Utils.log_error(f"Erreur lors de l'enregistrement dans DynamoDB: {e}")
# L'erreur n'est pas levée pour ne pas interrompre le flux du bot
raise e

async def get_chat_history(self, chat_id: int, limit: int = 100) -> list[dict]:
"""
Récupère l'historique d'une discussion donnée par chat_id, trié par timestamp.
Retourne une liste de dictionnaires représentant les messages.
"""
try:
# return Utils.get_chat_history(chat_id=chat_id, limit=limit)
response = await asyncio.to_thread(
self.table.query,
KeyConditionExpression=Key('id').eq(str(chat_id)),
KeyConditionExpression=Key('chat_id').eq(str(chat_id)),
Limit=limit,
ScanIndexForward=True # True pour tri ascendant (du plus ancien au plus récent)
)
Utils.log_info(f"Historique du chat {chat_id} récupéré. Messages trouvés: {len(response.get('Items', []))}")
return response.get('Items', [])
# return response.get('Items', [])
except ClientError as e:
error_code = e.response['Error']['Code']
Utils.log_error(f"Erreur DynamoDB lors de la récupération de l'historique: {error_code} - {e}")
Expand All @@ -94,6 +109,7 @@ async def get_user_messages_by_date_range(self, user_id: int, start_timestamp: s
"""
gsi_name = "UserIndex"
try:
# return Utils.get_user_chats(user_id, start_timestamp, end_timestamp, limit)
query_params = {
'IndexName': gsi_name,
'KeyConditionExpression': Key('user_id').eq(str(user_id)) & Key('timestamp').between(start_timestamp, end_timestamp),
Expand Down
Loading