
    Oj                        d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	m
Z
  e
e      j                         j                  j                  Zedz  Zej                   j#                  dd      Zej                   j#                  dd	      Zd
ZdZdddZddZda	 	 d	 	 	 ddZddZddZedk(  r ej:                   e              yy)u  Screen watcher — a local VLM watches the screen so Claude doesn't have to.

Ahmed: "watch my gameplay and tell me my mistakes." Sending frames to Claude
burns context fast; instead a SMALL local vision model (Qwen2.5-VL via
Ollama, running on the same GPU next to the game) analyzes a screenshot
every few seconds for free, accumulates observations, and when the watch
ends writes ONE summarized report to control/report.txt — which flows to
the master Jarvis through the normal worker-report channel, and he relays
it in his own words.

Standalone process (like hands.py), started/stopped by the engine via
control/watch.json:  {"on": true, "task": "spot mistakes in my Marvel
Rivals gameplay", "minutes": 5, "interval": 4}

Env: WATCH_MODEL (default qwen2.5vl:3b — ~3.2GB, fits beside a game on a
12GB card; use qwen2.5vl:7b when not gaming for sharper analysis),
OLLAMA_URL (default http://127.0.0.1:11434).
    )annotationsN)PathcontrolWATCH_MODELzqwen2.5vl:3b
OLLAMA_URLzhttp://127.0.0.1:11434zYou are watching {task}. This is one frame of the live screen. In 1-2 short sentences, note ONLY what matters for that task (mistakes, notable events, state changes). If nothing notable, reply exactly: nothing notable.a  You watched a screen over time for this task: {task}. Here are your timestamped frame notes:

{notes}

Write a single concise report (3-5 sentences, plain prose, no markdown) with the most useful observations and concrete advice. Skip frames that said nothing notable.c                   dd l }dd l}dd l}|j                         5 }|j                  |j                  d         }|j                  |      d d d d d df   }d d d        j                  d   | kD  rK| |j                  d   z  }|j                  || t        |j                  d   |z        f|j                        }|j                  d||j                  dg      \  }}	|st        d      |	j                         S # 1 sw Y   xY w)Nr         )interpolationz.jpgR   zjpeg encode failed)cv2mssnumpygrabmonitorsarrayshaperesizeint
INTER_AREAimencodeIMWRITE_JPEG_QUALITYRuntimeErrortobytes)
max_wr   r   npsctshotimgkokbufs
             ;/Users/ahmed/devFolder/Ultron/claude-voice/voice/watcher.py
_grab_jpegr$   1   s    	cxxQ(hhtnQ2A2X& 
 yy|eCIIaL jjuc#))A,*:&;<'*~~  7ll63)A)A2(FGGB/00;;= 
s   <C==Dc                     ddl } 	 | j                  g dddd      }t        |j                  j	                         j                         d         dz  S # t        $ r Y yw xY w)	z6Free GPU memory right now (0.0 when it can't be read).r   N)z
nvidia-smiz--query-gpu=memory.freez--format=csv,noheader,nounitsT   )capture_outputtexttimeoutg      @g        )
subprocessrunfloatstdoutstrip
splitlines	Exception)r*   outs     r#   _free_vram_gbr2   B   sh    nn.dA  7 SZZ%%'224Q786AA s   AA 	A A Fc                j   dd l }d| d}|(t        j                  |      j                  d      g|d<   ddi}t        rd|d<   dd l}t        j                  t        |gd	|j                  d
k(  rdnd|d      j                         }|j                  j                  t         d|ddi      }|j                  j                  ||      5 }	t        j                  |	j!                               }
d d d        
j#                  d      xs i j#                  dd      j%                         S # 1 sw Y   <xY w)Nr   user)rolecontentasciiimages
num_thread   num_gpuFdarwin3m30m)modelmessagesstream
keep_aliveoptionsz	/api/chatzContent-Typezapplication/json)dataheadersr)   messager6    )urllib.requestbase64	b64encodedecode	_CPU_ONLYsysjsondumpsMODELplatformencoderequestRequestOLLAMAurlopenloadsreadgetr.   )promptimager)   urllibmsgrC   _sysbodyreqrr1   s              r#   _ollama_chatrc   U   s%   F3C))%077@AH!1%G	 ::SEU"mmx7dU  vx	 	
 ..
 
 ()4!34 ! 6C 
		W		5jj" 
6GGI$")))R8>>@@ 
6	5s   
$D))D2c                    t         j                  d       t        t         dz  dd      5 }|j                  | j	                  dd      j                         dz          d	d	d	       y	# 1 sw Y   y	xY w)
u?   Append to control/report.txt — the master relays it to Ahmed.T)exist_okz
report.txtazutf-8)encoding
 N)CONTROLmkdiropenwritereplacer.   )linefs     r#   _reportrq   o   sT    MM4M 	g$cG	<	T3'--/$67 
=	<	<s   3A((A1c                    t         j                  j                  dd      } t        t         j                  j                  dd            }t        t         j                  j                  dd            }t         j                  j                  dd      d	k(  }t        t         j                  j                  d
d            }d}dgt        j
                  t        j                  fD ]  }	 t	        j                  |fd        t               }|dk  rRda	t        |d      }t        d|dd|ddd       	 dd l}|j                         j                  |j                         	 t!        dd       t        d t&         d!|  d"|dd#|dd$	d       g }
t)        j*                         |d%z  z   }t)        j*                         }d   r`t)        j*                         |k  rH	 t-               }t!        t.        j1                  | &      |      }t)        j*                         |z
  d'd(}|r}d)|j3                         vrk|
j5                  d*| d+|        t        d,| d+|d d-  d       |r<t)        j*                         |z
  |k\  r"t)        j*                         }t#        d.|        t)        j*                         |z   }d   rIt)        j*                         |k  r2t)        j6                  d1       d   rt)        j*                         |k  r2d   rt)        j*                         |k  rH	 |
rFt!        t8        j1                  | d2j;                  |
d3d        4      d      }t#        d5|  d6|        nt#        d5|  d7       t        d=d       y# t        $ r Y w xY w# t        $ r Y Fw xY w# t        $ r,}	t#        dt%        |	      d d  dt&         d       Y d }	~	yd }	~	ww xY w# t        $ r(}	t        d/t%        |	      d d%  d0d       Y d }	~	md }	~	ww xY w# t        $ r>}	t#        |
r'd8t%        |	      d d%  d9d:j;                  |
d;d        z   nd<       Y d }	~	d }	~	ww xY w)>N
WATCH_TASKz
the screenWATCH_MINUTES5WATCH_INTERVAL6
WATCH_LIVE01WATCH_LIVE_COOLDOWN25g    eTc                 (    j                  dd      S )Nr   F)__setitem__)_arunnings    r#   <lambda>zmain.<locals>.<lambda>   s    7+>+>q%+H    g      @g      (@zwatcher: GPU busy (z.1fu'   GB free) — CPU-only vision, interval z.0fzs, low priority)flushr   zReply with the word: readyx   rF   uJ   Screen watcher couldn't start — the local vision model isn't available (P   z). Is Ollama running with z pulled?r
   z	watcher: z watching 'z' every zs for m<   )taskz4.0fsznothing notable[z] z
watcher: [d   uK   [live screen watch — interject briefly if worth saying, else stay quiet] zwatcher: frame skipped ()g      ?rh   i)r   noteszScreen watch finished (z): z1): nothing notable happened while I was watching.z+Screen watch ended but summarizing failed (z); raw notes: z | z	no notes.zwatcher: done)osenvironrZ   r,   signalSIGTERMSIGINTr0   r2   rM   maxprintpsutilProcessniceBELOW_NORMAL_PRIORITY_CLASSrc   rq   strrQ   time	monotonicr$   FRAME_PROMPTformatlowerappendsleepSUMMARY_PROMPTjoin)r   minutesintervallivelive_cooldown	last_livesigfreer   er   t_endt0frameobsstamptargetsummaryr   s                     @r#   mainr   v   s:   ::>>,5DBJJNN?C89GRZZ^^$4c:;H ::>>,,3D"**..)>EFMIfG.	MM#HI / ?Dcz	x&#D: ."38?C	E	NN!!&"D"DE
13? 
IeWKvXhs^ DQ '+-ENNw|+E		B
!*)E1	ILE|222=uEC~~'*402E(		;qr#/0
5'CI;7tD DNN,y8MI $ 0I >>AUD E
 !H,ajT^^-6JJt ajT^^-6% !*)E1,">#8#85;!7 $9 $9BEGG-dV3wi@A-dV 45 6 7 
/&I  		   		   $$'F3BK=0J'# 	$ 	2  	I,SVCR[M;4HH	I   ;@ >c!fSbk] K !&E"#J!78	 	sn   )N8-N &N/ "CO' *AP 	NN	N,+N,/	O$8"OO$'	P0PP	Q"$4QQ"__main__)i   )r   r   returnbytes)r   r,   )Ng      N@)r[   r   r\   zbytes | Noner)   r,   r   r   )ro   r   r   None)r   r   )__doc__
__future__r   rJ   rO   r   r   rN   r   pathlibr   __file__resolveparentPROJECTrj   r   rZ   rQ   rV   r   r   r$   r2   rM   rc   rq   r   __name__exit r   r#   <module>r      s   & #   	  
  
x.
 
 
"
)
)
0
0
I



}n5	&>	?  "
  	 59"&AA+.A48Rj zCHHTV r   