Started to work on interaction views. However, need a quick check in because of a python upgrade systemwide that breaks code.
This commit is contained in:
@@ -13,8 +13,7 @@ from config.logging_config import LOGGING
|
||||
from common.utils.security import set_tenant_session_data
|
||||
from .errors import register_error_handlers
|
||||
from common.utils.celery_utils import make_celery, init_celery
|
||||
from common.utils.debug_utils import log_request_middleware
|
||||
from common.utils.nginx_utils import prefixed_url_for
|
||||
from common.utils.template_filters import register_filters
|
||||
|
||||
|
||||
def create_app(config_file=None):
|
||||
@@ -85,6 +84,9 @@ def create_app(config_file=None):
|
||||
# Register API
|
||||
register_api(app)
|
||||
|
||||
# Register template filters
|
||||
register_filters(app)
|
||||
|
||||
app.logger.info("EveAI App Server Started Successfully")
|
||||
app.logger.info("-------------------------------------------------------------------------------------------------")
|
||||
return app
|
||||
@@ -112,6 +114,8 @@ def register_blueprints(app):
|
||||
app.register_blueprint(document_bp)
|
||||
from .views.security_views import security_bp
|
||||
app.register_blueprint(security_bp)
|
||||
from .views.interaction_views import interaction_bp
|
||||
app.register_blueprint(interaction_bp)
|
||||
|
||||
|
||||
def register_api(app):
|
||||
|
||||
23
eveai_app/templates/interaction/chat_sessions.html
Normal file
23
eveai_app/templates/interaction/chat_sessions.html
Normal file
@@ -0,0 +1,23 @@
|
||||
{% extends 'base.html' %}
|
||||
{% from 'macros.html' import render_selectable_table, render_pagination %}
|
||||
|
||||
{% block title %}Chat Sessions{% endblock %}
|
||||
|
||||
{% block content_title %}Chat Sessions{% endblock %}
|
||||
{% block content_description %}View Chat Sessions for Tenant{% endblock %}
|
||||
{% block content_class %}<div class="col-xl-12 col-lg-5 col-md-7 mx-auto"></div>{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<form method="POST" action="{{ url_for('interaction_bp.handle_chat_session_selection') }}">
|
||||
{{ render_selectable_table(headers=["ID", "Session ID", "Session Start", "Session End"], rows=rows, selectable=True, id="documentsTable") }}
|
||||
<div class="form-group mt-3">
|
||||
<button type="submit" name="action" value="view_chat_session" class="btn btn-primary">View Chat Session</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block content_footer %}
|
||||
{{ render_pagination(pagination, 'interaction_bp.chat_sessions') }}
|
||||
{% endblock %}
|
||||
127
eveai_app/templates/interaction/view_chat_session.html
Normal file
127
eveai_app/templates/interaction/view_chat_session.html
Normal file
@@ -0,0 +1,127 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container mt-5">
|
||||
<h2>Chat Session Details</h2>
|
||||
<!-- Session Information -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5>Session Information</h5>
|
||||
<!-- Timezone Toggle Buttons -->
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-primary" id="toggle-interaction-timezone">Interaction Timezone</button>
|
||||
<button type="button" class="btn btn-secondary" id="toggle-admin-timezone">Admin Timezone</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<dl class="row">
|
||||
<dt class="col-sm-3">Session ID:</dt>
|
||||
<dd class="col-sm-9">{{ chat_session.session_id }}</dd>
|
||||
|
||||
<dt class="col-sm-3">Session Start:</dt>
|
||||
<dd class="col-sm-9">
|
||||
<span class="timezone interaction-timezone">{{ chat_session.session_start | to_local_time(chat_session.timezone) }}</span>
|
||||
<span class="timezone admin-timezone d-none">{{ chat_session.session_start | to_local_time(session['admin_user_timezone']) }}</span>
|
||||
</dd>
|
||||
|
||||
<dt class="col-sm-3">Session End:</dt>
|
||||
<dd class="col-sm-9">
|
||||
{% if chat_session.session_end %}
|
||||
<span class="timezone interaction-timezone">{{ chat_session.session_end | to_local_time(chat_session.timezone) }}</span>
|
||||
<span class="timezone admin-timezone d-none">{{ chat_session.session_end | to_local_time(session['admin_user_timezone']) }}</span>
|
||||
{% else %}
|
||||
Ongoing
|
||||
{% endif %}
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Interactions List -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5>Interactions</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% for interaction in interactions %}
|
||||
<div class="interaction mb-3">
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between">
|
||||
<span>Question:</span>
|
||||
<span class="text-muted">
|
||||
<span class="timezone interaction-timezone">{{ interaction.question_at | to_local_time(interaction.timezone) }}</span>
|
||||
<span class="timezone admin-timezone d-none">{{ interaction.question_at | to_local_time(session['admin_user_timezone']) }}</span>
|
||||
-
|
||||
<span class="timezone interaction-timezone">{{ interaction.answer_at | to_local_time(interaction.timezone) }}</span>
|
||||
<span class="timezone admin-timezone d-none">{{ interaction.answer_at | to_local_time(session['admin_user_timezone']) }}</span>
|
||||
({{ interaction.question_at | time_difference(interaction.answer_at) }})
|
||||
</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p><strong>Question:</strong> {{ interaction.question }}</p>
|
||||
<p><strong>Answer:</strong> {{ interaction.answer }}</p>
|
||||
<p>
|
||||
<strong>Algorithm Used:</strong>
|
||||
<i class="material-icons {{ 'fingerprint-rag-' ~ interaction.algorithm_used.lower() }}">
|
||||
fingerprint
|
||||
</i> {{ interaction.algorithm_used }}
|
||||
</p>
|
||||
<p>
|
||||
<strong>Appreciation:</strong>
|
||||
<i class="material-icons thumb-icon {{ 'thumb_up' if interaction.appreciation == 1 else 'thumb_down' }}">
|
||||
{{ 'thumb_up' if interaction.appreciation == 1 else 'thumb_down' }}
|
||||
</i>
|
||||
</p>
|
||||
<p><strong>Embeddings:</strong>
|
||||
{% if interaction.embeddings %}
|
||||
{% for embedding in interaction.embeddings %}
|
||||
<a href="{{ url_for('interaction_bp.view_embedding', embedding_id=embedding.embedding_id) }}" class="badge badge-info">
|
||||
{{ embedding.embedding_id }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
None
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Elements to toggle
|
||||
const interactionTimes = document.querySelectorAll('.interaction-timezone');
|
||||
const adminTimes = document.querySelectorAll('.admin-timezone');
|
||||
|
||||
// Buttons
|
||||
const interactionButton = document.getElementById('toggle-interaction-timezone');
|
||||
const adminButton = document.getElementById('toggle-admin-timezone');
|
||||
|
||||
// Toggle to Interaction Timezone
|
||||
interactionButton.addEventListener('click', function() {
|
||||
interactionTimes.forEach(el => el.classList.remove('d-none'));
|
||||
adminTimes.forEach(el => el.classList.add('d-none'));
|
||||
interactionButton.classList.add('btn-primary');
|
||||
interactionButton.classList.remove('btn-secondary');
|
||||
adminButton.classList.add('btn-secondary');
|
||||
adminButton.classList.remove('btn-primary');
|
||||
});
|
||||
|
||||
// Toggle to Admin Timezone
|
||||
adminButton.addEventListener('click', function() {
|
||||
interactionTimes.forEach(el => el.classList.add('d-none'));
|
||||
adminTimes.forEach(el => el.classList.remove('d-none'));
|
||||
interactionButton.classList.add('btn-secondary');
|
||||
interactionButton.classList.remove('btn-primary');
|
||||
adminButton.classList.add('btn-primary');
|
||||
adminButton.classList.remove('btn-secondary');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -79,7 +79,7 @@
|
||||
{'name': 'User Registration', 'url': '/user/user', 'roles': ['Super User', 'Tenant Admin']},
|
||||
]) }}
|
||||
{% endif %}
|
||||
{% if current_user.is_authenticated %}
|
||||
{% if current_user.is_authenticated %}
|
||||
{{ dropdown('Document Mgmt', 'contacts', [
|
||||
{'name': 'Add Document', 'url': '/document/add_document', 'roles': ['Super User', 'Tenant Admin']},
|
||||
{'name': 'Add URL', 'url': '/document/add_url', 'roles': ['Super User', 'Tenant Admin']},
|
||||
@@ -87,6 +87,11 @@
|
||||
{'name': 'Library Operations', 'url': '/document/library_operations', 'roles': ['Super User', 'Tenant Admin']},
|
||||
]) }}
|
||||
{% endif %}
|
||||
{% if current_user.is_authenticated %}
|
||||
{{ dropdown('Interactions', 'contacts', [
|
||||
{'name': 'Chat Sessions', 'url': '/interaction/chat_sessions', 'roles': ['Super User', 'Tenant Admin']},
|
||||
]) }}
|
||||
{% endif %}
|
||||
{% if current_user.is_authenticated %}
|
||||
{{ dropdown(current_user.user_name, 'contacts', [
|
||||
{'name': 'Session Defaults', 'url': '/session_defaults', 'roles': ['Super User', 'Tenant Admin']},
|
||||
|
||||
@@ -11,4 +11,4 @@
|
||||
<script src="{{url_for('static', filename='assets/js/plugins/parallax.min.js')}}"></script>
|
||||
<script src="{{url_for('static', filename='assets/js/plugins/nouislider.min.js')}}"></script>
|
||||
<script src="{{url_for('static', filename='assets/js/plugins/anime.min.js')}}"></script>
|
||||
<script src="{{url_for('static', filename='assets/js/material-kit-pro.min.js')}}?v=3.0.4 type="text/javascript"></script>
|
||||
<script src="{{url_for('static', filename='assets/js/material-kit-pro.min.js')}}?v=3.0.4 type="text/javascript"></script>
|
||||
|
||||
@@ -170,4 +170,26 @@
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
// JavaScript to detect user's timezone
|
||||
document.addEventListener('DOMContentLoaded', (event) => {
|
||||
// Detect timezone
|
||||
const userTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
|
||||
// Send timezone to the server via a POST request
|
||||
fetch('/set_user_timezone', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ timezone: userTimezone })
|
||||
}).then(response => {
|
||||
if (response.ok) {
|
||||
console.log('Timezone sent to server successfully');
|
||||
} else {
|
||||
console.error('Failed to send timezone to server');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import request, redirect, url_for, flash, render_template, Blueprint, session, current_app
|
||||
from flask import request, render_template, Blueprint, session, current_app, jsonify
|
||||
from flask_security import roles_required, roles_accepted
|
||||
|
||||
from .basic_forms import SessionDefaultsForm
|
||||
@@ -41,3 +41,16 @@ def session_defaults():
|
||||
session['default_language'] = form.default_language.data
|
||||
|
||||
return render_template('basic/session_defaults.html', form=form)
|
||||
|
||||
|
||||
@basic_bp.route('/set_user_timezone', methods=['POST'])
|
||||
def set_user_timezone():
|
||||
data = request.get_json()
|
||||
timezone = data.get('timezone')
|
||||
|
||||
if timezone:
|
||||
session['admin_user_timezone'] = timezone
|
||||
return jsonify({'status': 'success', 'timezone': timezone}), 200
|
||||
else:
|
||||
return jsonify({'status': 'error', 'message': 'Timezone not provided'}), 400
|
||||
|
||||
|
||||
100
eveai_app/views/interaction_views.py
Normal file
100
eveai_app/views/interaction_views.py
Normal file
@@ -0,0 +1,100 @@
|
||||
import ast
|
||||
import os
|
||||
from datetime import datetime as dt, timezone as tz
|
||||
|
||||
import chardet
|
||||
from flask import request, redirect, flash, render_template, Blueprint, session, current_app
|
||||
from flask_security import roles_accepted, current_user
|
||||
from sqlalchemy import desc
|
||||
from sqlalchemy.orm import joinedload
|
||||
from werkzeug.datastructures import FileStorage
|
||||
from werkzeug.utils import secure_filename
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
import requests
|
||||
from requests.exceptions import SSLError
|
||||
from urllib.parse import urlparse
|
||||
import io
|
||||
|
||||
from common.models.interaction import ChatSession, Interaction
|
||||
from common.extensions import db
|
||||
from .document_forms import AddDocumentForm, AddURLForm, EditDocumentForm, EditDocumentVersionForm
|
||||
from common.utils.middleware import mw_before_request
|
||||
from common.utils.celery_utils import current_celery
|
||||
from common.utils.nginx_utils import prefixed_url_for
|
||||
from common.utils.view_assistants import form_validation_failed, prepare_table_for_macro
|
||||
|
||||
interaction_bp = Blueprint('interaction_bp', __name__, url_prefix='/interaction')
|
||||
|
||||
|
||||
@interaction_bp.before_request
|
||||
def log_before_request():
|
||||
current_app.logger.debug(f"Before request (interaction_bp): {request.method} {request.url}")
|
||||
|
||||
|
||||
@interaction_bp.after_request
|
||||
def log_after_request(response):
|
||||
current_app.logger.debug(
|
||||
f"After request (interaction_bp): {request.method} {request.url} - Status: {response.status}")
|
||||
return response
|
||||
|
||||
|
||||
@interaction_bp.before_request
|
||||
def before_request():
|
||||
try:
|
||||
mw_before_request()
|
||||
except Exception as e:
|
||||
current_app.logger.error(f'Error switching schema in Interaction Blueprint: {e}')
|
||||
for role in current_user.roles:
|
||||
current_app.logger.debug(f'User {current_user.email} has role {role.name}')
|
||||
raise
|
||||
|
||||
|
||||
@interaction_bp.route('/chat_sessions', methods=['GET', 'POST'])
|
||||
def chat_sessions():
|
||||
page = request.args.get('page', 1, type=int)
|
||||
per_page = request.args.get('per_page', 10, type=int)
|
||||
|
||||
query = ChatSession.query.order_by(desc(ChatSession.session_start))
|
||||
|
||||
pagination = query.paginate(page=page, per_page=per_page, error_out=False)
|
||||
docs = pagination.items
|
||||
|
||||
rows = prepare_table_for_macro(docs, [('id', ''), ('session_id', ''), ('session_start', ''), ('session_end', '')])
|
||||
|
||||
return render_template('interaction/chat_sessions.html', rows=rows, pagination=pagination)
|
||||
|
||||
|
||||
@interaction_bp.route('/handle_chat_session_selection', methods=['POST'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
def handle_chat_session_selection():
|
||||
chat_session_identification = request.form['selected_row']
|
||||
cs_id = ast.literal_eval(chat_session_identification).get('value')
|
||||
|
||||
action = request.form['action']
|
||||
|
||||
match action:
|
||||
case 'view_chat_session':
|
||||
return redirect(prefixed_url_for('interaction_bp.view_chat_session', chat_session_id=cs_id))
|
||||
|
||||
# Add more conditions for other actions
|
||||
return redirect(prefixed_url_for('interaction_bp.chat_sessions'))
|
||||
|
||||
|
||||
@interaction_bp.route('/view_chat_session/<chat_session_id>', methods=['GET'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
def view_chat_session(chat_session_id):
|
||||
chat_session = ChatSession.query.get_or_404(chat_session_id)
|
||||
show_chat_session(chat_session)
|
||||
|
||||
|
||||
@interaction_bp.route('/view_chat_session_by_session_id/<session_id>', methods=['GET'])
|
||||
@roles_accepted('Super User', 'Tenant Admin')
|
||||
def view_chat_session_by_session_id(session_id):
|
||||
chat_session = ChatSession.query.filter_by(session_id=session_id).first_or_404()
|
||||
show_chat_session(chat_session)
|
||||
|
||||
|
||||
def show_chat_session(chat_session):
|
||||
interactions = Interaction.query.filter_by(chat_session_id=chat_session.id).all()
|
||||
return render_template('interaction/view_chat_session.html', chat_session=chat_session, interactions=interactions)
|
||||
|
||||
@@ -60,7 +60,8 @@ class TenantForm(FlaskForm):
|
||||
self.embedding_model.choices = [(model, model) for model in current_app.config['SUPPORTED_EMBEDDINGS']]
|
||||
self.llm_model.choices = [(model, model) for model in current_app.config['SUPPORTED_LLMS']]
|
||||
# Initialize fallback algorithms
|
||||
self.fallback_algorithms.choices = [(algorithm, algorithm.lower()) for algorithm in current_app.config['FALLBACK_ALGORITHMS']]
|
||||
self.fallback_algorithms.choices = \
|
||||
[(algorithm, algorithm.lower()) for algorithm in current_app.config['FALLBACK_ALGORITHMS']]
|
||||
|
||||
|
||||
class BaseUserForm(FlaskForm):
|
||||
|
||||
Reference in New Issue
Block a user