4This module sets up a Flask web application for managing storage items, controlling WLED devices,
5interacting with a WiFi scale, and querying an LLM service. It provides various routes for rendering templates,
6handling item creation, deletion, and search, as well as retrieving environment configurations,
7scale weight, and logging messages.
10 - /: Renders the search page.
11 - /toggleLight: Toggles the power state of the WLED device and renders the search template.
12 - /createItem: Renders the template for creating a new item.
13 - /sendCreation: Handles the creation of a new item by processing the incoming JSON request data.
14 - /item/<item_id>: Handles the request to display an item.
15 - /item/<item_id>/update: Updates an item using the Storage_connector and returns a status message.
16 - /item/<item_id>/delete: Deletes an item using the Storage_connector and renders the search.html template.
17 - /search/<term>: Searches for a term in the storage and returns the results in JSON format.
18 - /config/env: Retrieves the environment configuration.
19 - /config/ollama/models: Fetches the list of available Ollama models.
20 - /wifiscale/weight: Retrieves the weight of the scale.
21 - /llm/ask: Asks a question to the LLM service and returns the response.
22 - /log: Logs a message with a specified log level.
25 - handle_exception: Handles exceptions by passing through HTTP errors.
28 - Initializes the Flask app and sets up CORS.
29 - Loads environment variables from a .env file.
30 - Sets up the Storage_connector within the app context.
33 Run the application using the command `python app.py`.
36from typing
import Annotated
47from flask_cors
import CORS
48from dotenv
import load_dotenv
50from logger_config
import logger
51import Storage_connector
53import weigh_fi_manager
as wifiscale
55import ollama_manager
as ollama
57ENV_PATH = os.path.join(os.path.dirname(__file__),
"data/.env")
58load_dotenv(dotenv_path=ENV_PATH)
59IS_SCALE_ENABLED = os.getenv(
"IS_SCALE_ENABLED").lower() ==
"true"
65def index() -> Annotated[str, "search page as a rendered template"]:
67 Renders the search page.
69 Response: The rendered HTML template for the search page.
71 return render_template(
"search.html")
74@app.route("/toggleLight")
75def toggle_light() -> Annotated[str, "search page as a rendered template"]:
77 Toggles the power state of the WLED device and renders the search template.
78 This function changes the power state of the WLED device to the opposite of its current state
79 by calling the `changePowerState` method of the `wled_requests` object.
80 After toggling the power state,
81 it returns the rendered "search.html" template.
83 str: The rendered "search.html" template.
86 return render_template(
"search.html")
89@app.route("/createItem")
90def create_item() -> Annotated[str, "item creation page as a rendered template"]:
92 Renders the template for creating a new item.
94 Response: The rendered HTML template for creating a new item.
96 return render_template(
"createItem.html")
99@app.route("/sendCreation", methods=["POST"])
100def send_creation() -> Annotated[tuple, {"status": str,
"status_code": int}]:
102 Handle the creation of a new item by processing the incoming JSON request data.
103 The function expects a JSON payload with the following structure:
110 It extracts the necessary information from the JSON payload and attempts to create a new item
111 using the Storage_connector.CreateItem method.
112 If an exception occurs during the creation process,
113 it prints the exception.
115 tuple: A dictionary with a status message and an HTTP status code.
118 data = request.get_json()
119 logger.info(f
"Received creation request with data: {data}")
120 info = json.dumps(data[
"info"])
121 obj_type = data[
"type"]
123 pos = data[
"position"]
126 pos=pos, obj_type=obj_type, name=name, json_data=info
128 except Exception
as e:
130 f
"Failed to create item with name: {name}, type: {obj_type}, position: {pos}. Error: {e}"
132 return {
"status":
"error"}, 500
133 return {
"status":
"created"}, 201
136@app.route("/item/<item_id>")
137def item(item_id) -> Annotated[str, "item page as a rendered template"]:
139 Handles the request to display an item.
140 This function performs the following steps:
141 1. Changes the power state of the WLED device to on.
142 2. Fetches the item details from the storage using the provided item identifier.
143 3. Sets the color position on the WLED device based on the fetched item details.
144 4. If the fetched item contains additional information,
145 it parses the data and renders the 'item.jinja2' template
146 with the item details and information.
147 6. If the fetched item does not contain additional information,
148 it renders the 'item.jinja2' template with only the item details.
150 item_id (int): The id of the item to display.
152 The rendered HTML template for the item.
157 logger.info(f
"Fetched item details for item_id {item_id}: {item_sql}")
159 json_info = json.loads(item_sql[4])
160 return render_template(
"item.jinja2", item=item_sql, json=json_info, id=item_id)
162 return render_template(
"item.jinja2", item=item_sql, id=item_id)
165@app.route("/item/<item_id>/update", methods=["POST"])
166def update_item(item_id) -> Annotated[tuple, {"status": str,
"status_code": int}]:
168 Updates an item using the Storage_connector and returns a status message.
170 item_id: The id of the item to be updated.
172 A dictionary with a status message and an HTTP status code.
174 data = request.get_json()
175 logger.info(f
"Received update request for item_id {item_id} with data: {data}")
176 info = json.dumps(data.get(
"info", {}))
177 obj_type = data.get(
"type")
178 name = data.get(
"name")
179 pos = data.get(
"position")
182 item_id=item_id, pos=pos, obj_type=obj_type, name=name, json_data=info
184 except Exception
as e:
185 logger.error(f
"Failed to update item with id: {item_id}. Error: {e}")
186 return {
"status":
"error"}, 500
187 return {
"status":
"updated"}, 200
190@app.route("/item/<item>/delete")
191def delete_item(item_id) -> Annotated[str, "search page as a rendered template"]:
193 Deletes an item using the Storage_connector and renders the search.html template.
195 item_id: The id of the item to be deleted.
197 A rendered template for the search page.
201 return render_template(
"search.html")
204@app.route("/search/<term>", methods=["GET"])
207 Search for a term in the storage and return the results in JSON format.
209 term (str): The term to search for in the storage.
211 Response: A Flask Response object containing the search results in JSON format.
217@app.errorhandler(Exception)
220 Handles exceptions by passing through HTTP errors.
222 e (Exception): The exception to handle.
224 Exception: The same exception that was passed in.
231@app.route("/config/env")
234 Retrieve the environment configuration.
235 This function uses the config_manager to get the current environment
236 configuration and returns it as a JSON response.
238 Response: A Flask JSON response containing the environment configuration.
243@app.route("/config/ollama/models")
246 Fetches the list of available Ollama models.
248 Annotated[str, "json response"]: A JSON response containing the list of Ollama models.
250 values = ollama.get_ollama_models()
252 return jsonify({
"status":
"Ollama service is not enabled"}), 412
253 return jsonify(values)
256@app.route("/wifiscale/weight")
259 Retrieve the weight of the scale.
260 This function checks if the scale service is enabled by reading the IS_SCALE_ENABLED environment variable.
261 If the scale service is not enabled, it returns a JSON response with a status message and HTTP status code 412.
262 If the scale service is enabled, it uses the wifiscale module to get the weight of the scale and returns it as a JSON response.
264 Response: A Flask JSON response containing the weight of the scale or a status message.
266 if IS_SCALE_ENABLED ==
"False":
267 return jsonify({
"status":
"scale service is not enabled"}), 412
269 weight = wifiscale.get_weight()
270 return jsonify({
"weight": weight})
273@app.route("/llm/ask", methods=["POST"])
276 Ask a question to the Language Learning Model (LLM) service.
277 This function sends a GET request to the LLM service at the specified endpoint
278 and returns the response as a JSON object.
280 Response: A Flask JSON response containing the response from the LLM service.
282 data = request.get_json()
283 question = data.get(
"question")
284 logger.info(f
"Received question via llm endpoint: {question}")
285 response = ollama.ask_question(question)
286 return jsonify(response)
289@app.route("/log", methods=["POST"])
290def log_message() -> Annotated[tuple, {"status": str,
"status_code": int}]:
292 Logs a message with a specified log level.
294 The log level and message content are extracted from the JSON payload of the request.
295 If the log level is not provided, it defaults to 'INFO'.
296 If the message content is not provided, it defaults to an empty string.
299 tuple: A dictionary with a status message and an HTTP status code 201.
301 Request JSON structure:
303 "level": "DEBUG" | "INFO" | "WARNING" | "ERROR" | "CRITICAL",
304 "message": "Your log message here"
308 data: Annotated[str,
"content of request"] = request.json
309 level: Annotated[str,
"log level, default value is INFO"] = data.get(
312 message: Annotated[str,
"content of log, default value is empty"] = data.get(
318 logger.debug(message)
322 logger.warning(message)
324 logger.error(message)
326 logger.critical(message)
328 return {
"status":
"created"}, 201
331with app.app_context():
335if __name__ ==
"__main__":
336 app.run(host=
"0.0.0.0", debug=
True)
Annotated[ list, "list of tuples containing the rows from the database that match the search criteria",] search(search_term)
None create_item(pos, obj_type, name, json_data)
None delete_item(item_id)
Annotated[tuple, "tuple containing the item's data if found, otherwise None"] fetch_item(item_id)
None update_item(item_id, pos, obj_type, name, json_data)
Response ask_llm_question()
Exception handle_exception(e)
Annotated[tuple, {"status":str, "status_code":int}] log_message()
Annotated[tuple, {"status":str, "status_code":int}] send_creation()
Annotated[tuple, {"status":str, "status_code":int}] update_item(item_id)
tuple[Response, int]|Response get_ollama_models()
Annotated[str, "item creation page as a rendered template"] create_item()
tuple[Response, int]|Response get_weight()
Annotated[str, "search page as a rendered template"] toggle_light()
Annotated[str, "search page as a rendered template"] delete_item(item_id)
Annotated[str, "item page as a rendered template"] item(item_id)
Annotated[str, "search page as a rendered template"] index()
Annotated[dict, "dictionary of environment variables"] get_env()
Annotated[bool, "True if power is on, false if power is off"] get_power_state()
None change_power_state(state)