mirror of
https://github.com/infinition/Bjorn.git
synced 2026-03-11 07:01:59 +00:00
Add RLUtils class for managing RL/AI dashboard endpoints
- Implemented methods for fetching AI stats, training history, and recent experiences. - Added functionality to set operation mode (MANUAL, AUTO, AI) with appropriate handling. - Included helper methods for querying the database and sending JSON responses. - Integrated model metadata extraction for visualization purposes.
This commit is contained in:
@@ -10,6 +10,85 @@ from logger import Logger
|
||||
|
||||
logger = Logger(name="image_utils.py", level=logging.DEBUG)
|
||||
|
||||
|
||||
# --- Multipart form helpers (replaces cgi module removed in Python 3.13) ---
|
||||
def _parse_header(line):
|
||||
parts = line.split(';')
|
||||
key = parts[0].strip()
|
||||
pdict = {}
|
||||
for p in parts[1:]:
|
||||
if '=' in p:
|
||||
k, v = p.strip().split('=', 1)
|
||||
pdict[k.strip()] = v.strip().strip('"')
|
||||
return key, pdict
|
||||
|
||||
|
||||
class _FormField:
|
||||
__slots__ = ('name', 'filename', 'file', 'value')
|
||||
def __init__(self, name, filename=None, data=b''):
|
||||
self.name = name
|
||||
self.filename = filename
|
||||
if filename:
|
||||
self.file = BytesIO(data)
|
||||
self.value = data
|
||||
else:
|
||||
self.value = data.decode('utf-8', errors='replace').strip()
|
||||
self.file = None
|
||||
|
||||
|
||||
class _MultipartForm:
|
||||
"""Minimal replacement for _MultipartForm."""
|
||||
def __init__(self, fp, headers, environ=None, keep_blank_values=False):
|
||||
import re as _re
|
||||
self._fields = {}
|
||||
ct = headers.get('Content-Type', '') if hasattr(headers, 'get') else ''
|
||||
_, params = _parse_header(ct)
|
||||
boundary = params.get('boundary', '').encode()
|
||||
if hasattr(fp, 'read'):
|
||||
cl = headers.get('Content-Length') if hasattr(headers, 'get') else None
|
||||
body = fp.read(int(cl)) if cl else fp.read()
|
||||
else:
|
||||
body = fp
|
||||
for part in body.split(b'--' + boundary)[1:]:
|
||||
part = part.strip(b'\r\n')
|
||||
if part == b'--' or not part:
|
||||
continue
|
||||
sep = b'\r\n\r\n' if b'\r\n\r\n' in part else b'\n\n'
|
||||
if sep not in part:
|
||||
continue
|
||||
hdr, data = part.split(sep, 1)
|
||||
hdr_s = hdr.decode('utf-8', errors='replace')
|
||||
nm = _re.search(r'name="([^"]*)"', hdr_s)
|
||||
fn = _re.search(r'filename="([^"]*)"', hdr_s)
|
||||
if not nm:
|
||||
continue
|
||||
name = nm.group(1)
|
||||
filename = fn.group(1) if fn else None
|
||||
field = _FormField(name, filename, data)
|
||||
if name in self._fields:
|
||||
existing = self._fields[name]
|
||||
if isinstance(existing, list):
|
||||
existing.append(field)
|
||||
else:
|
||||
self._fields[name] = [existing, field]
|
||||
else:
|
||||
self._fields[name] = field
|
||||
|
||||
def __contains__(self, key):
|
||||
return key in self._fields
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self._fields[key]
|
||||
|
||||
def getvalue(self, key, default=None):
|
||||
if key not in self._fields:
|
||||
return default
|
||||
f = self._fields[key]
|
||||
if isinstance(f, list):
|
||||
return [x.value for x in f]
|
||||
return f.value
|
||||
|
||||
|
||||
ALLOWED_IMAGE_EXTS = {'.bmp', '.png', '.jpg', '.jpeg', '.gif', '.ico', '.webp'}
|
||||
|
||||
class ImageUtils:
|
||||
@@ -149,12 +228,12 @@ class ImageUtils:
|
||||
|
||||
def upload_status_image(self, h):
|
||||
"""Add/replace <action>/<action>.bmp (always 28x28 BMP)."""
|
||||
import cgi
|
||||
|
||||
try:
|
||||
ctype, pdict = cgi.parse_header(h.headers.get('Content-Type'))
|
||||
ctype, pdict = _parse_header(h.headers.get('Content-Type'))
|
||||
if ctype != 'multipart/form-data': raise ValueError('Content-Type doit être multipart/form-data')
|
||||
pdict['boundary']=bytes(pdict['boundary'],'utf-8'); pdict['CONTENT-LENGTH']=int(h.headers.get('Content-Length'))
|
||||
form = cgi.FieldStorage(fp=BytesIO(h.rfile.read(pdict['CONTENT-LENGTH'])),
|
||||
form = _MultipartForm(fp=BytesIO(h.rfile.read(pdict['CONTENT-LENGTH'])),
|
||||
headers=h.headers, environ={'REQUEST_METHOD':'POST'}, keep_blank_values=True)
|
||||
for key in ('type','action_name','status_image'):
|
||||
if key not in form: raise ValueError(f'Missing field: {key}')
|
||||
@@ -179,12 +258,12 @@ class ImageUtils:
|
||||
except Exception as e: self.logger.error(e); self._err(h, str(e))
|
||||
|
||||
def upload_static_image(self, h):
|
||||
import cgi
|
||||
|
||||
try:
|
||||
ctype, pdict = cgi.parse_header(h.headers.get('Content-Type'))
|
||||
ctype, pdict = _parse_header(h.headers.get('Content-Type'))
|
||||
if ctype != 'multipart/form-data': raise ValueError('Content-Type must be multipart/form-data')
|
||||
pdict['boundary']=bytes(pdict['boundary'],'utf-8'); pdict['CONTENT-LENGTH']=int(h.headers.get('Content-Length'))
|
||||
form = cgi.FieldStorage(fp=BytesIO(h.rfile.read(pdict['CONTENT-LENGTH'])),
|
||||
form = _MultipartForm(fp=BytesIO(h.rfile.read(pdict['CONTENT-LENGTH'])),
|
||||
headers=h.headers, environ={'REQUEST_METHOD':'POST'}, keep_blank_values=True)
|
||||
if 'static_image' not in form or not getattr(form['static_image'],'filename',''): raise ValueError('No static_image provided')
|
||||
filename = self._safe(form['static_image'].filename); base, _ = os.path.splitext(filename); filename = base + '.bmp'
|
||||
@@ -216,12 +295,12 @@ class ImageUtils:
|
||||
except Exception as e: self.logger.error(e); self._err(h, str(e))
|
||||
|
||||
def upload_web_image(self, h):
|
||||
import cgi
|
||||
|
||||
try:
|
||||
ctype, pdict = cgi.parse_header(h.headers.get('Content-Type'))
|
||||
ctype, pdict = _parse_header(h.headers.get('Content-Type'))
|
||||
if ctype != 'multipart/form-data': raise ValueError('Content-Type doit être multipart/form-data')
|
||||
pdict['boundary']=bytes(pdict['boundary'],'utf-8'); pdict['CONTENT-LENGTH']=int(h.headers.get('Content-Length'))
|
||||
form = cgi.FieldStorage(fp=BytesIO(h.rfile.read(pdict['CONTENT-LENGTH'])),
|
||||
form = _MultipartForm(fp=BytesIO(h.rfile.read(pdict['CONTENT-LENGTH'])),
|
||||
headers=h.headers, environ={'REQUEST_METHOD':'POST'}, keep_blank_values=True)
|
||||
if 'web_image' not in form or not getattr(form['web_image'],'filename',''): raise ValueError('Aucun fichier web_image fourni')
|
||||
file_item = form['web_image']; filename = self._safe(file_item.filename)
|
||||
@@ -250,12 +329,12 @@ class ImageUtils:
|
||||
except Exception as e: self.logger.error(e); self._err(h, str(e))
|
||||
|
||||
def upload_actions_icon(self, h):
|
||||
import cgi
|
||||
|
||||
try:
|
||||
ctype, pdict = cgi.parse_header(h.headers.get('Content-Type'))
|
||||
ctype, pdict = _parse_header(h.headers.get('Content-Type'))
|
||||
if ctype != 'multipart/form-data': raise ValueError('Content-Type doit être multipart/form-data')
|
||||
pdict['boundary']=bytes(pdict['boundary'],'utf-8'); pdict['CONTENT-LENGTH']=int(h.headers.get('Content-Length'))
|
||||
form = cgi.FieldStorage(fp=BytesIO(h.rfile.read(pdict['CONTENT-LENGTH'])),
|
||||
form = _MultipartForm(fp=BytesIO(h.rfile.read(pdict['CONTENT-LENGTH'])),
|
||||
headers=h.headers, environ={'REQUEST_METHOD':'POST'}, keep_blank_values=True)
|
||||
if 'icon_image' not in form or not getattr(form['icon_image'],'filename',''): raise ValueError('Aucun fichier icon_image fourni')
|
||||
file_item = form['icon_image']; filename = self._safe(file_item.filename)
|
||||
@@ -315,12 +394,12 @@ class ImageUtils:
|
||||
|
||||
def replace_image(self, h):
|
||||
"""Replace image. For type='action': status icon here; character images delegated to CharacterUtils."""
|
||||
import cgi
|
||||
|
||||
try:
|
||||
ctype, pdict = cgi.parse_header(h.headers.get('Content-Type'))
|
||||
ctype, pdict = _parse_header(h.headers.get('Content-Type'))
|
||||
if ctype != 'multipart/form-data': raise ValueError('Content-Type must be multipart/form-data')
|
||||
pdict['boundary']=bytes(pdict['boundary'],'utf-8'); pdict['CONTENT-LENGTH']=int(h.headers.get('Content-Length'))
|
||||
form = cgi.FieldStorage(fp=BytesIO(h.rfile.read(pdict['CONTENT-LENGTH'])),
|
||||
form = _MultipartForm(fp=BytesIO(h.rfile.read(pdict['CONTENT-LENGTH'])),
|
||||
headers=h.headers, environ={'REQUEST_METHOD':'POST'}, keep_blank_values=True)
|
||||
tp = form.getvalue('type'); image_name = self._safe(form.getvalue('image_name') or '')
|
||||
file_item = form['new_image'] if 'new_image' in form else None
|
||||
|
||||
Reference in New Issue
Block a user