Compare commits
54 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9203641e6a | |||
| 14eaf57335 | |||
| 9ae5840e8b | |||
| 659b0937d3 | |||
| 7bc8a129c6 | |||
| a12c11c058 | |||
| 5771e52c49 | |||
| d038f1ac24 | |||
| 86374c91fe | |||
| 0adbb9c222 | |||
| c3d7f3ba4f | |||
| d864d7529a | |||
| 0b971dffc4 | |||
| ecf45bd2e7 | |||
| b88e573761 | |||
| ecf2ddf46e | |||
| b4a35bafef | |||
| de3e59afea | |||
| 9f5bdddb8f | |||
| 854ebbdd94 | |||
| 7d954e7380 | |||
| d843a2b74c | |||
| ab94c06e75 | |||
| 1757542077 | |||
| 941b426574 | |||
| 534874e810 | |||
| 0cccd02050 | |||
| e69a131875 | |||
| d797440288 | |||
| 1b5624018c | |||
| 807a766a63 | |||
| 5245e53954 | |||
| d1b0554748 | |||
| f8c3bcd156 | |||
| 25e5c6acea | |||
| 20fa94f533 | |||
| ccc8e73f48 | |||
| f179e8e19b | |||
| bfe8479016 | |||
| b261437952 | |||
| dac233ba9c | |||
| 7c9d20896e | |||
| ce5532e9a6 | |||
| feb7e61fd8 | |||
| 9a9b1388ce | |||
| 61974859bd | |||
| bf165d8181 | |||
| fbcac82bbf | |||
| 60ad3d109b | |||
| 8ddb920e99 | |||
| adbf14c43c | |||
| a2144e0480 | |||
| d0935f771a | |||
| 9bb9b76227 |
@@ -1,24 +1,27 @@
|
|||||||
# Frontend Configuration
|
# Frontend Configuration
|
||||||
frontend:
|
frontend:
|
||||||
url: "http://localhost:8000"
|
url: "http://localhost:5004"
|
||||||
|
|
||||||
# Backend Configuration
|
# Backend Configuration
|
||||||
backend:
|
backend:
|
||||||
url: "http://localhost:5005"
|
url: "http://localhost:5004"
|
||||||
api: "/api/chat"
|
api: "/api/chat"
|
||||||
|
|
||||||
# Ollama Server Configuration
|
# Ollama Server Configuration
|
||||||
ollama:
|
ollama:
|
||||||
url: "http://localhost:11434"
|
url: "http://localhost:11434"
|
||||||
api_key: "${OLLAMA_API_KEY}" # Refer to environment variable
|
api_key: "${OLLAMA_API_KEY}" # Refer to environment variable
|
||||||
# model: "phi3:mini" # Select a model supported by the Ollama server
|
model: "phi3:mini" # Select a model supported by the Ollama server
|
||||||
# model: "llama3:70b" # Select a model supported by the Ollama server
|
# model: "llama3:70b" # Select a model supported by the Ollama server
|
||||||
# model: "llama3:latest" # Select a model supported by the Ollama server
|
# model: "llama3:latest" # Select a model supported by the Ollama server
|
||||||
model: "mannix/llama3-8b-ablitered-v3:latest" # Select a model supported by the Ollama server
|
# model: "mannix/llama3-8b-ablitered-v3:latest" # Select a model supported by the Ollama server
|
||||||
|
# model: "mistral-nemo:latest" # Select a model supported by the Ollama server
|
||||||
|
# model: "gemma2:27b"
|
||||||
|
|
||||||
# Logging – comment out the whole section for default level which is INFO
|
# Logging – comment out the whole section for default level which is INFO
|
||||||
logging:
|
logging:
|
||||||
level: DEBUG # Set log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
|
level: DEBUG # Set log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
|
||||||
|
# level: INFO # Set log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
|
||||||
|
|
||||||
# Additional Configuration Options (Optional – ignored for now)
|
# Additional Configuration Options (Optional – ignored for now)
|
||||||
|
|
||||||
|
|||||||
+100
-26
@@ -1,25 +1,93 @@
|
|||||||
|
|
||||||
# Import the necessary functions from ollama, Flask, requests, threading
|
# Import the necessary functions from ollama, Flask, requests, threading
|
||||||
from ollama import Client
|
from ollama import Client
|
||||||
from flask import Flask, request, jsonify
|
from flask import Flask, request, jsonify, send_from_directory, render_template, session, make_response
|
||||||
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.
|
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 requests
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
from utils import set_local_logger
|
import os
|
||||||
|
import utils
|
||||||
|
from utils import GlobalState
|
||||||
|
|
||||||
logger = logging.getLogger(__name__) # Separate logger for this module
|
# Create a logger for this module
|
||||||
set_local_logger(logger) # Set log level for logger
|
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
|
||||||
|
|
||||||
|
|
||||||
|
# Find out the path to current directory according to the Python interpreter (venv)
|
||||||
|
logger.debug("Current working directory: %s", os.getcwd())
|
||||||
|
|
||||||
# Initialize a Flask application
|
# Initialize a Flask application
|
||||||
app = Flask(__name__)
|
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('/')
|
||||||
|
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
|
||||||
|
api_endpoint = global_state.get_backend_api_ep() # Retrieve the environment variable
|
||||||
|
logger.debug("Backend API endpoint: %s", api_endpoint)
|
||||||
|
use_model = global_state.get_llm()
|
||||||
|
with open('smartassist/src/html/client.html', 'r') as f:
|
||||||
|
client_html = f.read()
|
||||||
|
logger.debug("Client HTML (first few characters): %s", client_html[:50]) # Print to see if it's loading
|
||||||
|
# logger.debug("Client HTML (all characters): %s", client_html) # Print to see if it's loading
|
||||||
|
|
||||||
|
return render_template('index.html', api_endpoint=api_endpoint, use_model = use_model, client_content=client_html)
|
||||||
|
|
||||||
|
@app.route('/set_session')
|
||||||
|
def set_session():
|
||||||
|
resp = make_response()
|
||||||
|
resp.set_cookie('session', 'some-value', samesite='None', secure=True) # Add SameSite attribute here
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@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)
|
||||||
|
|
||||||
|
|
||||||
|
# CORS(app, resources={
|
||||||
|
# r"/api/chat": {
|
||||||
|
# "origins": "*",
|
||||||
|
# "headers": ["Origin", "Content-Type", "Authorization"],
|
||||||
|
# }
|
||||||
|
# })
|
||||||
|
|
||||||
CORS(app, resources={
|
CORS(app, resources={
|
||||||
r"/api/chat": {
|
r"/api/chat": {
|
||||||
"origins": "*",
|
"origins": "*"
|
||||||
"headers": ["Origin", "Content-Type", "Authorization"],
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/chat', methods=['POST'])
|
@app.route('/api/chat', methods=['POST'])
|
||||||
def chat(url_server = "http://localhost:11434/api/generate", model = "phi3:mini"):
|
def chat(url_server = "http://localhost:11434/api/generate", model = "phi3:mini"):
|
||||||
"""
|
"""
|
||||||
@@ -31,31 +99,38 @@ def chat(url_server = "http://localhost:11434/api/generate", model = "phi3:mini"
|
|||||||
# Get the message from the JSON in the request body
|
# Get the message from the JSON in the request body
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
message = data.get('query')
|
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
|
||||||
|
|
||||||
|
# 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})
|
||||||
|
|
||||||
|
# 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
|
||||||
|
}
|
||||||
|
|
||||||
# print(f"data = {data}\nmessage = {message}")
|
|
||||||
logger.debug("data = %s\nmessage = %s", str(data), str(message))
|
|
||||||
try:
|
try:
|
||||||
# Alternative LLM: "model": "mannix/llama3-8b-ablitered-v3:latest",
|
|
||||||
url = url_server
|
url = url_server
|
||||||
model_to_use = model
|
|
||||||
data = {
|
|
||||||
"model": model_to_use,
|
|
||||||
'prompt': message,
|
|
||||||
"stream": False
|
|
||||||
}
|
|
||||||
headers = {
|
headers = {
|
||||||
"Content-Type": "application/json",
|
"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,
|
response = requests.post(url,
|
||||||
headers=headers,
|
headers=headers,
|
||||||
data=json.dumps(data))
|
data=json.dumps(data_to_send))
|
||||||
response.raise_for_status() # Raise an exception for bad status codes
|
response.raise_for_status() # Raise an exception for bad status codes
|
||||||
|
llm_response = response.json()['response'] # Assuming the LLM's response is under 'response' key
|
||||||
|
chat_history.append({'role': 'assistant', 'message': llm_response}) # Add assistant response to chat history
|
||||||
|
logger.debug(f"Chat History: {chat_history}")
|
||||||
return response.json()
|
return response.json()
|
||||||
except requests.exceptions.RequestException as e:
|
except requests.exceptions.RequestException as e:
|
||||||
logger.error("Request Exception: %s", str(e))
|
logger.error("Request Exception: %s", str(e))
|
||||||
@@ -65,6 +140,7 @@ def chat(url_server = "http://localhost:11434/api/generate", model = "phi3:mini"
|
|||||||
return jsonify({'error': 'Invalid JSON response from server'}), 500
|
return jsonify({'error': 'Invalid JSON response from server'}), 500
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/smartassist', methods=["POST"])
|
@app.route('/smartassist', methods=["POST"])
|
||||||
def smartassist():
|
def smartassist():
|
||||||
# Extract the query from the incoming JSON data
|
# Extract the query from the incoming JSON data
|
||||||
@@ -79,13 +155,11 @@ def smartassist():
|
|||||||
return jsonify({"response": response})
|
return jsonify({"response": response})
|
||||||
|
|
||||||
def get_response(user_query):
|
def get_response(user_query):
|
||||||
# Create a client object for interacting with OLLAMA API
|
client = Client() # Create a client object for interacting with OLLAMA API
|
||||||
client = Client()
|
response = client.generate_response(user_query) # Generate and retrieve the response based on user's query
|
||||||
# Generate and retrieve the response based on user's query
|
|
||||||
response = client.generate_response(user_query)
|
|
||||||
# Return the generated response
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
def run_flask(fport=5005):
|
def run_flask(fport=5005):
|
||||||
"""
|
"""
|
||||||
Starts the Flask server
|
Starts the Flask server
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
<!--
|
|
||||||
Run a simple HTTP server in the directory containing your HTML file
|
|
||||||
python -m http.server 8000
|
|
||||||
Open your web browser and navigate to http://localhost:8000/smartassist/src/client.html
|
|
||||||
Note that the path starts from where the python venv was defined (project root)
|
|
||||||
-->
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Ollama Interaction</title>
|
|
||||||
<style>
|
|
||||||
/* Basic styling */
|
|
||||||
body { font-family: Arial, sans-serif; }
|
|
||||||
#chatbox {
|
|
||||||
width: 80%; /* responsive width */
|
|
||||||
max-width: 400px;
|
|
||||||
height: 300px;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
overflow-y: scroll;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
.message {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
.user-message {
|
|
||||||
background-color: #eae2d5;
|
|
||||||
padding: 10px;
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
.ai-response {
|
|
||||||
background-color: #cfc68b;
|
|
||||||
padding: 10px;
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>Ollama Interaction</h1>
|
|
||||||
<div id="chatbox">
|
|
||||||
<!-- messages will be rendered here -->
|
|
||||||
</div>
|
|
||||||
<input type="text" id="userInput" placeholder="Type your message here...">
|
|
||||||
<button onclick="sendMessage()">Send</button>
|
|
||||||
|
|
||||||
<!-- Link to the external frontend.js script (relative or absolute path)-->
|
|
||||||
<script src="frontend.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
|
|
||||||
// Get the user input element from the DOM
|
|
||||||
const chatbox = document.getElementById('chatbox');
|
|
||||||
const userInput = document.getElementById('userInput');
|
|
||||||
|
|
||||||
// Define a function to send the user's message to the AI
|
|
||||||
function sendMessage() {
|
|
||||||
// Get the user's input message and trim any whitespace
|
|
||||||
const query = userInput.value.trim();
|
|
||||||
|
|
||||||
// Check if the message is not empty
|
|
||||||
if (query !== '') {
|
|
||||||
// Send a POST request to the /api/chat endpoint with the message
|
|
||||||
fetch('http://localhost:5005/api/chat', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify({ query }),
|
|
||||||
})
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(data => {
|
|
||||||
// Get the AI's response from the API data
|
|
||||||
const aiResponse = data.response;
|
|
||||||
|
|
||||||
// Render the user's original message in the chatbox
|
|
||||||
renderMessage(query, 'user-message');
|
|
||||||
|
|
||||||
// Render the AI's response in the chatbox
|
|
||||||
renderMessage(aiResponse, 'ai-response');
|
|
||||||
|
|
||||||
// Clear the user input field for the next message
|
|
||||||
userInput.value = '';
|
|
||||||
})
|
|
||||||
.catch(error => console.error('Error sending message:', error));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Define a function to render a message in the chatbox with a specific class name
|
|
||||||
function renderMessage(text, className) {
|
|
||||||
// Create a new div element to hold the message
|
|
||||||
const messageElement = document.createElement('div');
|
|
||||||
|
|
||||||
// Add the specified class name to the element
|
|
||||||
messageElement.className = className;
|
|
||||||
|
|
||||||
// Set the text content of the element to the message text
|
|
||||||
messageElement.textContent = text;
|
|
||||||
|
|
||||||
// Append the message element to the chatbox
|
|
||||||
chatbox.appendChild(messageElement);
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Ollama Chat</title>
|
||||||
|
<link rel="stylesheet" href="/css/clientstyle.css">
|
||||||
|
<!-- <link rel="stylesheet" href="python_test/smartassist/src/css/clientstyle.css"> -->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Ollama Chat</h1>
|
||||||
|
<div id="chatbox">
|
||||||
|
<!-- messages will be rendered here -->
|
||||||
|
</div>
|
||||||
|
<textarea id="userInput" placeholder="Type your message..." rows="5"></textarea>
|
||||||
|
<button id="sendButton" onclick="sendMessage()">Send</button>
|
||||||
|
|
||||||
|
<!-- Get the apiEndpoint and the useModel -->
|
||||||
|
<!-- <script>
|
||||||
|
const apiEndpoint = window.apiEndpoint;
|
||||||
|
const useModel = window.useModel;
|
||||||
|
console.log("client.html - API Endpoint: ", apiEndpoint);
|
||||||
|
console.log("client.html - use model: ", useModel);
|
||||||
|
</script> -->
|
||||||
|
|
||||||
|
<!-- <script>
|
||||||
|
let apiEndpoint; // Make variable available outside of the scope of the event listener
|
||||||
|
let useModel; // Make variable available outside of the scope of the event listener
|
||||||
|
window.addEventListener('message', function(event) {
|
||||||
|
if (event.origin === 'http://localhost:5004') { // Make sure this matches your origin
|
||||||
|
const { apiEndpoint, useModel } = event.data;
|
||||||
|
console.log("client.html - API Endpoint: ", apiEndpoint);
|
||||||
|
console.log("client.html - use model: ", useModel);
|
||||||
|
window.apiEndpoint = apiEndpoint;
|
||||||
|
window.useModel = useModel;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script> -->
|
||||||
|
|
||||||
|
<!-- Marked-it for markdown rendering -->
|
||||||
|
<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 -->
|
||||||
|
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
|
||||||
|
<script>
|
||||||
|
window.MathJax = {
|
||||||
|
loader: { load: ['input/tex', 'output/chtml'] },
|
||||||
|
tex: {
|
||||||
|
packages: ['base', 'ams'],
|
||||||
|
inlineMath: [['$', '$']]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const chatContainer = document.getElementById('chatbox');
|
||||||
|
|
||||||
|
// Handle resize events
|
||||||
|
window.addEventListener('resize',
|
||||||
|
function() {
|
||||||
|
chatContainer.style.height = 'auto';
|
||||||
|
});
|
||||||
|
|
||||||
|
const userInputElement = document.getElementById('userInput');
|
||||||
|
|
||||||
|
userInputElement.addEventListener('keydown', function(event) {
|
||||||
|
if (event.shiftKey && event.key === 'Enter') { // Shift+Enter for newline
|
||||||
|
event.preventDefault();
|
||||||
|
userInputElement.value += '\n';
|
||||||
|
} else if (event.key === 'Enter') { // Enter to send message
|
||||||
|
window.frontendApi.sendMessage();
|
||||||
|
userInputElement.value = ''; // Clear the input field after sending
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Get the javascript handling communication with the backend -->
|
||||||
|
<script src="/js/frontend.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
@@ -5,21 +5,22 @@ import yaml
|
|||||||
import json
|
import json
|
||||||
import socket
|
import socket
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
|
from backend import run_flask
|
||||||
import logging
|
import logging
|
||||||
import utils
|
import utils
|
||||||
from utils import set_local_logger
|
from utils import GlobalState
|
||||||
from backend import run_flask
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__) # Logger for this module
|
global_state = GlobalState() # Configure root logger. The level will be adjusted later based on config file
|
||||||
|
logger = global_state.getLogger(__name__) # Logger for this module, inherit properties of the root logger
|
||||||
|
|
||||||
def configure():
|
def configure():
|
||||||
"""
|
"""
|
||||||
Reads YAML configruation file into dictionary, parse it and fill all referenceed
|
Reads YAML configruation file into dictionary, parse it and fill all referenceed
|
||||||
environment variables with their values.
|
environment variables with their values.
|
||||||
"""
|
"""
|
||||||
##################
|
####################################
|
||||||
# Read YAML config
|
# Read YAML config
|
||||||
##################
|
####################################
|
||||||
# Load configuration file that defines parameters for services
|
# Load configuration file that defines parameters for services
|
||||||
with open('./smartassist/config/smartassist.yaml') as f:
|
with open('./smartassist/config/smartassist.yaml') as f:
|
||||||
config = yaml.safe_load(f)
|
config = yaml.safe_load(f)
|
||||||
@@ -41,42 +42,62 @@ def configure():
|
|||||||
# Update the config dictionary with resolved environment variables
|
# Update the config dictionary with resolved environment variables
|
||||||
updated_config = update_dict_with_env_vars(config)
|
updated_config = update_dict_with_env_vars(config)
|
||||||
|
|
||||||
##################
|
####################################
|
||||||
# Extract global logging level
|
# Extract global logging level
|
||||||
##################
|
####################################
|
||||||
# The log_level variable will be used by the logger module to set the log level
|
|
||||||
# global log_level # Must be defined within function if referencing the global variable log_level defined outside this function
|
|
||||||
if isinstance(updated_config.get('logging'), dict): # Look for 'logging' key in config file
|
if isinstance(updated_config.get('logging'), dict): # Look for 'logging' key in config file
|
||||||
logging_config = updated_config['logging']
|
logging_config = updated_config['logging']
|
||||||
if isinstance(logging_config.get('level'), str): # Set to value of the yaml file if specified
|
if isinstance(logging_config.get('level'), str): # Set to value of the yaml file if specified
|
||||||
utils.log_level = logging_config['level']
|
global_state.set_log_level(logging_config['level'])
|
||||||
|
logger.debug("configure(): This logger now has effective log level %s", logger.getEffectiveLevel())
|
||||||
|
|
||||||
|
####################################
|
||||||
|
# Extract and export backend API
|
||||||
|
# endpoint as global state variable
|
||||||
|
####################################
|
||||||
|
if isinstance(updated_config.get('backend'), dict): # Look for 'backend' key
|
||||||
|
if isinstance(updated_config['backend'].get('url'), str): # Look for 'url' key
|
||||||
|
url = updated_config['backend'].get('url')
|
||||||
|
if isinstance(updated_config['backend'].get('api'), str): # Look for 'api' key
|
||||||
|
api = updated_config['backend'].get('api')
|
||||||
|
# backend_api_ep = url+api # Extract API endpoint if defined
|
||||||
|
logger.debug(f"Constructing endpoint address as url+api: {url+api}")
|
||||||
|
global_state.set_backend_api_ep(url+api) # Extract API endpoint if defined and set in global_state
|
||||||
|
logger.debug(f"Backend API endpoint is set to {global_state.get_backend_api_ep()}")
|
||||||
|
# os.environ['BE_API_ENDPOINT'] = backend_api_ep # Look into alternative way to share this with backend.py
|
||||||
|
|
||||||
set_local_logger(logger) # Set log level for logger based on log_level
|
####################################
|
||||||
|
# Extract Ollama parameters (url, api_key, model)
|
||||||
|
####################################
|
||||||
|
if isinstance(updated_config.get('ollama'), dict): # Look for 'ollama' key
|
||||||
|
if isinstance(updated_config['ollama'].get('model'), str): # Look for 'model' key
|
||||||
|
model_to_use = updated_config['ollama'].get('model')
|
||||||
|
global_state.set_llm(model_to_use)
|
||||||
|
logger.debug("configure(): LLM is set to: %s",global_state.get_llm())
|
||||||
|
|
||||||
return updated_config
|
return updated_config
|
||||||
|
|
||||||
|
|
||||||
def start_frontend(config):
|
# def start_frontend(config):
|
||||||
parsed_url = urllib.parse.urlparse(config['frontend']['url'])
|
# parsed_url = urllib.parse.urlparse(config['frontend']['url'])
|
||||||
hostname = parsed_url.netloc.split(':')[0] # Split by ':' and take the first part, i.e., 'localhost', IP, or domain name
|
# hostname = parsed_url.netloc.split(':')[0] # Split by ':' and take the first part, i.e., 'localhost', IP, or domain name
|
||||||
port = parsed_url.port # This is the server port
|
# port = parsed_url.port # This is the server port
|
||||||
|
|
||||||
# Use the socket module in Python to check whether a port is in use,
|
# # Use the socket module in Python to check whether a port is in use,
|
||||||
# which would indicate that a server is already running on that port.
|
# # which would indicate that a server is already running on that port.
|
||||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
# with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||||||
try:
|
# try:
|
||||||
s.bind((hostname, port))
|
# s.bind((hostname, port))
|
||||||
logger.info("No server is running on %s -— starting one.", parsed_url.netloc)
|
# logger.debug("No server is running on %s -— starting one.", parsed_url.netloc)
|
||||||
# Start frontend (web server) as a separate process
|
# # Start frontend (web server) as a separate process
|
||||||
subprocess.Popen(["python", "-m", "http.server", str(port)])
|
# subprocess.Popen(["python", "-m", "http.server", str(port)])
|
||||||
except socket.error as e:
|
# except socket.error as e:
|
||||||
if e.errno == 48:
|
# if e.errno == 48:
|
||||||
logger.error("A server is already running on %s -— will use this.", parsed_url.netloc)
|
# logger.debug("A server is already running on %s -— will use this.", parsed_url.netloc)
|
||||||
else:
|
# else:
|
||||||
raise # Unexpected error, re-raise it so we can see the traceback
|
# raise # Unexpected error, re-raise it so we can see the traceback
|
||||||
except Exception as e:
|
# except Exception as e:
|
||||||
logger.error("Failed to start frontend: %s", str(e)) # Corresponds to print(f"Failed to start frontend: {e}")
|
# logger.error("Failed to start frontend: %s", str(e)) # Corresponds to print(f"Failed to start frontend: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -95,6 +116,6 @@ def start_backend(config):
|
|||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
conf = configure() # Read config from file and set up config dict
|
conf = configure() # Read config from file and set up config dict
|
||||||
logger.debug('conf dictionary set to {}'.format(json.dumps(conf, indent=4)))
|
logger.debug('conf dictionary set to {}'.format(json.dumps(conf, indent=4)))
|
||||||
start_frontend(config=conf)
|
# start_frontend(config=conf) # Not needed as we are using Flask for backend now
|
||||||
start_backend(config=conf)
|
start_backend(config=conf)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#chatbox {
|
||||||
|
width: calc(50% - 60px); /* Adjust width for input and button */
|
||||||
|
/* max-width: 500px; */
|
||||||
|
height: 600px;
|
||||||
|
/* 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 {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-message {
|
||||||
|
background-color: #9cc1ecbb;
|
||||||
|
padding: 10px 15px;
|
||||||
|
border-radius: 10px;
|
||||||
|
text-align: left; /* Align user messages to the left */
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-response {
|
||||||
|
/* background-color: #f0f8ff; */
|
||||||
|
background-color: #f5ecd0;
|
||||||
|
padding: 10px 15px;
|
||||||
|
border-radius: 10px;
|
||||||
|
text-align: left; /* Align AI responses to the left */
|
||||||
|
}
|
||||||
|
|
||||||
|
#userInput {
|
||||||
|
width: calc(50% - 60px); /* Adjust width for input and button */
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-family: 'Courier New', Courier, monospace; /* Fixed width typeface */
|
||||||
|
}
|
||||||
|
|
||||||
|
#userInput:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #66afe9; /* Blue outline on focus */
|
||||||
|
}
|
||||||
|
|
||||||
|
button[onclick="sendMessage()"] {
|
||||||
|
background-color: #4CAF50; /* Green */
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
padding: 10px 20px;
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 16px;
|
||||||
|
border-radius: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.3s; /* Smooth transition effect */
|
||||||
|
}
|
||||||
|
|
||||||
|
button[onclick="sendMessage()"]:hover {
|
||||||
|
background-color: #b2b2b2; /* Light Grey on hover */
|
||||||
|
}
|
||||||
|
|
||||||
|
button[onclick="sendMessage()"]:active {
|
||||||
|
background-color: #6f6f6f; /* Dark Grey when clicked */
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,192 @@
|
|||||||
|
|
||||||
|
// // Get the user input element from the DOM
|
||||||
|
// const chatbox = document.getElementById('chatbox');
|
||||||
|
// const userInput = document.getElementById('userInput');
|
||||||
|
|
||||||
|
// const parser = window.markdownit({
|
||||||
|
// linkify: true,
|
||||||
|
// strikethrough: true,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// parser.enable(['table']);
|
||||||
|
|
||||||
|
// // const apiEndpoint = window.apiEndpoint; // Get the API endpoint
|
||||||
|
// // const useModel = window.useModel; // Get whether to use a model or not
|
||||||
|
// // console.log("frontend.js - API Endpoint: ", window.apiEndpoint);
|
||||||
|
// // console.log("frontend.js - Use model: ", window.useModel);
|
||||||
|
|
||||||
|
// let apiEndpoint; // Make variable available outside of the scope of the event listener
|
||||||
|
// let useModel; // Make variable available outside of the scope of the event listener
|
||||||
|
// window.addEventListener('message', function(event) {
|
||||||
|
// if (event.origin === 'http://localhost:5004') { // Make sure this matches your origin
|
||||||
|
// const { apiEndpoint, useModel } = event.data;
|
||||||
|
// console.log("client.html - API Endpoint: ", apiEndpoint);
|
||||||
|
// console.log("client.html - use model: ", useModel);
|
||||||
|
// window.apiEndpoint = apiEndpoint;
|
||||||
|
// window.useModel = useModel;
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
// console.log("frontend.js - API Endpoint: ", window.apiEndpoint);
|
||||||
|
// console.log("frontend.js - Use model: ", window.useModel);
|
||||||
|
|
||||||
|
// // Define a function to send the user's message to the AI
|
||||||
|
// function sendMessage() {
|
||||||
|
// // Get the user's input message and trim any whitespace
|
||||||
|
// const query = userInput.value.trim();
|
||||||
|
|
||||||
|
// // Check if the message is not empty
|
||||||
|
// if (query !== '') {
|
||||||
|
|
||||||
|
// // fetch(`${apiEndpoint}`, {
|
||||||
|
// fetch(apiEndpoint, {
|
||||||
|
// method: 'POST',
|
||||||
|
// headers: { 'Content-Type': 'application/json' },
|
||||||
|
// body: JSON.stringify({ query, model: useModel }), // Add these parameters here
|
||||||
|
// // body: JSON.stringify({ query, url_server: "http://your-custom-url", model: "phi3:mini" }), // Add these parameters here
|
||||||
|
// })
|
||||||
|
// .then(response => response.json())
|
||||||
|
// .then(data => {
|
||||||
|
// // Get the AI's response from the API data
|
||||||
|
// const aiResponse = data.response;
|
||||||
|
|
||||||
|
// // Render the user's original message in the chatbox
|
||||||
|
// renderMessage(query, 'user-message');
|
||||||
|
|
||||||
|
// // Render the AI's response in the chatbox
|
||||||
|
// renderMessage(aiResponse, 'ai-response');
|
||||||
|
|
||||||
|
// // Clear the user input field for the next message
|
||||||
|
// userInput.value = '';
|
||||||
|
// })
|
||||||
|
// .catch(error => console.error('Error sending message:', error));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// // Define a function to render a message in the chatbox with a specific class name
|
||||||
|
// function renderMessage(text, className) {
|
||||||
|
// // Create a new div element to hold the message
|
||||||
|
// const messageElement = document.createElement('div');
|
||||||
|
|
||||||
|
// // Add the specified class name to the element
|
||||||
|
// messageElement.className = className;
|
||||||
|
|
||||||
|
// // // Set the text content of the element to the message text
|
||||||
|
// // messageElement.textContent = text;
|
||||||
|
|
||||||
|
// // Use the markdown-it parser
|
||||||
|
// const html = parser.render(text);
|
||||||
|
// messageElement.innerHTML = html;
|
||||||
|
|
||||||
|
// // Append the message element to the chatbox immediately
|
||||||
|
// // 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);
|
||||||
|
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Make the button toggle colour when user presses Enter on keyboard
|
||||||
|
// const sendButton = document.getElementById('sendButton');
|
||||||
|
|
||||||
|
// document.addEventListener('keydown', function(event) {
|
||||||
|
// if (event.key === 'Enter') {
|
||||||
|
// sendButton.style.backgroundColor = '#6f6f6f'; // Dark Grey when Enter is pressed
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
// document.addEventListener('keyup', function() {
|
||||||
|
// sendButton.style.backgroundColor = ''; // Restore the original style when any key is released
|
||||||
|
// });
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Get the user input element from the DOM
|
||||||
|
const chatbox = document.getElementById('chatbox');
|
||||||
|
const userInput = document.getElementById('userInput');
|
||||||
|
const parser = window.markdownit({
|
||||||
|
linkify: true,
|
||||||
|
strikethrough: true,
|
||||||
|
});
|
||||||
|
parser.enable(['table']);
|
||||||
|
|
||||||
|
let apiEndpoint; // Make variable available outside of the scope of the event listener
|
||||||
|
let useModel; // Make variable available outside of the scope of the event listener
|
||||||
|
|
||||||
|
const frontendApi = {
|
||||||
|
// Define a function to send the user's message to the AI
|
||||||
|
sendMessage: function() {
|
||||||
|
if (!window.apiEndpoint || !window.useModel) { // Check if we're ready before proceeding
|
||||||
|
console.error("Not ready yet. Please wait for apiEndpoint and useModel to be set.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the user's input message and trim any whitespace
|
||||||
|
const query = userInput.value.trim();
|
||||||
|
// Check if the message is not empty
|
||||||
|
if (query !== '') {
|
||||||
|
fetch(window.apiEndpoint, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ query, model: window.useModel }), // Add these parameters here
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
// Get the AI's response from the API data
|
||||||
|
const aiResponse = data.response;
|
||||||
|
// Render the user's original message in the chatbox
|
||||||
|
this.renderMessage(query, 'user-message');
|
||||||
|
// Render the AI's response in the chatbox
|
||||||
|
this.renderMessage(aiResponse, 'ai-response');
|
||||||
|
// Clear the user input field for the next message
|
||||||
|
userInput.value = '';
|
||||||
|
})
|
||||||
|
.catch(error => console.error('Error sending message:', error));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Define a function to render a message in the chatbox with a specific class name
|
||||||
|
renderMessage: function(text, className) {
|
||||||
|
// Create a new div element to hold the message
|
||||||
|
const messageElement = document.createElement('div');
|
||||||
|
// Add the specified class name to the element
|
||||||
|
messageElement.className = className;
|
||||||
|
// Use the markdown-it parser
|
||||||
|
const html = parser.render(text);
|
||||||
|
messageElement.innerHTML = html;
|
||||||
|
// Append the message element to the chatbox immediately
|
||||||
|
chatbox.appendChild(messageElement);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Wait for the event listener to set apiEndpoint and useModel
|
||||||
|
window.addEventListener('message', function(event) {
|
||||||
|
if (event.origin === 'http://localhost:5004') { // Make sure this matches your origin
|
||||||
|
const { apiEndpoint, useModel } = event.data;
|
||||||
|
console.log("fronend.js - API Endpoint: ", apiEndpoint);
|
||||||
|
console.log("fronend.js - use model: ", useModel);
|
||||||
|
window.apiEndpoint = apiEndpoint;
|
||||||
|
window.useModel = useModel;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Wait for the DOM to be fully loaded before making the API available
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
window.frontendApi = frontendApi;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Make the button toggle colour when user presses Enter on keyboard
|
||||||
|
const sendButton = document.getElementById('sendButton');
|
||||||
|
document.addEventListener('keydown', function(event) {
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
sendButton.style.backgroundColor = '#6f6f6f'; // Dark Grey when Enter is pressed
|
||||||
|
}
|
||||||
|
});
|
||||||
|
document.addEventListener('keyup', function() {
|
||||||
|
sendButton.style.backgroundColor = ''; // Restore the original style when any key is released
|
||||||
|
});
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<!-- <title>Frontend</title> -->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- This iframe will hold the content from client.html -->
|
||||||
|
<!-- Passing the API endpoint as a query parameter to the srcdoc attribute -->
|
||||||
|
<!-- srcdoc="{{ client_content }}?apiEndpoint={{ api_endpoint }}/"> -->
|
||||||
|
|
||||||
|
<iframe id="client-frame"
|
||||||
|
style="width: 100%; height: 100vh;"
|
||||||
|
srcdoc="{{ client_content }}">
|
||||||
|
</iframe>
|
||||||
|
|
||||||
|
<!-- <script>
|
||||||
|
// Extract apiEndpoint for use in your frontend code...
|
||||||
|
const apiEndpoint = '{{ api_endpoint }}'; // Templating syntax (Jinja2)
|
||||||
|
const useModel = '{{ use_model }}'; // Templating syntax (Jinja2)
|
||||||
|
// Tell the iframe about the apiEndpoint
|
||||||
|
document.getElementById('client-frame').contentWindow.apiEndpoint = apiEndpoint;
|
||||||
|
document.getElementById('client-frame').contentWindow.useModel = useModel;
|
||||||
|
console.log("index.html - API Endpoint: ", apiEndpoint);
|
||||||
|
console.log("index.html - use model: ", useModel);
|
||||||
|
</script> -->
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Extract apiEndpoint for use in frontend.js
|
||||||
|
const apiEndpoint = '{{ api_endpoint }}'; // Templating syntax (Jinja2)
|
||||||
|
const useModel = '{{ use_model }}'; // Templating syntax (Jinja2)
|
||||||
|
window.addEventListener('load', function() {
|
||||||
|
const clientFrame = document.getElementById('client-frame').contentWindow;
|
||||||
|
clientFrame.postMessage({ apiEndpoint, useModel }, '*'); // Send the data to the iframe
|
||||||
|
});
|
||||||
|
console.log("index.html - API Endpoint: ", apiEndpoint);
|
||||||
|
console.log("index.html - use model: ", useModel);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Responsive scaling and some padding -->
|
||||||
|
<script>
|
||||||
|
const clientFrame = document.getElementById('client-frame');
|
||||||
|
|
||||||
|
function resizeIframe() {
|
||||||
|
clientFrame.style.height = window.innerHeight - 50 + 'px'; // Adjust the subtraction for padding/margins if needed
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('resize', resizeIframe);
|
||||||
|
resizeIframe(); // Call it once on page load
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
+66
-13
@@ -2,21 +2,74 @@
|
|||||||
# imported to more than one other module. The rational for defining these things here
|
# imported to more than one other module. The rational for defining these things here
|
||||||
# is that it is easier to avoid circular imports when they are defined in a central location.
|
# is that it is easier to avoid circular imports when they are defined in a central location.
|
||||||
import logging
|
import logging
|
||||||
global log_level # Remember, in Python globals are only global in the module it is defined in
|
|
||||||
log_level = 'INFO' # Default logging level
|
|
||||||
|
|
||||||
|
class GlobalState:
|
||||||
def set_local_logger(log_instance):
|
|
||||||
"""
|
"""
|
||||||
Configure logging based on the global variable log_level
|
This class holds various variables and methods which are accessible across
|
||||||
Logging is controlled by integer values, where DEBUG < INFO < WARNING < ERROR < CRITICAL.
|
different modules in the Python project using the Singleton design pattern.
|
||||||
To turn off logging completely, set numeric_log_level to at least CRITICAL + 1.
|
This ensures that only one instance of the class is created and shared among
|
||||||
|
all modules, preventing circular imports and providing a centralized location
|
||||||
|
for managing shared resources.
|
||||||
"""
|
"""
|
||||||
global log_level
|
_instance = None # Private class attribute to hold the single instance of the class
|
||||||
numeric_log_level = getattr(logging, log_level, None)
|
|
||||||
if not isinstance(numeric_log_level, int):
|
|
||||||
raise ValueError('Invalid log level: %s' % log_level)
|
|
||||||
|
|
||||||
logging.basicConfig(level=numeric_log_level) # Set the root logger level to the configured level
|
def __new__(cls):
|
||||||
log_instance.info('Log level set to {}'.format(log_level)) # Example usage of the logger
|
if cls._instance is None:
|
||||||
|
cls._instance = super(GlobalState, cls).__new__(cls)
|
||||||
|
cls._instance.log_level = 'INFO' # Default logging level
|
||||||
|
cls._instance.logger = logging.getLogger() # Get root logger for the caller module
|
||||||
|
handler = logging.StreamHandler() # Or other handler (FileHandler for logs to file)
|
||||||
|
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
||||||
|
handler.setFormatter(formatter)
|
||||||
|
cls._instance.logger.addHandler(handler)
|
||||||
|
cls._instance.logger.setLevel(getattr(logging, cls._instance.log_level)) # Initialize root logger level
|
||||||
|
cls._instance.logger.info(" __new__(cls): Logger in GlobalState created: %s", cls._instance.logger)
|
||||||
|
cls._instance.llm = "phi3:mini" # Default LLM for queries. TODO: Check with ollama server that it actually exists
|
||||||
|
cls._instance.backend_api_ep = "http://localhost:5005/api/chat" # Default backend API endpoint
|
||||||
|
return cls._instance
|
||||||
|
|
||||||
|
def configure_logging(self, level=None):
|
||||||
|
"""Set up logging for the project."""
|
||||||
|
if level is None:
|
||||||
|
level = self.log_level
|
||||||
|
# numeric_level = getattr(logging, level.upper()) # Convert string to numeric level
|
||||||
|
numeric_level = getattr(logging, level.upper()) # Convert string to numeric level
|
||||||
|
self.logger.setLevel(numeric_level)
|
||||||
|
self.logger.debug(f"utils.py -- configure_logging(): effective log level is {level} which is {self.logger.getEffectiveLevel()}")
|
||||||
|
|
||||||
|
def set_log_level(self, level = 'INFO'):
|
||||||
|
"""Set the logging level."""
|
||||||
|
self.log_level = level
|
||||||
|
self.configure_logging()
|
||||||
|
|
||||||
|
def get_log_level(self):
|
||||||
|
"""Getter for log_level attribute."""
|
||||||
|
return self.log_level
|
||||||
|
|
||||||
|
def get_effective_log_level(self):
|
||||||
|
"""Getter for effective log level of loggerattribute."""
|
||||||
|
return self.logger.getEffectiveLevel()
|
||||||
|
|
||||||
|
def getLogger(self, module_name = None):
|
||||||
|
"""Return a logger based on the module name."""
|
||||||
|
if module_name is None:
|
||||||
|
module_name = __name__
|
||||||
|
logger = logging.getLogger(module_name)
|
||||||
|
return logger
|
||||||
|
|
||||||
|
def set_llm(self, model_name="phi3:mini"):
|
||||||
|
"""Set LLM for queries"""
|
||||||
|
self.llm = model_name
|
||||||
|
|
||||||
|
def get_llm(self):
|
||||||
|
"""Getter for which LLM is used for queries"""
|
||||||
|
return self.llm
|
||||||
|
|
||||||
|
def set_backend_api_ep(self, be_api_ep=None):
|
||||||
|
"""Set backend API endpoint"""
|
||||||
|
self.backend_api_ep = be_api_ep
|
||||||
|
|
||||||
|
def get_backend_api_ep(self):
|
||||||
|
"""Getter for backend API endpoint"""
|
||||||
|
return self.backend_api_ep
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user