Added Live Screenshot data functionality
This commit is contained in:
parent
17b99ca836
commit
0c16b74b49
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
.vs/
|
.vs/
|
||||||
|
Borealis-Workflow-Automation-Tool/
|
@ -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):
|
||||||
"""
|
"""
|
||||||
|
@ -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()
|
||||||
|
@ -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)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user