Setting up the chat client functionality using SocketIO - Start

This commit is contained in:
Josako
2024-05-15 14:37:21 +02:00
parent 6f13d72261
commit ea23e8d327
10 changed files with 165 additions and 2 deletions

View File

@@ -5,6 +5,7 @@ from flask_security import Security
from flask_mailman import Mail from flask_mailman import Mail
from flask_login import LoginManager from flask_login import LoginManager
from flask_cors import CORS from flask_cors import CORS
from flask_socketio import SocketIO
# Create extensions # Create extensions
@@ -15,3 +16,4 @@ security = Security()
mail = Mail() mail = Mail()
login_manager = LoginManager() login_manager = LoginManager()
cors = CORS() cors = CORS()
socketio = SocketIO()

View File

@@ -0,0 +1,37 @@
from ..extensions import db
from .user import User, Tenant
class ChatSession(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('public.user.id'), nullable=True)
session_start = db.Column(db.DateTime, nullable=False)
session_end = db.Column(db.DateTime, nullable=True)
# Relations
chat_interactions = db.relationship('Interaction', backref='chat_session', lazy=True)
user = db.relationship('User', backref='chat_sessions', lazy=True)
def __repr__(self):
return f"<ChatSession {self.id} by {self.user_id}>"
class Interaction(db.Model):
id = db.Column(db.Integer, primary_key=True)
chat_session_id = db.Column(db.Integer, db.ForeignKey('public.chat_session.id'), nullable=False)
question = db.Column(db.Text, nullable=False)
answer = db.Column(db.Text, nullable=True)
language = db.Column(db.String(2), nullable=False)
appreciation = db.Column(db.Integer, nullable=True, default=100)
# Timing information
question_at = db.Column(db.DateTime, nullable=False)
answer_at = db.Column(db.DateTime, nullable=True)
def __repr__(self):
return f"<Interaction {self.id}>"
class InteractionEmbedding(db.Model):
interaction_id = db.Column(db.Integer, db.ForeignKey('interaction.id', ondelete='CASCADE'), primary_key=True)
embedding_id = db.Column(db.Integer, db.ForeignKey('embedding.id', ondelete='CASCADE'), primary_key=True)

View File

@@ -63,6 +63,9 @@ class Config(object):
Text is delimited between triple backquotes. Text is delimited between triple backquotes.
```{text}```""" ```{text}```"""
# SocketIO settings
SOCKETIO_ASYNC_MODE = 'gevent'
class DevConfig(Config): class DevConfig(Config):
DEVELOPMENT = True DEVELOPMENT = True
@@ -92,6 +95,17 @@ class DevConfig(Config):
UNSTRUCTURED_BASE_URL = 'https://flowitbv-16c4us0m.api.unstructuredapp.io' UNSTRUCTURED_BASE_URL = 'https://flowitbv-16c4us0m.api.unstructuredapp.io'
UNSTRUCTURED_FULL_URL = 'https://flowitbv-16c4us0m.api.unstructuredapp.io/general/v0/general' UNSTRUCTURED_FULL_URL = 'https://flowitbv-16c4us0m.api.unstructuredapp.io/general/v0/general'
# SocketIO settings
SOCKETIO_MESSAGE_QUEUE = 'redis://localhost:6379/1'
SOCKETIO_CORS_ALLOWED_ORIGINS = '*'
SOCKETIO_LOGGER = True
SOCKETIO_ENGINEIO_LOGGER = True
# Google Cloud settings
GC_PROJECT_NAME = 'EveAI'
GC_KEY_RING = 'eveai-chat'
GC_CRYPTO_KEY = 'envelope-encryption-key'
class ProdConfig(Config): class ProdConfig(Config):
DEVELOPMENT = False DEVELOPMENT = False

View File

@@ -18,6 +18,14 @@ LOGGING = {
'backupCount': 10, 'backupCount': 10,
'formatter': 'standard', 'formatter': 'standard',
}, },
'file_chat': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler',
'filename': 'logs/eveai_chat.log',
'maxBytes': 1024*1024*5, # 5MB
'backupCount': 10,
'formatter': 'standard',
},
'console': { 'console': {
'class': 'logging.StreamHandler', 'class': 'logging.StreamHandler',
'level': 'DEBUG', 'level': 'DEBUG',
@@ -40,6 +48,11 @@ LOGGING = {
'level': 'DEBUG', 'level': 'DEBUG',
'propagate': False 'propagate': False
}, },
'eveai_chat': { # logger for the eveai_chat
'handlers': ['file_chat', 'console'],
'level': 'DEBUG',
'propagate': False
},
'': { # root logger '': { # root logger
'handlers': ['console'], 'handlers': ['console'],
'level': 'WARNING', # Set higher level for root to minimize noise 'level': 'WARNING', # Set higher level for root to minimize noise

View File

@@ -7,7 +7,7 @@ from werkzeug.middleware.proxy_fix import ProxyFix
import logging.config import logging.config
from common.extensions import db, migrate, bootstrap, security, mail, login_manager, cors from common.extensions import db, migrate, bootstrap, security, mail, login_manager, cors
from common.models.user import User, Role from common.models.user import User, Role, Tenant, TenantDomain
from config.logging_config import LOGGING from config.logging_config import LOGGING
from common.utils.security import set_tenant_session_data from common.utils.security import set_tenant_session_data
from .errors import register_error_handlers from .errors import register_error_handlers

33
eveai_chat/__init__.py Normal file
View File

@@ -0,0 +1,33 @@
import logging
import logging.config
from flask import Flask
from flask_socketio import emit
from common.extensions import db, socketio
from config.logging_config import LOGGING
def create_app(config_file=None):
app = Flask(__name__)
if config_file is None:
app.config.from_object('config.config.DevConfig')
else:
app.config.from_object(config_file)
logging.config.dictConfig(LOGGING)
register_extensions(app)
return app
def register_extensions(app):
db.init_app(app)
socketio.init_app(app,
message_queue=app.config.get('SOCKETIO_MESSAGE_QUEUE'),
cors_allowed_origins=app.config.get('SOCKETIO_CORS_ALLOWED_ORIGINS'),
async_mode=app.config.get('SOCKETIO_ASYNC_MODE'),
logger=app.config.get('SOCKETIO_LOGGER'),
engineio_logger=app.config.get('SOCKETIO_ENGINEIO_LOGGER'),
)

View File

@@ -0,0 +1,34 @@
# 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_security import hash_password, roles_required, roles_accepted
from sqlalchemy.exc import SQLAlchemyError
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.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.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

View File

@@ -10,3 +10,4 @@ kombu~=5.3.7
langchain~=0.1.17 langchain~=0.1.17
requests~=2.31.0 requests~=2.31.0
beautifulsoup4~=4.12.3 beautifulsoup4~=4.12.3
google~=3.0.0

14
scripts/run_eveai_chat.py Normal file
View File

@@ -0,0 +1,14 @@
from eveai_chat import create_app
from gevent.pywsgi import WSGIServer
from geventwebsocket.handler import WebSocketHandler
app = create_app()
if __name__ == '__main__':
print("Server starting on port 5001")
http_server = WSGIServer(('0.0.0.0', 5001), app, handler_class=WebSocketHandler)
http_server.serve_forever() # Continuously listens for incoming requests

15
scripts/start_eveai_chat.sh Executable file
View File

@@ -0,0 +1,15 @@
#!/usr/bin/env bash
cd "/Volumes/OWC4M2_1/Dropbox/Josako's Dev/Josako/EveAI/Development/eveAI/" || exit 1
source "/Volumes/OWC4M2_1/Dropbox/Josako's Dev/Josako/EveAI/Development/eveAI/.venv/bin/activate"
export PYTHONPATH="$PYTHONPATH:/Volumes/OWC4M2_1/Dropbox/Josako's Dev/Josako/EveAI/Development/eveAI/"
# Set flask environment variables
export FLASK_ENV=development # Use 'production' as appropriate
export FLASK_DEBUG=1 # Use 0 for production
# Start Flask app
python scripts/run_eveai_chat.py
deactivate