- remove allowed_langages from tenant - Correct bugs in Tenant, TenantMake, SpecialistMagicLink - Change chat client customisation elements
195 lines
7.2 KiB
Python
195 lines
7.2 KiB
Python
import uuid
|
|
from flask import Blueprint, render_template, request, session, current_app, jsonify, abort
|
|
from sqlalchemy.exc import SQLAlchemyError
|
|
|
|
from common.extensions import db
|
|
from common.models.user import Tenant, SpecialistMagicLinkTenant, TenantMake
|
|
from common.models.interaction import SpecialistMagicLink, Specialist, ChatSession, Interaction
|
|
from common.services.interaction.specialist_services import SpecialistServices
|
|
from common.utils.database import Database
|
|
from common.utils.chat_utils import get_default_chat_customisation
|
|
|
|
chat_bp = Blueprint('chat_bp', __name__, url_prefix='/chat')
|
|
|
|
@chat_bp.before_request
|
|
def log_before_request():
|
|
current_app.logger.debug(f'Before request: {request.path} =====================================')
|
|
|
|
|
|
@chat_bp.after_request
|
|
def log_after_request(response):
|
|
return response
|
|
|
|
|
|
# @chat_bp.before_request
|
|
# def before_request():
|
|
# try:
|
|
# mw_before_request()
|
|
# except Exception as e:
|
|
# current_app.logger.error(f'Error switching schema in Document Blueprint: {e}')
|
|
# raise
|
|
|
|
|
|
@chat_bp.route('/')
|
|
def index():
|
|
customisation = get_default_chat_customisation()
|
|
return render_template('error.html', message="Please use a valid magic link to access the chat.",
|
|
customisation=customisation)
|
|
|
|
|
|
@chat_bp.route('/<magic_link_code>')
|
|
def chat(magic_link_code):
|
|
"""
|
|
Main chat interface accessed via magic link
|
|
"""
|
|
try:
|
|
# Find the tenant using the magic link code
|
|
magic_link_tenant = SpecialistMagicLinkTenant.query.filter_by(magic_link_code=magic_link_code).first()
|
|
|
|
if not magic_link_tenant:
|
|
current_app.logger.error(f"Invalid magic link code: {magic_link_code}")
|
|
return render_template('error.html', message="Invalid magic link code.")
|
|
|
|
# Get tenant information
|
|
tenant_id = magic_link_tenant.tenant_id
|
|
tenant = Tenant.query.get(tenant_id)
|
|
if not tenant:
|
|
current_app.logger.error(f"Tenant not found for ID: {tenant_id}")
|
|
return render_template('error.html', message="Tenant not found.")
|
|
# Switch to tenant schema
|
|
Database(tenant_id).switch_schema()
|
|
|
|
# Get specialist magic link details from tenant schema
|
|
specialist_ml = SpecialistMagicLink.query.filter_by(magic_link_code=magic_link_code).first()
|
|
if not specialist_ml:
|
|
current_app.logger.error(f"Specialist magic link not found in tenant schema: {tenant_id}")
|
|
return render_template('error.html', message="Specialist configuration not found.")
|
|
|
|
# Get relevant TenantMake
|
|
tenant_make = TenantMake.query.get(specialist_ml.tenant_make_id)
|
|
if not tenant_make:
|
|
current_app.logger.error(f"Tenant make not found: {specialist_ml.tenant_make_id}")
|
|
return render_template('error.html', message="Tenant make not found.")
|
|
|
|
# Get specialist details
|
|
specialist = Specialist.query.get(specialist_ml.specialist_id)
|
|
if not specialist:
|
|
current_app.logger.error(f"Specialist not found: {specialist_ml.specialist_id}")
|
|
return render_template('error.html', message="Specialist not found.")
|
|
|
|
# Store necessary information in session
|
|
session['tenant'] = tenant.to_dict()
|
|
session['specialist'] = specialist.to_dict()
|
|
session['magic_link'] = specialist_ml.to_dict()
|
|
session['tenant_make'] = tenant_make.to_dict()
|
|
|
|
# Get customisation options with defaults
|
|
customisation = get_default_chat_customisation(tenant_make.chat_customisation_options)
|
|
|
|
# Start a new chat session
|
|
session['chat_session_id'] = SpecialistServices.start_session()
|
|
|
|
return render_template('chat.html',
|
|
tenant=tenant,
|
|
tenant_make=tenant_make,
|
|
specialist=specialist,
|
|
customisation=customisation)
|
|
|
|
except Exception as e:
|
|
current_app.logger.error(f"Error in chat view: {str(e)}", exc_info=True)
|
|
return render_template('error.html', message="An error occurred while setting up the chat.")
|
|
|
|
@chat_bp.route('/api/send_message', methods=['POST'])
|
|
def send_message():
|
|
"""
|
|
API endpoint to send a message to the specialist
|
|
"""
|
|
try:
|
|
data = request.json
|
|
message = data.get('message')
|
|
|
|
if not message:
|
|
return jsonify({'error': 'No message provided'}), 400
|
|
|
|
tenant_id = session.get('tenant_id')
|
|
specialist_id = session.get('specialist_id')
|
|
chat_session_id = session.get('chat_session_id')
|
|
specialist_args = session.get('specialist_args', {})
|
|
|
|
if not all([tenant_id, specialist_id, chat_session_id]):
|
|
return jsonify({'error': 'Session expired or invalid'}), 400
|
|
|
|
# Switch to tenant schema
|
|
Database(tenant_id).switch_schema()
|
|
|
|
# Add user message to specialist arguments
|
|
specialist_args['user_message'] = message
|
|
|
|
# Execute specialist
|
|
result = SpecialistServices.execute_specialist(
|
|
tenant_id=tenant_id,
|
|
specialist_id=specialist_id,
|
|
specialist_arguments=specialist_args,
|
|
session_id=chat_session_id,
|
|
user_timezone=data.get('timezone', 'UTC')
|
|
)
|
|
|
|
# Store the task ID for polling
|
|
session['current_task_id'] = result['task_id']
|
|
|
|
return jsonify({
|
|
'status': 'processing',
|
|
'task_id': result['task_id']
|
|
})
|
|
|
|
except Exception as e:
|
|
current_app.logger.error(f"Error sending message: {str(e)}", exc_info=True)
|
|
return jsonify({'error': str(e)}), 500
|
|
|
|
@chat_bp.route('/api/check_status', methods=['GET'])
|
|
def check_status():
|
|
"""
|
|
API endpoint to check the status of a task
|
|
"""
|
|
try:
|
|
task_id = request.args.get('task_id') or session.get('current_task_id')
|
|
|
|
if not task_id:
|
|
return jsonify({'error': 'No task ID provided'}), 400
|
|
|
|
tenant_id = session.get('tenant_id')
|
|
if not tenant_id:
|
|
return jsonify({'error': 'Session expired or invalid'}), 400
|
|
|
|
# Switch to tenant schema
|
|
Database(tenant_id).switch_schema()
|
|
|
|
# Check task status using Celery
|
|
task_result = current_app.celery.AsyncResult(task_id)
|
|
|
|
if task_result.state == 'PENDING':
|
|
return jsonify({'status': 'pending'})
|
|
elif task_result.state == 'SUCCESS':
|
|
result = task_result.result
|
|
|
|
# Format the response
|
|
specialist_result = result.get('result', {})
|
|
response = {
|
|
'status': 'success',
|
|
'answer': specialist_result.get('answer', ''),
|
|
'citations': specialist_result.get('citations', []),
|
|
'insufficient_info': specialist_result.get('insufficient_info', False),
|
|
'interaction_id': result.get('interaction_id')
|
|
}
|
|
|
|
return jsonify(response)
|
|
else:
|
|
return jsonify({
|
|
'status': 'error',
|
|
'message': str(task_result.info)
|
|
})
|
|
|
|
except Exception as e:
|
|
current_app.logger.error(f"Error checking status: {str(e)}", exc_info=True)
|
|
return jsonify({'error': str(e)}), 500
|