4 Commits

Author SHA1 Message Date
Joakim Persson d864d7529a Konfigurerar parser. Städat upp från bortkommenterad kod. 2024-07-30 16:42:59 +02:00
Joakim Persson 0b971dffc4 Ändrat på färger i chat-fönstret 2024-07-30 16:42:09 +02:00
Joakim Persson ecf45bd2e7 Importerar plugin till markdown-it för tabeller och annat. 2024-07-30 16:41:37 +02:00
Joakim Persson b88e573761 Lagt till chat-historik 2024-07-30 16:40:47 +02:00
4 changed files with 106 additions and 39 deletions
+88 -18
View File
@@ -1,7 +1,7 @@
# Import the necessary functions from ollama, Flask, requests, threading
from ollama import Client
from flask import Flask, request, jsonify, send_from_directory, render_template
from flask import Flask, request, jsonify, send_from_directory, render_template, session
from flask_cors import CORS, cross_origin # CORS stands for Cross-Origin Resource Sharing. This is necessary to allow the frontend to make requests to our backend.
import requests
import json
@@ -11,11 +11,8 @@ import utils
from utils import GlobalState
# Create a logger for this module
# logger = logging.getLogger(__name__) # This logger will be used to log messages from this module
# logger.debug("Logging level of backend logger has been configured")
global_state = GlobalState() # Import the singleton that holds global states (e.g., logger)
logger = global_state.getLogger(__name__) # Logger for this module, inherit properties of the root logger
# llm = global_state.get_llm()
# Find out the path to current directory according to the Python interpreter (venv)
@@ -25,6 +22,15 @@ logger.debug("Current working directory: %s", os.getcwd())
app = Flask(__name__)
app.config['STATIC_FOLDER'] = 'static' # Adjust if needed
# Set the secret key for session management
secret_key = os.urandom(24)
app.config['SECRET_KEY'] = secret_key # When do I need this. How is it retained between sessions?
# Optionally set other configuration options
app.config['SESSION_PERMANENT'] = False # Session will expire after each request
app.config['SESSION_TYPE'] = 'filesystem' # Store sessions on the filesystem
logger.debug("flask app template folder: %s", app.template_folder)
@app.route('/')
@@ -33,6 +39,7 @@ def index():
This route serves index.html to connecting clients
"""
session['chat_history'] = [] # The session object (actually, a dictonary) holds the chat session
logger.debug("Entering route '/'")
api_endpoint = os.environ['BE_API_ENDPOINT'] # Retrieve the environment variable
logger.debug("API endpoint: %s", api_endpoint)
@@ -44,6 +51,17 @@ def index():
return render_template('index.html', api_endpoint=api_endpoint, use_model = use_model, client_content=client_html)
@app.route('/profile')
def profile():
# Retrieve data from the session
user_id = session.get('user_id')
if user_id:
return f'User ID: {user_id}'
else:
return 'No user ID found'
@app.route('/<path:filename>')
def serve_static(filename):
return send_from_directory(app.config['STATIC_FOLDER'], filename)
@@ -62,6 +80,50 @@ CORS(app, resources={
}
})
# @app.route('/api/memfree_chat', methods=['POST'])
# def chat(url_server = "http://localhost:11434/api/generate", model = "phi3:mini"):
# """
# This function handles the chat. The frontend client (web browser) calls the
# backend server through this endpoint (/api/chat) that manage queries
# to the LLM (Large Language Model) server and it also manages the response
# from the LLM server.
# """
# # Get the message from the JSON in the request body
# data = request.get_json()
# message = data.get('query')
# url_server = data.get('url_server', url_server) # Use provided URL or default
# model = data.get('model', model) # Use provided model or default
# logger.debug("data = %s\nmessage = %s", str(data), str(message))
# try:
# url = url_server
# model_to_use = model
# data = {
# "model": model_to_use,
# 'prompt': message,
# "stream": False
# }
# headers = {
# "Content-Type": "application/json",
# }
# # With API key
# # headers = {
# # "Content-Type": "application/json",
# # "Authorization": "Bearer YOUR_API_KEY" # Replace with your API key
# # }
# response = requests.post(url,
# headers=headers,
# data=json.dumps(data))
# response.raise_for_status() # Raise an exception for bad status codes
# return response.json()
# except requests.exceptions.RequestException as e:
# logger.error("Request Exception: %s", str(e))
# return jsonify({'error': 'Failed to process request'}), 500
# except json.JSONDecodeError as e:
# logger.error("JSON Decode Error: %s", str(e)) # Corresponds to print(f"JSON Decode Error: {e}")
# return jsonify({'error': 'Invalid JSON response from server'}), 500
@app.route('/api/chat', methods=['POST'])
def chat(url_server = "http://localhost:11434/api/generate", model = "phi3:mini"):
"""
@@ -75,28 +137,35 @@ def chat(url_server = "http://localhost:11434/api/generate", model = "phi3:mini"
message = data.get('query')
url_server = data.get('url_server', url_server) # Use provided URL or default
model = data.get('model', model) # Use provided model or default
logger.debug("data = %s\nmessage = %s", str(data), str(message))
# Get chat history from session storage (e.g., a dictionary)
chat_history = session.get('chat_history', [])
# Add the new message to the chat history
chat_history.append({'role': 'user', 'message': message})
logger.debug(f"Chat History: {chat_history}")
# Update the session with the new chat history
session['chat_history'] = chat_history
# Create the data dictionary with chat history
data_to_send = {
"model": model,
'prompt': '\n'.join([f"{item['role']}: {item['message']}" for item in chat_history]),
"stream": False
}
try:
url = url_server
model_to_use = model
data = {
"model": model_to_use,
'prompt': message,
"stream": False
}
headers = {
"Content-Type": "application/json",
}
# With API key
# headers = {
# "Content-Type": "application/json",
# "Authorization": "Bearer YOUR_API_KEY" # Replace with your API key
# }
response = requests.post(url,
headers=headers,
data=json.dumps(data))
data=json.dumps(data_to_send))
response.raise_for_status() # Raise an exception for bad status codes
return response.json()
except requests.exceptions.RequestException as e:
logger.error("Request Exception: %s", str(e))
@@ -106,6 +175,7 @@ def chat(url_server = "http://localhost:11434/api/generate", model = "phi3:mini"
return jsonify({'error': 'Invalid JSON response from server'}), 500
@app.route('/smartassist', methods=["POST"])
def smartassist():
# Extract the query from the incoming JSON data
+2
View File
@@ -23,6 +23,8 @@
<!-- Marked for markdown rendering -->
<!-- <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script> -->
<script src="https://cdn.jsdelivr.net/npm/markdown-it@14.1.0/dist/markdown-it.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/markdown-it@14/dist/markdown-it.min.js"></script>
<!-- Include MathJax library to render mathematical notation -->
+6 -3
View File
@@ -16,13 +16,16 @@ h1 {
#chatbox {
width: calc(50% - 60px); /* Adjust width for input and button */
/* max-width: 500px; */
height: 80px;
background-color: #e1dcccb8;
height: 200px;
/* background-color: #fff8bc; */
background-color: #ffffff;
border-radius: 10px;
padding: 20px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
overflow: auto; /* Allow horizontal and vertical scrolling of the chatbox */
resize: both; /* Allow resizing vertically */
border: 1px solid #ccc; /* Add a thin grey border around chatbox */
margin-bottom: 20px; /* Add some space between chatbox and userInput */
}
.message {
@@ -38,7 +41,7 @@ h1 {
.ai-response {
/* background-color: #f0f8ff; */
background-color: #e1dcccb8;
background-color: #f5ecd0;
padding: 10px 15px;
border-radius: 10px;
text-align: left; /* Align AI responses to the left */
+10 -18
View File
@@ -3,7 +3,13 @@
const chatbox = document.getElementById('chatbox');
const userInput = document.getElementById('userInput');
const parser = window.markdownit();
const parser = window.markdownit({
linkify: true,
strikethrough: true,
});
parser.enable(['table']);
// const html = markdownIt.use({
// // You can customize the parser options here, e.g., enable/disable certain features
@@ -42,18 +48,6 @@ function sendMessage() {
}
}
function customRenderer(markdownText) {
// Use a regex pattern to match LaTeX code (e.g. $$...$$ or $...$)
const latexPattern = /(?:\$\$|\\\[)(.*?)?(?:\$\$|\\\])/g;
// Replace each occurrence of LaTeX code with an HTML span element
const html = markdownText.replace(latexPattern, (match, p1) => {
return `<span class="latex">${p1}</span>`;
});
// Return the rendered HTML
return html;
}
// Define a function to render a message in the chatbox with a specific class name
@@ -67,20 +61,18 @@ function renderMessage(text, className) {
// // Set the text content of the element to the message text
// messageElement.textContent = text;
// Parse Markdown text into HTML and set it as the innerHTML of the element
// messageElement.innerHTML = marked.parse(text);
// Use the markdown-it parser
const html = parser.render(text);
messageElement.innerHTML = html;
// Typeset math
// Append the message element to the chatbox immediately
chatbox.appendChild(messageElement);
// chatbox.appendChild(messageElement);
// Typeset math in the message element
MathJax.typesetPromise([messageElement]).then(() => {
// No need to append anything here, it's already appended above
chatbox.appendChild(messageElement);
});
}