7 Commits

7 changed files with 71 additions and 72 deletions
+2 -2
View File
@@ -11,10 +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 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: "mistral-nemo:latest" # Select a model supported by the Ollama server
# model: "gemma2:27b" # model: "gemma2:27b"
+13 -48
View File
@@ -1,7 +1,7 @@
# 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, send_from_directory, render_template, session 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
@@ -41,8 +41,9 @@ def index():
session['chat_history'] = [] # The session object (actually, a dictonary) holds the chat session session['chat_history'] = [] # The session object (actually, a dictonary) holds the chat session
logger.debug("Entering route '/'") logger.debug("Entering route '/'")
api_endpoint = os.environ['BE_API_ENDPOINT'] # Retrieve the environment variable # api_endpoint = os.environ['BE_API_ENDPOINT'] # Retrieve the environment variable
logger.debug("API endpoint: %s", api_endpoint) 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() use_model = global_state.get_llm()
with open('smartassist/src/html/client.html', 'r') as f: with open('smartassist/src/html/client.html', 'r') as f:
client_html = f.read() client_html = f.read()
@@ -51,6 +52,12 @@ def index():
return render_template('index.html', api_endpoint=api_endpoint, use_model = use_model, client_content=client_html) 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') @app.route('/profile')
def profile(): def profile():
# Retrieve data from the session # Retrieve data from the session
@@ -79,49 +86,6 @@ CORS(app, resources={
"origins": "*" "origins": "*"
} }
}) })
# @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']) @app.route('/api/chat', methods=['POST'])
@@ -143,7 +107,6 @@ def chat(url_server = "http://localhost:11434/api/generate", model = "phi3:mini"
# Add the new message to the chat history # Add the new message to the chat history
chat_history.append({'role': 'user', 'message': message}) chat_history.append({'role': 'user', 'message': message})
logger.debug(f"Chat History: {chat_history}")
# Update the session with the new chat history # Update the session with the new chat history
session['chat_history'] = chat_history session['chat_history'] = chat_history
@@ -165,7 +128,9 @@ def chat(url_server = "http://localhost:11434/api/generate", model = "phi3:mini"
headers=headers, headers=headers,
data=json.dumps(data_to_send)) 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))
+20 -6
View File
@@ -14,14 +14,27 @@
<textarea id="userInput" placeholder="Type your message..." rows="5"></textarea> <textarea id="userInput" placeholder="Type your message..." rows="5"></textarea>
<button id="sendButton" onclick="sendMessage()">Send</button> <button id="sendButton" onclick="sendMessage()">Send</button>
<!-- Get the apiEndpoint --> <!-- Get the apiEndpoint and the useModel -->
<script> <!-- <script>
const apiEndpoint = window.apiEndpoint; const apiEndpoint = window.apiEndpoint;
const useModel = window.useModel; 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);
}
});
</script> </script>
<!-- Marked for markdown rendering --> <!-- Marked-it 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.1.0/dist/markdown-it.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/markdown-it@14/dist/markdown-it.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/markdown-it@14/dist/markdown-it.min.js"></script>
@@ -40,8 +53,7 @@
</script> </script>
<!-- Get the javascript handling communication with the backend -->
<script src="/js/frontend.js"></script>
<script> <script>
const chatContainer = document.getElementById('chatbox'); const chatContainer = document.getElementById('chatbox');
@@ -67,6 +79,8 @@
</script> </script>
<!-- Get the javascript handling communication with the backend -->
<script src="/js/frontend.js"></script>
</body> </body>
</html> </html>
+7 -6
View File
@@ -52,18 +52,19 @@ def configure():
logger.debug("configure(): This logger now has effective log level %s", logger.getEffectiveLevel()) logger.debug("configure(): This logger now has effective log level %s", logger.getEffectiveLevel())
#################################### ####################################
# Extract and export API endpoint as # Extract and export backend API
# envrionment variable # endpoint as global state variable
#################################### ####################################
backend_api_ep = 'http://localhost:5005/api/chat' # Default API endpoint
if isinstance(updated_config.get('backend'), dict): # Look for 'backend' key if isinstance(updated_config.get('backend'), dict): # Look for 'backend' key
if isinstance(updated_config['backend'].get('url'), str): # Look for 'url' key if isinstance(updated_config['backend'].get('url'), str): # Look for 'url' key
url = updated_config['backend'].get('url') url = updated_config['backend'].get('url')
if isinstance(updated_config['backend'].get('api'), str): # Look for 'api' key if isinstance(updated_config['backend'].get('api'), str): # Look for 'api' key
api = updated_config['backend'].get('api') api = updated_config['backend'].get('api')
backend_api_ep = url+api # Extract API endpoint if defined # backend_api_ep = url+api # Extract API endpoint if defined
logger.debug("BE_API_ENDPOINT is set to '{}'".format(backend_api_ep)) logger.debug(f"Constructing endpoint address as url+api: {url+api}")
os.environ['BE_API_ENDPOINT'] = backend_api_ep # Look into alternative way to share this with backend.py 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
#################################### ####################################
# Extract Ollama parameters (url, api_key, model) # Extract Ollama parameters (url, api_key, model)
+5 -7
View File
@@ -10,11 +10,8 @@ const parser = window.markdownit({
parser.enable(['table']); parser.enable(['table']);
console.log("frontend.js - API Endpoint: ", apiEndpoint);
// const html = markdownIt.use({ console.log("frontend.js - use model: ", useModel);
// // You can customize the parser options here, e.g., enable/disable certain features
// });
// Define a function to send the user's message to the AI // Define a function to send the user's message to the AI
function sendMessage() { function sendMessage() {
@@ -24,10 +21,11 @@ function sendMessage() {
// Check if the message is not empty // Check if the message is not empty
if (query !== '') { if (query !== '') {
fetch(`${apiEndpoint}`, { // fetch(`${apiEndpoint}`, {
fetch(apiEndpoint, {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query, model: `${useModel}` }), // Add these parameters here 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 // body: JSON.stringify({ query, url_server: "http://your-custom-url", model: "phi3:mini" }), // Add these parameters here
}) })
.then(response => response.json()) .then(response => response.json())
+14 -2
View File
@@ -15,15 +15,27 @@
srcdoc="{{ client_content }}"> srcdoc="{{ client_content }}">
</iframe> </iframe>
<script> <!-- <script>
// Extract apiEndpoint for use in your frontend code... // Extract apiEndpoint for use in your frontend code...
const apiEndpoint = '{{ api_endpoint }}'; // Templating syntax (Jinja2) const apiEndpoint = '{{ api_endpoint }}'; // Templating syntax (Jinja2)
const useModel = '{{ use_model }}'; // Templating syntax (Jinja2) const useModel = '{{ use_model }}'; // Templating syntax (Jinja2)
// Tell the iframe about the apiEndpoing // Tell the iframe about the apiEndpoint
document.getElementById('client-frame').contentWindow.apiEndpoint = apiEndpoint; document.getElementById('client-frame').contentWindow.apiEndpoint = apiEndpoint;
document.getElementById('client-frame').contentWindow.useModel = useModel; document.getElementById('client-frame').contentWindow.useModel = useModel;
console.log("index.html - API Endpoint: ", apiEndpoint); console.log("index.html - API Endpoint: ", apiEndpoint);
console.log("index.html - use model: ", useModel); 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> </script>
<!-- Responsive scaling and some padding --> <!-- Responsive scaling and some padding -->
+10 -1
View File
@@ -25,6 +25,7 @@ class GlobalState:
cls._instance.logger.setLevel(getattr(logging, cls._instance.log_level)) # Initialize root logger level 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.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.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 return cls._instance
def configure_logging(self, level=None): def configure_logging(self, level=None):
@@ -49,7 +50,7 @@ class GlobalState:
"""Getter for effective log level of loggerattribute.""" """Getter for effective log level of loggerattribute."""
return self.logger.getEffectiveLevel() return self.logger.getEffectiveLevel()
def getLogger(self, module_name=None): def getLogger(self, module_name = None):
"""Return a logger based on the module name.""" """Return a logger based on the module name."""
if module_name is None: if module_name is None:
module_name = __name__ module_name = __name__
@@ -64,3 +65,11 @@ class GlobalState:
"""Getter for which LLM is used for queries""" """Getter for which LLM is used for queries"""
return self.llm 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