Microsoft Teams Development
Microsoft Teams: A Microsoft customizable chat-based workspace.Development: The process of researching, productizing, and refining new or existing technologies.
3,638 questions
This browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
Hi,
We have built a custom AI agent with RAG approach using AI search and Azure Open AI service in Teams toolkit framework. We have also provisioned PostgreSQL in Azure for storing the responses and human feedback.
The toolkit works fine when tested locally using test tool, but when deployed into the teams, bot is not responding.
This issue raised when PostgreSQL integrated with toolkit for capturing responses and feedback.
the bot code is as follows, any suggestion would help.
import asyncio
from dataclasses import dataclass, asdict
import json
import os
import sys
import traceback
from typing import Generic, TypeVar, List, Dict, Any, Optional
import psycopg2
from datetime import datetime
from botbuilder.core import MemoryStorage, TurnContext, Middleware, ActivityHandler
from botbuilder.schema import Activity, ActivityTypes
from teams import Application, ApplicationOptions, TeamsAdapter
from teams.ai import AIOptions
from teams.ai.models import AzureOpenAIModelOptions, OpenAIModel, OpenAIModelOptions
from teams.ai.planners import ActionPlanner, ActionPlannerOptions
from teams.ai.prompts import PromptManager, PromptManagerOptions
from teams.ai.actions import ActionTypes
from teams.state import TurnState
from teams.feedback_loop_data import FeedbackLoopData
from azure_ai_search_data_source import AzureAISearchDataSource, AzureAISearchDataSourceOptions
from config import Config
class ChatbotApplication:
def __init__(self, config):
self.config = config
# Azure PostgreSQL connection parameters
self.db_config = {
'dbname': 'POSTGREDB_NAME', # Standard database name in Azure PostgreSQL
'user': 'USER',
'password': 'DB_KEY',
'host': 'DB_HOST',
'port': '5432',
'sslmode': 'require' # Required for secure Azure connections
}
# Initialize the chat bot components
self.create_required_tables()
self.setup_bot_components()
def setup_bot_components(self):
# Create AI components
model = OpenAIModel(
AzureOpenAIModelOptions(
api_key=self.config.AZURE_OPENAI_API_KEY,
default_model=self.config.AZURE_OPENAI_MODEL_DEPLOYMENT_NAME,
endpoint=self.config.AZURE_OPENAI_ENDPOINT,
)
)
prompts = PromptManager(PromptManagerOptions(prompts_folder=f"{os.getcwd()}/prompts"))
prompts.add_data_source(
AzureAISearchDataSource(
AzureAISearchDataSourceOptions(
name='azure-ai-search',
indexName='index-demo',
azureAISearchApiKey=self.config.AZURE_SEARCH_KEY,
azureAISearchEndpoint=self.config.AZURE_SEARCH_ENDPOINT,
)
)
)
planner = ActionPlanner(
ActionPlannerOptions(model=model, prompts=prompts, default_prompt="chat")
)
# Create our custom adapter
self.custom_adapter = ResponseCaptureAdapter(self.config)
# Define storage and application
self.storage = MemoryStorage()
self.bot_app = Application[TurnState](
ApplicationOptions(
bot_app_id=self.config.APP_ID,
storage=self.storage,
adapter=self.custom_adapter, # Use our custom adapter
ai=AIOptions(planner=planner, enable_feedback_loop=True),
)
)
def setup_event_handlers(self):
"""Setup all event handlers for the bot application"""
@self.bot_app.error
async def on_error(context: TurnContext, error: Exception):
print(f"\n [on_turn_error] unhandled error: {error}", file=sys.stderr)
traceback.print_exc()
await context.send_activity("The bot encountered an error or bug.")
@self.bot_app.activity("message")
async def on_message(context: TurnContext, state: TurnState):
try:
query = context.activity.text
print(f"Received message: {query[:100] if query else 'None'}")
# Run the AI which will generate and send responses
result = await self.bot_app.ai.run(context, state)
print(f"AI result: {result}")
# Capture the response from our adapter
adapter = context.adapter
if isinstance(adapter, ResponseCaptureAdapter):
response_data = adapter.get_response_for_query(context)
if query and response_data:
conversation_id = response_data['conversation_id']
activity_id = response_data['activity_id']
print(f"Processing response for conversation_id: {conversation_id}, activity_id: {activity_id}")
# Store response along with conversation and activity IDs
chat_log_id = await self.log_chat_to_db(
query,
response_data['text'],
conversation_id,
activity_id,
None, # Initially, human_feedback is null
None # Initially, comments are null
)
if chat_log_id:
# Store mapping in our new table
await self.store_feedback_mapping(conversation_id, activity_id, chat_log_id)
# Store IDs in conversation state for persistence
# We'll also store in turn state as a backup
key = f"{conversation_id}_last_activity"
await self.storage.write({key: activity_id})
# Store in turn state as well (may not persist between turns)
# Use dictionary style access for TurnState
state["conversation_reference"] = {
'conversation_id': conversation_id,
'activity_id': activity_id,
'chat_log_id': chat_log_id
}
print(f"Stored conversation reference in state: {state['conversation_reference']}")
# Clear stored response
conversation_activity_id = f"{conversation_id}_{activity_id}"
if conversation_activity_id in adapter.query_response_map:
del adapter.query_response_map[conversation_activity_id]
print(f"Cleared response from map for {conversation_activity_id}")
else:
print("Adapter is not an instance of ResponseCaptureAdapter")
return result
except Exception as e:
print(f"Error in on_message handler: {e}")
traceback.print_exc()