Added Live Screenshot data functionality

This commit is contained in:
Nicole Rappe 2025-03-05 21:01:35 -07:00
parent 17b99ca836
commit 0c16b74b49
4 changed files with 90 additions and 9 deletions

3
.gitignore vendored
View File

@ -1 +1,2 @@
.vs/ .vs/
Borealis-Workflow-Automation-Tool/

View File

@ -35,7 +35,6 @@ regions = {}
app_instance = None app_instance = None
def _ensure_qapplication(): def _ensure_qapplication():
""" """
Ensures that QApplication is initialized before creating widgets. Ensures that QApplication is initialized before creating widgets.
@ -45,6 +44,15 @@ def _ensure_qapplication():
if app_instance is None: if app_instance is None:
app_instance = QApplication(sys.argv) # Start in main thread 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): def create_ocr_region(region_id, x=250, y=50, w=DEFAULT_WIDTH, h=DEFAULT_HEIGHT, color=(255, 255, 0), thickness=2):
""" """

View File

@ -1,7 +1,7 @@
# Modules/data_manager.py
import threading import threading
import time import time
from flask import Flask, jsonify import base64
from flask import Flask, jsonify, Response
from PyQt5.QtCore import QMutex from PyQt5.QtCore import QMutex
# Global datastore for character metrics # Global datastore for character metrics
@ -21,6 +21,9 @@ data_mutex = QMutex()
# Flag to ensure only one character status collector node exists # Flag to ensure only one character status collector node exists
character_status_collector_exists = False character_status_collector_exists = False
# A place to store the screenshot in base64
status_screenshot_base64 = ""
# Flask Application # Flask Application
app = Flask(__name__) app = Flask(__name__)
@ -68,6 +71,47 @@ def fp_api():
"fp_total": get_data()["fp_total"] "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(): def start_api_server():
""" """
Starts the Flask API server in a separate daemon thread. Starts the Flask API server in a separate daemon thread.
@ -101,3 +145,12 @@ def set_data_bulk(metrics_dict):
data_mutex.lock() data_mutex.lock()
data_store.update(metrics_dict) data_store.update(metrics_dict)
data_mutex.unlock() 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()

View File

@ -3,12 +3,19 @@
Flyff Character Status Node: Flyff Character Status Node:
- Creates an OCR region in data_collector. - Creates an OCR region in data_collector.
- Periodically grabs raw text from that region and updates status. - 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 re
import base64
from io import BytesIO
from OdenGraphQt import BaseNode from OdenGraphQt import BaseNode
from PyQt5.QtWidgets import QMessageBox from PyQt5.QtWidgets import QMessageBox
from PyQt5.QtCore import QTimer # Corrected import from PyQt5.QtCore import QTimer # Corrected import
# Import the existing modules
from Modules import data_manager, data_collector from Modules import data_manager, data_collector
class FlyffCharacterStatusNode(BaseNode): class FlyffCharacterStatusNode(BaseNode):
@ -29,7 +36,10 @@ class FlyffCharacterStatusNode(BaseNode):
self.add_text_input("exp", "EXP", text="EXP: 0%") self.add_text_input("exp", "EXP", text="EXP: 0%")
self.region_id = "character_status" 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() data_collector.start_collector()
self.set_name("Flyff - Character Status") self.set_name("Flyff - Character Status")
@ -80,14 +90,14 @@ class FlyffCharacterStatusNode(BaseNode):
def process_input(self): 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) 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) 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({ data_manager.set_data_bulk({
"hp_current": hp_c, "hp_current": hp_c,
"hp_total": hp_t, "hp_total": hp_t,
@ -103,3 +113,12 @@ class FlyffCharacterStatusNode(BaseNode):
self.set_property("mp", f"MP: {mp_c}/{mp_t}") self.set_property("mp", f"MP: {mp_c}/{mp_t}")
self.set_property("fp", f"FP: {fp_c}/{fp_t}") self.set_property("fp", f"FP: {fp_c}/{fp_t}")
self.set_property("exp", f"EXP: {exp_v}%") 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)