Added Live Screenshot data functionality
This commit is contained in:
		
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1 +1,2 @@ | ||||
| .vs/ | ||||
| .vs/ | ||||
| Borealis-Workflow-Automation-Tool/ | ||||
| @@ -35,7 +35,6 @@ regions = {} | ||||
|  | ||||
| app_instance = None | ||||
|  | ||||
|  | ||||
| def _ensure_qapplication(): | ||||
|     """ | ||||
|     Ensures that QApplication is initialized before creating widgets. | ||||
| @@ -45,6 +44,15 @@ def _ensure_qapplication(): | ||||
|     if app_instance is None: | ||||
|         app_instance = QApplication(sys.argv)  # Start in main thread | ||||
|  | ||||
| def capture_region_as_image(region_id): | ||||
|     collector_mutex.lock() | ||||
|     if region_id not in regions: | ||||
|         collector_mutex.unlock() | ||||
|         return None | ||||
|     x, y, w, h = regions[region_id]['bbox'][:] | ||||
|     collector_mutex.unlock() | ||||
|     screenshot = ImageGrab.grab(bbox=(x, y, x + w, y + h)) | ||||
|     return screenshot | ||||
|  | ||||
| def create_ocr_region(region_id, x=250, y=50, w=DEFAULT_WIDTH, h=DEFAULT_HEIGHT, color=(255, 255, 0), thickness=2): | ||||
|     """ | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| # Modules/data_manager.py | ||||
| import threading | ||||
| import time | ||||
| from flask import Flask, jsonify | ||||
| import base64 | ||||
| from flask import Flask, jsonify, Response | ||||
| from PyQt5.QtCore import QMutex | ||||
|  | ||||
| # Global datastore for character metrics | ||||
| @@ -21,6 +21,9 @@ data_mutex = QMutex() | ||||
| # Flag to ensure only one character status collector node exists | ||||
| character_status_collector_exists = False | ||||
|  | ||||
| # A place to store the screenshot in base64 | ||||
| status_screenshot_base64 = "" | ||||
|  | ||||
| # Flask Application | ||||
| app = Flask(__name__) | ||||
|  | ||||
| @@ -68,6 +71,47 @@ def fp_api(): | ||||
|         "fp_total": get_data()["fp_total"] | ||||
|     }) | ||||
|  | ||||
| @app.route('/status_screenshot') | ||||
| def status_screenshot(): | ||||
|     """ | ||||
|     Returns an HTML page that displays the stored screenshot and | ||||
|     automatically refreshes it every second without requiring a manual page reload. | ||||
|     """ | ||||
|     html = """ | ||||
|     <html> | ||||
|     <head> | ||||
|         <title>Live Flyff Character Status</title> | ||||
|         <script> | ||||
|             // Reload the <img> every second | ||||
|             setInterval(function(){ | ||||
|                 var img = document.getElementById('status_img'); | ||||
|                 img.src = '/status_screenshot_data?random=' + Math.random(); | ||||
|             }, 1000); | ||||
|         </script> | ||||
|     </head> | ||||
|     <body> | ||||
|         <img id="status_img" src="/status_screenshot_data" /> | ||||
|     </body> | ||||
|     </html> | ||||
|     """ | ||||
|     return html | ||||
|  | ||||
| @app.route('/status_screenshot_data') | ||||
| def status_screenshot_data(): | ||||
|     """ | ||||
|     Serves the raw PNG bytes (decoded from base64) used by <img> in /status_screenshot. | ||||
|     """ | ||||
|     data_mutex.lock() | ||||
|     encoded = status_screenshot_base64 | ||||
|     data_mutex.unlock() | ||||
|  | ||||
|     if not encoded: | ||||
|         # No image captured yet, return HTTP 204 "No Content" | ||||
|         return "", 204 | ||||
|  | ||||
|     raw_img = base64.b64decode(encoded) | ||||
|     return Response(raw_img, mimetype='image/png') | ||||
|  | ||||
| def start_api_server(): | ||||
|     """ | ||||
|     Starts the Flask API server in a separate daemon thread. | ||||
| @@ -101,3 +145,12 @@ def set_data_bulk(metrics_dict): | ||||
|     data_mutex.lock() | ||||
|     data_store.update(metrics_dict) | ||||
|     data_mutex.unlock() | ||||
|  | ||||
| def set_status_screenshot(encoded_str): | ||||
|     """ | ||||
|     Called by the OCR node to store the base64-encoded screenshot data. | ||||
|     """ | ||||
|     global status_screenshot_base64 | ||||
|     data_mutex.lock() | ||||
|     status_screenshot_base64 = encoded_str | ||||
|     data_mutex.unlock() | ||||
|   | ||||
| @@ -3,12 +3,19 @@ | ||||
| Flyff Character Status Node: | ||||
| - Creates an OCR region in data_collector. | ||||
| - Periodically grabs raw text from that region and updates status. | ||||
| - ALSO: Captures a screenshot from the same region, converts to base64, | ||||
|         and updates data_manager so the Flask server can serve it. | ||||
| """ | ||||
|  | ||||
| import re | ||||
| import base64 | ||||
| from io import BytesIO | ||||
|  | ||||
| from OdenGraphQt import BaseNode | ||||
| from PyQt5.QtWidgets import QMessageBox | ||||
| from PyQt5.QtCore import QTimer  # Corrected import | ||||
|  | ||||
| # Import the existing modules | ||||
| from Modules import data_manager, data_collector | ||||
|  | ||||
| class FlyffCharacterStatusNode(BaseNode): | ||||
| @@ -29,7 +36,10 @@ class FlyffCharacterStatusNode(BaseNode): | ||||
|         self.add_text_input("exp", "EXP", text="EXP: 0%") | ||||
|  | ||||
|         self.region_id = "character_status" | ||||
|         data_collector.create_ocr_region(self.region_id, x=250, y=50, w=180, h=130, color=(255, 255, 0), thickness=2) | ||||
|         data_collector.create_ocr_region( | ||||
|             self.region_id, x=250, y=50, w=180, h=130, | ||||
|             color=(255, 255, 0), thickness=2 | ||||
|         ) | ||||
|  | ||||
|         data_collector.start_collector() | ||||
|         self.set_name("Flyff - Character Status") | ||||
| @@ -80,14 +90,14 @@ class FlyffCharacterStatusNode(BaseNode): | ||||
|  | ||||
|     def process_input(self): | ||||
|         """ | ||||
|         Called periodically to update character status from OCR. | ||||
|         Called periodically to update character status from OCR, | ||||
|         and also capture the screenshot to display via Flask. | ||||
|         """ | ||||
|         # 1) Update the text-based status (same as before). | ||||
|         raw_text = data_collector.get_raw_text(self.region_id) | ||||
| #        print("Raw OCR Text:", raw_text)  # Debugging OCR text reading | ||||
|  | ||||
|         hp_c, hp_t, mp_c, mp_t, fp_c, fp_t, exp_v = self.parse_character_stats(raw_text) | ||||
|  | ||||
|         # Update the data manager with the parsed values | ||||
|         # Update data_manager with the parsed values | ||||
|         data_manager.set_data_bulk({ | ||||
|             "hp_current": hp_c, | ||||
|             "hp_total": hp_t, | ||||
| @@ -103,3 +113,12 @@ class FlyffCharacterStatusNode(BaseNode): | ||||
|         self.set_property("mp", f"MP: {mp_c}/{mp_t}") | ||||
|         self.set_property("fp", f"FP: {fp_c}/{fp_t}") | ||||
|         self.set_property("exp", f"EXP: {exp_v}%") | ||||
|  | ||||
|         # 2) Capture the screenshot used by OCR and store as base64 | ||||
|         screenshot_img = data_collector.capture_region_as_image(self.region_id) | ||||
|         if screenshot_img: | ||||
|             # Convert PIL image to base64 | ||||
|             buf = BytesIO() | ||||
|             screenshot_img.save(buf, format='PNG') | ||||
|             image_b64 = base64.b64encode(buf.getvalue()).decode('utf-8') | ||||
|             data_manager.set_status_screenshot(image_b64) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user