API key working, CORS working, SocketIO working (but no JWT), Chat client v1, Session implemented (server side)
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
import logging
|
||||
import logging.config
|
||||
from flask import Flask
|
||||
from flask_socketio import emit
|
||||
from redis import Redis
|
||||
|
||||
from common.extensions import db, socketio
|
||||
from common.extensions import db, socketio, jwt, kms_client, cors, session
|
||||
from config.logging_config import LOGGING
|
||||
from eveai_chat.socket_handlers import chat_handler
|
||||
from common.utils.cors_utils import create_cors_after_request
|
||||
|
||||
|
||||
def create_app(config_file=None):
|
||||
@@ -18,6 +20,15 @@ def create_app(config_file=None):
|
||||
logging.config.dictConfig(LOGGING)
|
||||
register_extensions(app)
|
||||
|
||||
# Register Blueprints
|
||||
register_blueprints(app)
|
||||
|
||||
@app.route('/ping')
|
||||
def ping():
|
||||
return 'pong'
|
||||
|
||||
app.logger.info("EveAI Chat Server Started Successfully")
|
||||
app.logger.info("-------------------------------------------------------------------------------------------------")
|
||||
return app
|
||||
|
||||
|
||||
@@ -29,5 +40,25 @@ def register_extensions(app):
|
||||
async_mode=app.config.get('SOCKETIO_ASYNC_MODE'),
|
||||
logger=app.config.get('SOCKETIO_LOGGER'),
|
||||
engineio_logger=app.config.get('SOCKETIO_ENGINEIO_LOGGER'),
|
||||
path='/socket.io'
|
||||
)
|
||||
jwt.init_app(app)
|
||||
kms_client.init_app(app)
|
||||
|
||||
# Cors setup
|
||||
cors.init_app(app, resources={r"/chat/*": {"origins": "*"}})
|
||||
app.after_request(create_cors_after_request('/chat'))
|
||||
|
||||
# Session setup
|
||||
# redis_config = app.config['SESSION_REDIS']
|
||||
# redis_client = Redis(host=redis_config['host'],
|
||||
# port=redis_config['port'],
|
||||
# db=redis_config['db'],
|
||||
# password=redis_config['password']
|
||||
# )
|
||||
session.init_app(app)
|
||||
|
||||
|
||||
def register_blueprints(app):
|
||||
from .views.chat_views import chat_bp
|
||||
app.register_blueprint(chat_bp)
|
||||
|
||||
52
eveai_chat/socket_handlers/chat_handler.py
Normal file
52
eveai_chat/socket_handlers/chat_handler.py
Normal file
@@ -0,0 +1,52 @@
|
||||
from flask_jwt_extended import verify_jwt_in_request, get_jwt_identity, verify_jwt_in_request, decode_token
|
||||
from flask_socketio import emit, disconnect
|
||||
from flask import current_app, request
|
||||
from common.extensions import socketio
|
||||
|
||||
|
||||
@socketio.on('connect')
|
||||
def handle_connect():
|
||||
try:
|
||||
# Extract token from the auth object
|
||||
token = request.args.get('token')
|
||||
if not token:
|
||||
raise Exception("Missing Authorization Token")
|
||||
current_app.logger.debug(f'SocketIO: Received token: {token}')
|
||||
# Verify token
|
||||
decoded_token = decode_token(token.split(" ")[1]) # Split to remove "Bearer " prefix
|
||||
tenant_id = decoded_token["identity"]["tenant_id"]
|
||||
current_app.logger.info(f'SocketIO: Tenant {decoded_token["identity"]["tenant_id"]} connected')
|
||||
# communicate connection to client
|
||||
emit('connect', {'status': 'Connected', 'tenant_id': tenant_id})
|
||||
except Exception as e:
|
||||
current_app.logger.error(f'SocketIO: Connection failed: {e}')
|
||||
# communicate connection problem to client
|
||||
emit('connect', {'status': 'Connection Failed'})
|
||||
disconnect()
|
||||
|
||||
|
||||
@socketio.on('disconnect')
|
||||
def handle_disconnect():
|
||||
current_app.logger.debug('SocketIO: Client disconnected')
|
||||
|
||||
|
||||
@socketio.on('user_message')
|
||||
def handle_message(data):
|
||||
try:
|
||||
current_app.logger.debug(f"SocketIO: Received message from tenant {data['tenantId']}: {data['message']}")
|
||||
verify_jwt_in_request()
|
||||
current_tenant = get_jwt_identity()
|
||||
print(f'Tenant {current_tenant["tenant_id"]} sent a message: {data}')
|
||||
# Store interaction in the database
|
||||
response = {
|
||||
'tenantId': data['tenantId'],
|
||||
'message': 'This is a bot response. Actual implementation still required.',
|
||||
'messageId': 'bot-message-id',
|
||||
'algorithm': 'alg1'
|
||||
}
|
||||
current_app.logger.debug(f"SocketIO: Bot response: {response}")
|
||||
emit('bot_response', response, broadcast=True)
|
||||
except Exception as e:
|
||||
current_app.logger.error(f'SocketIO: Message handling failed: {e}')
|
||||
disconnect()
|
||||
|
||||
66
eveai_chat/static/eve_ai_chat.html
Normal file
66
eveai_chat/static/eve_ai_chat.html
Normal file
@@ -0,0 +1,66 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Chat Client</title>
|
||||
<script src="https://cdn.socket.io/4.0.0/socket.io.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Chat Client</h1>
|
||||
<button onclick="registerClient()">Register Client</button>
|
||||
<div>
|
||||
<input type="text" id="message" placeholder="Enter your message">
|
||||
<button onclick="sendMessage()">Send Message</button>
|
||||
</div>
|
||||
<div id="messages"></div>
|
||||
|
||||
<script>
|
||||
let socket;
|
||||
|
||||
async function registerClient() {
|
||||
const tenantId = '1';
|
||||
const apiKey = 'EveAI-CHAT-8553-7987-2800-9115-6454';
|
||||
|
||||
const response = await fetch('http://127.0.0.1:5001/chat/register_client', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ tenant_id: tenantId, api_key: apiKey })
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
const token = data.token;
|
||||
|
||||
socket = io('http://127.0.0.1:5001/chat', {
|
||||
auth: {
|
||||
token: `Bearer ${token}`
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('connect', () => {
|
||||
console.log('Connected to server');
|
||||
});
|
||||
|
||||
socket.on('response', (msg) => {
|
||||
const messagesDiv = document.getElementById('messages');
|
||||
const messageElement = document.createElement('div');
|
||||
messageElement.innerText = `Response: ${msg.data}`;
|
||||
messagesDiv.appendChild(messageElement);
|
||||
});
|
||||
} else {
|
||||
console.error('Registration failed');
|
||||
}
|
||||
}
|
||||
|
||||
function sendMessage() {
|
||||
const message = document.getElementById('message').value;
|
||||
if (socket) {
|
||||
socket.emit('message', { content: message });
|
||||
} else {
|
||||
console.error('Socket not connected');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
20
eveai_chat/static/eveai_chat.html
Normal file
20
eveai_chat/static/eveai_chat.html
Normal file
@@ -0,0 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Chat Client</title>
|
||||
<link rel="stylesheet" href="css/eveai-chat-style.css">
|
||||
<script src="js/eveai-sdk.js" defer></script>
|
||||
<script src="js/eveai-chat-widget.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="chat-container"></div>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const eveAI = new EveAI('tenant-id', 'EVEAI-CHAT-xxxx-xxxx-xxxx-xxxx-xxxx');
|
||||
eveAI.initializeChat('chat-container');
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,34 +1,75 @@
|
||||
# from . import user_bp
|
||||
import uuid
|
||||
from datetime import datetime as dt, timezone as tz
|
||||
from flask import request, redirect, url_for, flash, render_template, Blueprint, session, current_app
|
||||
from flask import request, redirect, url_for, render_template, Blueprint, session, current_app, jsonify
|
||||
from flask_security import hash_password, roles_required, roles_accepted
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
from flask_jwt_extended import create_access_token, jwt_required, get_jwt_identity
|
||||
from flask_socketio import emit, join_room, leave_room
|
||||
import ast
|
||||
|
||||
|
||||
from common.models.user import User, Tenant
|
||||
from common.models.interaction import ChatSession, Interaction, InteractionEmbedding
|
||||
from common.models.document import Embedding
|
||||
from common.extensions import db, socketio
|
||||
from common.extensions import db, socketio, kms_client
|
||||
from common.utils.database import Database
|
||||
|
||||
chat_bp = Blueprint('chat_bp', __name__, url_prefix='/chat')
|
||||
|
||||
|
||||
@chat_bp.route('/', methods=['GET', 'POST'])
|
||||
def chat():
|
||||
return render_template('chat.html')
|
||||
@chat_bp.route('/register_client', methods=['POST'])
|
||||
def register_client():
|
||||
tenant_id = request.json.get('tenant_id')
|
||||
api_key = request.json.get('api_key')
|
||||
|
||||
# Validate tenant_id and api_key here (e.g., check against the database)
|
||||
if validate_tenant(tenant_id, api_key):
|
||||
access_token = create_access_token(identity={'tenant_id': tenant_id, 'api_key': api_key})
|
||||
return jsonify({'token': access_token}), 200
|
||||
else:
|
||||
return jsonify({'message': 'Invalid credentials'}), 401
|
||||
|
||||
|
||||
@chat.record_once
|
||||
def on_register(state):
|
||||
# TODO: write initialisation code when the blueprint is registered (only once)
|
||||
# socketio.init_app(state.app)
|
||||
pass
|
||||
@socketio.on('connect', namespace='/chat')
|
||||
@jwt_required()
|
||||
def handle_connect():
|
||||
current_tenant = get_jwt_identity()
|
||||
print(f'Tenant {current_tenant["tenant_id"]} connected')
|
||||
|
||||
|
||||
@socketio.on('message', namespace='/chat')
|
||||
def handle_message(message):
|
||||
# TODO: write message handling code to actually realise chat
|
||||
# print('Received message:', message)
|
||||
# socketio.emit('response', {'data': message}, namespace='/chat')
|
||||
pass
|
||||
@jwt_required()
|
||||
def handle_message(data):
|
||||
current_tenant = get_jwt_identity()
|
||||
print(f'Tenant {current_tenant["tenant_id"]} sent a message: {data}')
|
||||
# Store interaction in the database
|
||||
emit('response', {'data': 'Message received'}, broadcast=True)
|
||||
|
||||
|
||||
def validate_tenant(tenant_id, api_key):
|
||||
tenant = Tenant.query.get_or_404(tenant_id)
|
||||
encrypted_api_key = ast.literal_eval(tenant.encrypted_chat_api_key)
|
||||
|
||||
decrypted_api_key = kms_client.decrypt_api_key(encrypted_api_key)
|
||||
|
||||
return decrypted_api_key == api_key
|
||||
|
||||
|
||||
|
||||
# @chat_bp.route('/', methods=['GET', 'POST'])
|
||||
# def chat():
|
||||
# return render_template('chat.html')
|
||||
#
|
||||
#
|
||||
# @chat.record_once
|
||||
# def on_register(state):
|
||||
# # TODO: write initialisation code when the blueprint is registered (only once)
|
||||
# # socketio.init_app(state.app)
|
||||
# pass
|
||||
#
|
||||
#
|
||||
# @socketio.on('message', namespace='/chat')
|
||||
# def handle_message(message):
|
||||
# # TODO: write message handling code to actually realise chat
|
||||
# # print('Received message:', message)
|
||||
# # socketio.emit('response', {'data': message}, namespace='/chat')
|
||||
# pass
|
||||
|
||||
Reference in New Issue
Block a user