simplyprint: bring up AI stream to correct state

Signed-off-by:  Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
Eric Callahan 2022-10-10 17:19:21 -04:00
parent 6e121c2221
commit 785213b2b3
No known key found for this signature in database
GPG Key ID: 5A1EB336DFB4C71B
1 changed files with 68 additions and 41 deletions

View File

@ -77,7 +77,6 @@ class SimplyPrint(Subscribable):
self.amb_detect = AmbientDetect(config, self, ambient)
self.layer_detect = LayerDetect()
self.webcam_stream = WebcamStream(config, self)
self.ai_stream = AIStream(config, self)
self.print_handler = PrintHandler(self)
self.last_received_temps: Dict[str, float] = {}
self.last_err_log_time: float = 0.
@ -434,15 +433,11 @@ class SimplyPrint(Subscribable):
self.connect_url = f"{ep}/{printer_id}/{token}"
def _update_intervals(self, intervals: Dict[str, Any]) -> None:
prev_ai = self.intervals.get("ai", 0.)
for key, val in intervals.items():
self.intervals[key] = val / 1000.
cur_ai = self.intervals.get("ai", prev_ai)
if abs(prev_ai - cur_ai) > 1e-8:
if abs(cur_ai) < 1e-8:
self.ai_stream.stop()
else:
self.ai_stream.start(cur_ai)
cur_ai_interval = self.intervals.get("ai", 0.)
if not cur_ai_interval:
self.webcam_stream.stop_ai()
logging.debug(f"Intervals Updated: {self.intervals}")
async def _announce_setup(self, short_id: str) -> None:
@ -673,6 +668,8 @@ class SimplyPrint(Subscribable):
job_info["started"] = True
self.layer_detect.start(metadata)
self._send_job_event(job_info)
self.webcam_stream.reset_ai_scores()
self.webcam_stream.start_ai(120.)
def _check_job_started(
self,
@ -700,10 +697,13 @@ class SimplyPrint(Subscribable):
self.send_sp("job_info", {"paused": True})
self._update_state("paused")
self.layer_detect.stop()
self.webcam_stream.stop_ai()
def _on_print_resumed(self, *args) -> None:
self._update_state("printing")
self.layer_detect.resume()
self.webcam_stream.reset_ai_scores()
self.webcam_stream.start_ai(self.intervals["ai"])
def _on_print_cancelled(self, *args) -> None:
self._check_job_started(*args)
@ -712,6 +712,7 @@ class SimplyPrint(Subscribable):
self._update_state_from_klippy()
self.cache.job_info = {}
self.layer_detect.stop()
self.webcam_stream.stop_ai()
def _on_print_error(self, *args) -> None:
self._check_job_started(*args)
@ -724,6 +725,7 @@ class SimplyPrint(Subscribable):
self._update_state_from_klippy()
self.cache.job_info = {}
self.layer_detect.stop()
self.webcam_stream.stop_ai()
def _on_print_complete(self, *args) -> None:
self._check_job_started(*args)
@ -732,11 +734,13 @@ class SimplyPrint(Subscribable):
self._update_state_from_klippy()
self.cache.job_info = {}
self.layer_detect.stop()
self.webcam_stream.stop_ai()
def _on_print_standby(self, *args) -> None:
self._update_state_from_klippy()
self.cache.job_info = {}
self.layer_detect.stop()
self.webcam_stream.stop_ai()
def _on_pause_requested(self) -> None:
self._print_request_event.set()
@ -1088,7 +1092,7 @@ class SimplyPrint(Subscribable):
async def close(self):
self.print_handler.cancel()
self.webcam_stream.stop()
self.webcam_stream.stop_ai()
self.amb_detect.stop()
self.printer_info_timer.stop()
self.ping_sp_timer.stop()
@ -1268,6 +1272,7 @@ class LayerDetect:
# go through the reverse proxy
FALLBACK_URL = "http://127.0.0.1:8080/?action=snapshot"
SP_SNAPSHOT_URL = "https://apirewrite.simplyprint.io/jobs/ReceiveSnapshot"
SP_AI_URL = "https://ai.simplyprint.io/api/v2/infer"
class WebcamStream:
def __init__(
@ -1281,6 +1286,10 @@ class WebcamStream:
self.client: HttpClient = self.server.lookup_component("http_client")
self.cam: Optional[WebCam] = None
self._connected = False
self.ai_running = False
self.ai_task: Optional[asyncio.Task] = None
self.ai_scores: List[Any] = []
self.failed_ai_attempts = 0
@property
def connected(self) -> bool:
@ -1354,55 +1363,73 @@ class WebcamStream:
except Exception as e:
if not self.server.is_debug_enabled():
return
logging.exception(f"SimplyPrint WebCam Stream Error")
logging.exception("SimplyPrint WebCam Stream Error")
class AIStream(WebcamStream):
ai_url = "https://ai.simplyprint.io/api/v2/infer"
def __init__(self, config: ConfigHelper, simplyprint: SimplyPrint) -> None:
super().__init__(config, simplyprint)
self.running = False
self.interval: float = 1.
self.stream_task: Optional[asyncio.Task] = None
async def _send_image(self, base_image: str) -> None:
token = self.simplyprint.sp_info["printer_token"]
async def _send_ai_image(self, base_image: str) -> None:
interval = self.simplyprint.intervals["ai"]
headers = {"User-Agent": "Mozilla/5.0"}
data = {
"api_key": token,
"api_key": self.simplyprint.sp_info["printer_token"],
"image_array": base_image,
"interval": self.interval
"interval": interval,
"printer_id": self.simplyprint.sp_info["printer_id"],
"settings": {
"buffer_percent": 80,
"confidence": 60,
"buffer_length": 16
},
"scores": self.ai_scores
}
resp = await self.client.post(
self.ai_url, body=data, headers=headers, enable_cache=False
SP_AI_URL, body=data, headers=headers, enable_cache=False
)
resp.raise_for_status()
self.failed_ai_attempts = 0
resp_json = resp.json()
if isinstance(resp_json, dict):
self.ai_scores = resp_json.get("scores", self.ai_scores)
ai_result = resp_json.get("s1", [0, 0, 0])
self.simplyprint.send_sp("ai_resp", {"ai": ai_result})
async def _stream(self) -> None:
while self.running:
async def _ai_stream(self, delay: float) -> None:
if delay:
await asyncio.sleep(delay)
while self.ai_running:
interval = self.simplyprint.intervals["ai"]
try:
img = await self.extract_image()
await self._send_image(img)
await self._send_ai_image(img)
except asyncio.CancelledError:
raise
except Exception:
logging.exception(f"SimplyPrint AI Stream Error")
self.failed_ai_attempts += 1
if self.failed_ai_attempts == 1:
logging.exception("SimplyPrint AI Stream Error")
elif not self.failed_ai_attempts % 10:
logging.info(
f"SimplyPrint: {self.failed_ai_attempts} consecutive "
"AI failures"
)
delay = min(120., self.failed_ai_attempts * 5.0)
interval = self.simplyprint.intervals["ai"] + delay
await asyncio.sleep(interval)
def start(self, interval: float) -> None:
if self.running:
if interval == self.interval:
return
self.stop()
self.interval = interval
self.running = True
self.stream_task = self.eventloop.create_task(self._stream())
def reset_ai_scores(self):
self.ai_scores = []
def stop(self) -> None:
if not self.running:
def start_ai(self, delay: float = 0) -> None:
if self.ai_running:
self.stop_ai()
self.ai_running = True
self.ai_task = self.eventloop.create_task(self._ai_stream(delay))
def stop_ai(self) -> None:
if not self.ai_running:
return
self.running = False
if self.stream_task is not None:
self.stream_task.cancel()
self.stream_task = None
self.ai_running = False
if self.ai_task is not None:
self.ai_task.cancel()
self.ai_task = None
class PrintHandler:
def __init__(self, simplyprint: SimplyPrint) -> None: