Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b3136a9bcd | |||
| 81f2352291 | |||
| b102309d7b | |||
| 753353445c |
@@ -11,9 +11,10 @@ backend:
|
|||||||
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
|
||||||
|
|
||||||
# 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:
|
||||||
|
|||||||
+28
-16
@@ -5,7 +5,13 @@ from flask import Flask, request, jsonify
|
|||||||
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 threading
|
import logging
|
||||||
|
import utils
|
||||||
|
from utils import set_local_logger, run_flask
|
||||||
|
|
||||||
|
global log_level # Global variable to store the log level that is set in startservices.py
|
||||||
|
logger = logging.getLogger(__name__) # Separate logger for this module
|
||||||
|
set_local_logger(logger) # Set log level for logger based on log_level
|
||||||
|
|
||||||
# Initialize a Flask application
|
# Initialize a Flask application
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
@@ -19,12 +25,18 @@ CORS(app, resources={
|
|||||||
|
|
||||||
@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"):
|
||||||
|
"""
|
||||||
|
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
|
# 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')
|
||||||
|
|
||||||
print(f"data = {data}\nmessage = {message}")
|
# 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",
|
# Alternative LLM: "model": "mannix/llama3-8b-ablitered-v3:latest",
|
||||||
url = url_server
|
url = url_server
|
||||||
@@ -47,13 +59,12 @@ def chat(url_server = "http://localhost:11434/api/generate", model = "phi3:mini"
|
|||||||
headers=headers,
|
headers=headers,
|
||||||
data=json.dumps(data))
|
data=json.dumps(data))
|
||||||
response.raise_for_status() # Raise an exception for bad status codes
|
response.raise_for_status() # Raise an exception for bad status codes
|
||||||
# print(json.dumps(response.json(), indent=4))
|
|
||||||
return response.json()
|
return response.json()
|
||||||
except requests.exceptions.RequestException as e:
|
except requests.exceptions.RequestException as e:
|
||||||
print(f"Request Exception: {e}")
|
logger.error("Request Exception: %s", str(e))
|
||||||
return jsonify({'error': 'Failed to process request'}), 500
|
return jsonify({'error': 'Failed to process request'}), 500
|
||||||
except json.JSONDecodeError as e:
|
except json.JSONDecodeError as e:
|
||||||
print(f"JSON Decode Error: {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
|
return jsonify({'error': 'Invalid JSON response from server'}), 500
|
||||||
|
|
||||||
|
|
||||||
@@ -73,24 +84,25 @@ def smartassist():
|
|||||||
def get_response(user_query):
|
def get_response(user_query):
|
||||||
# Create a client object for interacting with OLLAMA API
|
# Create a client object for interacting with OLLAMA API
|
||||||
client = Client()
|
client = Client()
|
||||||
|
|
||||||
# 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)
|
response = client.generate_response(user_query)
|
||||||
|
|
||||||
# Return the generated response
|
# Return the generated response
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def run_flask(fport=5005):
|
# def run_flask(fport=5005):
|
||||||
# Flask endpoint for user interaction
|
# """
|
||||||
print(f"Entering run_flask()")
|
# Starts the Flask server
|
||||||
# app.run(port = str(str(fport)), debug=False)
|
# """
|
||||||
app.run(port = str(str(fport)), debug=True)
|
# # Flask endpoint for user interaction
|
||||||
# app.run(port=5000, debug=True, use_reloader=False)
|
# logger.debug("Entering run_flask()")
|
||||||
print(f"Exiting run_flask()")
|
# # app.run(port = str(str(fport)), debug=False)
|
||||||
|
# app.run(port = str(str(fport)), debug=True)
|
||||||
|
# # app.run(port=5000, debug=True, use_reloader=False)
|
||||||
|
# logger.debug("Exiting run_flask()")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# Run the Flask application
|
# Run the Flask application
|
||||||
run_flask()
|
run_flask(app)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,31 +3,36 @@ import subprocess
|
|||||||
import os
|
import os
|
||||||
import yaml
|
import yaml
|
||||||
import json
|
import json
|
||||||
from backend import run_flask
|
# from backend import run_flask
|
||||||
import socket
|
import socket
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
import logging
|
import logging
|
||||||
|
import utils
|
||||||
|
from utils import set_local_logger, run_flask
|
||||||
|
|
||||||
global log_level
|
# global log_level
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
# logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
def set_local_logger(log_instance):
|
# def set_local_logger(log_instance):
|
||||||
"""
|
# """
|
||||||
Configure logging based on the global variable log_level
|
# Configure logging based on the global variable log_level
|
||||||
Logging is controlled by integer values, where DEBUG < INFO < WARNING < ERROR < CRITICAL.
|
# Logging is controlled by integer values, where DEBUG < INFO < WARNING < ERROR < CRITICAL.
|
||||||
To turn off logging completely, set numeric_log_level to at least CRITICAL + 1.
|
# To turn off logging completely, set numeric_log_level to at least CRITICAL + 1.
|
||||||
"""
|
# """
|
||||||
global log_level
|
# global log_level
|
||||||
numeric_log_level = getattr(logging, log_level, None)
|
# numeric_log_level = getattr(logging, log_level, None)
|
||||||
if not isinstance(numeric_log_level, int):
|
# if not isinstance(numeric_log_level, int):
|
||||||
raise ValueError('Invalid log level: %s' % log_level)
|
# raise ValueError('Invalid log level: %s' % log_level)
|
||||||
|
|
||||||
logging.basicConfig(level=numeric_log_level) # Set the root logger level to the configured level
|
# logging.basicConfig(level=numeric_log_level) # Set the root logger level to the configured level
|
||||||
log_instance.info('Log level set to {}'.format(log_level)) # Example usage of the logger
|
# log_instance.info('Log level set to {}'.format(log_level)) # Example usage of the logger
|
||||||
|
|
||||||
def configure():
|
def configure():
|
||||||
|
"""
|
||||||
|
Reads YAML configruation file into dictionary, parse it and fill all referenceed
|
||||||
|
environment variables with their values.
|
||||||
|
"""
|
||||||
##################
|
##################
|
||||||
# Read YAML config
|
# Read YAML config
|
||||||
##################
|
##################
|
||||||
@@ -56,14 +61,14 @@ def configure():
|
|||||||
# Extract global logging level
|
# Extract global logging level
|
||||||
##################
|
##################
|
||||||
# The log_level variable will be used by the logger module to set the log level
|
# The log_level variable will be used by the logger module to set the log level
|
||||||
global log_level
|
global log_level # REALLY NECESSARY TO DEFINE THIS GLOBAL AGAIN???
|
||||||
log_level = 'INFO' # Default value if not specified in the config file
|
log_level = 'INFO' # Default value if not specified in the config file
|
||||||
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
|
||||||
log_level = logging_config['level']
|
log_level = logging_config['level']
|
||||||
|
|
||||||
set_local_logger(logger) # Set log level for logger based on log_level
|
set_local_logger(utils.logger) # Set log level for logger based on log_level
|
||||||
|
|
||||||
return updated_config
|
return updated_config
|
||||||
|
|
||||||
@@ -78,16 +83,16 @@ def start_frontend(config):
|
|||||||
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)
|
utils.logger.info("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)
|
utils.logger.error("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}")
|
utils.logger.error("Failed to start frontend: %s", str(e)) # Corresponds to print(f"Failed to start frontend: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -95,17 +100,17 @@ def start_backend(config):
|
|||||||
parsed_url = urllib.parse.urlparse(config['backend']['url'])
|
parsed_url = urllib.parse.urlparse(config['backend']['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
|
||||||
logger.debug('Backend parsed url set to {}'.format(parsed_url))
|
utils.logger.debug('Backend parsed url set to {}'.format(parsed_url))
|
||||||
logger.debug('Backend port set to {}'.format(port))
|
utils.logger.debug('Backend port set to {}'.format(port))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
run_flask(fport = port)
|
run_flask(fport = port)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("Failed to start backend: %s", str(e)) # Corresponds to print(f"Failed to start backend: {e}")
|
utils.logger.error("Failed to start backend: %s", str(e)) # Corresponds to print(f"Failed to start backend: {e}")
|
||||||
|
|
||||||
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)))
|
utils.logger.debug('conf dictionary set to {}'.format(json.dumps(conf, indent=4)))
|
||||||
start_frontend(config=conf)
|
start_frontend(config=conf)
|
||||||
start_backend(config=conf)
|
start_backend(config=conf)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# This module contains definitions of variables, functions, classes, et cetera, that are
|
||||||
|
# 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.
|
||||||
|
import logging
|
||||||
|
|
||||||
|
global log_level
|
||||||
|
log_level = 'INFO'
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
def set_local_logger(log_instance):
|
||||||
|
"""
|
||||||
|
Configure logging based on the global variable log_level
|
||||||
|
Logging is controlled by integer values, where DEBUG < INFO < WARNING < ERROR < CRITICAL.
|
||||||
|
To turn off logging completely, set numeric_log_level to at least CRITICAL + 1.
|
||||||
|
"""
|
||||||
|
global log_level
|
||||||
|
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
|
||||||
|
log_instance.info('Log level set to {}'.format(log_level)) # Example usage of the logger
|
||||||
|
|
||||||
|
|
||||||
|
def run_flask(app, fport=5005):
|
||||||
|
"""
|
||||||
|
Starts the Flask server
|
||||||
|
"""
|
||||||
|
# Flask endpoint for user interaction
|
||||||
|
logger.debug("Entering run_flask()")
|
||||||
|
# app.run(port = str(str(fport)), debug=False)
|
||||||
|
app.run(port = str(str(fport)), debug=True)
|
||||||
|
# app.run(port=5000, debug=True, use_reloader=False)
|
||||||
|
logger.debug("Exiting run_flask()")
|
||||||
Reference in New Issue
Block a user