
    q%jv                    ,   d Z ddlmZ ddlZddlZddlmZmZmZmZ ddl	m
Z
 ddlmZ ddlmZ ddlmZ dd	lmZ dd
lmZ ddlmZ  ej.                  d      Z e ed            Zd ZddZddZddZddZddZddZ ddZ!ddZ"ddZ#d Z$d Z%y)u  
排程服務(階段 8):每分鐘 tick,跑三件事:
  1. 整點時:檢查任務逾期 / 今天到期 → ping 對應的人(B)
  2. 09:00 Asia/Taipei:每個綁定 LINE 的人收到個人化簡報(C-1)
  3. 18:00 Asia/Taipei:推團隊 wrap-up 到群組(C-2)

設計:
  - 純 asyncio loop,沒有外部依賴(APScheduler / cron)
  - 失敗只 log,不影響其他 tick
  - 「同一事件同一天最多跑一次」用 AgentActivity 表去重
  - 完整跑 = 寫一筆 'task_ping' / 'brief_pushed' / 'wrap_pushed' activity
    )annotationsN)datedatetime	timedeltatimezone)UUID)select)settings)AsyncSessionLocal)AgentActivity)Task)Userzcoba.scheduler   )hoursc                 &  K   t         j                  d       d} d}d}	 	 t        j                  d       d{    t	        j
                  t              }|j                         }|j                  dk(  r>|j                  dk  r/| |k7  r*t         j                  d       	 t                d{    |} |j                  dk(  r>|j                  dk  r/||k7  r*t         j                  d	       	 t                d{    |}|j                  dk(  r>|j                  dk  r/||k7  r*t         j                  d       	 t                d{    |}07 7 # t        $ r t         j                  d       Y w xY w7 ~# t        $ r t         j                  d
       Y w xY w7 W# t        $ r t         j                  d       Y uw xY w# t        j                  $ r t         j                  d       Y yt        $ r t         j                  d       Y w xY ww)u  每 60 秒 tick 一次。

    階段 9-K(Robert 簡化):
      只保留兩個自動推送,全部進「群組」(管理者看得到):
        1. 08:00  早晨「逾期任務 ping」(@相關人員)
        2. 22:00  晚間「今日完成公告 + 進度%」
      取消所有 1對1 私訊推送(老闆看不到 → 沒管理價值)。
      暫關週六/月底覆盤,等 Robert 開再啟用。
    uW   scheduler_loop 啟動 — 模式:群組 only(8:00 逾期 + 21:00 進度 + 22:00 完成)N<   r      z&[scheduler] morning overdue group-pingzmorning overdue ping failed   z![scheduler] evening progress pingzevening progress ping failed   z+[scheduler] evening completion announcementzevening recap failedu#   scheduler_loop 收到 cancel,退出u)   scheduler tick 例外(繼續下一分鐘))loggerinfoasynciosleepr   nowTPEr   hourminute_run_morning_overdue_group_ping	Exception	exception_run_evening_progress_ping$_run_evening_completion_announcementCancelledError)last_morning_overduelast_evening_progresslast_evening_recapr   todays        :/volume1/homes/robertsu/coba/app/app/services/scheduler.pyscheduler_loopr)   %   s     KKij(,)-&*
$	J--###,,s#CHHJE xx1}a4HE4QDED9;;; (-$ xx2~#**q.5Je5S?@E4666 ).% xx2~#**q.5G55PIJ=>@@@ &+"? # <  D$$%BCD 7  E$$%CDE A  =$$%;<= %% 	KK=> 	JHI	Js   HG EA%G E ,E-E 1:G ,E: 9E8:E: >:G 9F  FF  G HG E E52G 4E55G 8E: :FG FG F   G>G  GG (H,H.HHHHc                 ^	  K   ddl m}  ddlm} t	        j
                  t              j                         }t               4 d{   }|j                  t        t              j                  t        j                  j                  d      t        j                  j!                  g d      t        j"                  j%                  d      t        j"                  |k               d{   j'                         j)                         }|s't*        j-                  d       	 ddd      d{    yi }t/               }|D ]Q  }|j0                  xs |j2                  }|s |j5                  |       |j7                  |g       j9                  |       S |s	 ddd      d{    yi }	|r|j                  t        t:              j                  t:        j<                  j!                  |                   d{   j'                         j)                         }
|
D ci c]  }|j<                  | }	}|j                  t        |      j                  |j>                  dk(  |j                  j                  d                   d{   j'                         j)                         }ddd      d{    st*        j-                  d       yd	g}d}jA                         D ]  \  }}	jC                  |      }|r|jD                  nd
}|j9                  d|        |D ]]  }||j"                  z
  jF                  }|j9                  d|jH                   d|j"                  jK                          d| d       |dz  }_  |j9                  d       djM                  |      }|D ]  }|jN                  s| jQ                  |jN                  |       d{   }|s7t               4 d{   }|j5                  tS        dd| dtU        |       d|jV                  |tU        |      d             |jY                          d{    ddd      d{     y7 7 |7 ;7 7 tc c}w 7 7 # 1 d{  7  sw Y   xY w7 7 7 K7 =# 1 d{  7  sw Y   xY ww)u  08:00 推群組,公告所有逾期未完成任務 + 點名 assignee。

    格式:
      ☀️ 早安,以下是逾期任務需要回報:

      神狙手阿綠
        • 《X》(原訂 5/7,已逾期 1 天)
        • 《Y》(原訂 5/5,已逾期 3 天)

      Jonina🕊️
        • 《Z》(原訂 5/6,已逾期 2 天)

      請各自回報目前狀況。沒人逾期就不推。
    r   line_clientChannelNtodoin_progressreviewu%   [morning ping] 沒逾期任務,不推groupu$   [morning ping] 沒 LINE 群組可推u1   ☀️ 早安,以下是逾期任務需要回報:
   (未知)
	     • 《u   》(原訂 u   ,已逾期 u    天)   uy   
請各自回報目前狀況(回「庫柏 X 任務完成」我幫你改 / 「庫柏 X 延到 Y/Z」我幫你改截止)。morning_overdue_pingu   早晨逾期 ping 推群(    件,    人)channel_name
task_count
user_countactivity_typesummaryextra)-app.servicesr,   app.models.channelr.   r   r   r   r   r   executer	   r   where
deleted_atis_statusin_due_dateis_notscalarsallr   r   setassignee_id
created_byadd
setdefaultappendr   idline_source_typeitemsgetdisplay_namedaystitle	isoformatjoinline_source_id	push_textr   lennamecommit)r,   r.   r'   dbtasksgroups_by_userusers_neededtuid	users_mapusuchanslinestotal_counttsra   	days_latetextchoks                        r(   r   r   a   s     )*LL""$E ""bzz4L##D) AB$$T*%	
 
 79SSU 	 KK?@ #""   "uA--/1<<CS!%%c2.55a8  3 #""6 	

6$<#5#5dggkk,6O#PQQZZ\``bB*,-"Qq"I- zz7O!!((G3""&&t,
 

 79SSU 	C #"P :; BBEK!'')RMM#!"q~~
r$[!A+11ILL9QWWI[9M9M9O8PP[\e[ffklm1K 	 * 
LL  N  P99UD  (():):DAA(**b}"87}E#nJ]I^^cd(*&1&).&9  iik!! +** w #
 #": R-
C #"""| B* " +***s8  AR-QR-BQ9&Q"'8Q9R-*Q%+R-0A%Q9R- Q(!R-&AQ97Q+8$Q9Q.0AQ9Q3 Q9&R-1Q62D#R-RR-R-+R,R-/ARRRR-RR-"Q9%R-(R-+Q9.Q96R-9R?R R	R-R-RR-R*	R R*	%R-c                   K   ddl m}  ddlm} t	        j
                  t              j                         }t               4 d{   }|j                  t        t              j                  t        j                  j                  d      t        j                  j!                  g d      t        j"                  |k(               d{   j%                         j'                         }|s't(        j+                  d       	 ddd      d{    yi }t-               }|D ]Q  }|j.                  xs |j0                  }|s |j3                  |       |j5                  |g       j7                  |       S |s	 ddd      d{    yi }	|r|j                  t        t8              j                  t8        j:                  j!                  |                   d{   j%                         j'                         }
|
D ci c]  }|j:                  | }	}|j                  t        |      j                  |j<                  dk(  |j                  j                  d                   d{   j%                         j'                         }ddd      d{    st(        j+                  d       yd	g}d}j?                         D ]e  \  }}	jA                  |      }|r|jB                  nd
}|j7                  d|        |D ]&  }|j7                  d|jD                   d       |dz  }( g |j7                  d       djG                  |      }|D ]  }|jH                  s| jK                  |jH                  |       d{   }|s7t               4 d{   }|j3                  tM        dd| dtO        |       d|jP                  |tO        |      d             |jS                          d{    ddd      d{     y7 7 E7 7 7 =c c}w 7 7 # 1 d{  7  sw Y   xY w7 7 7 K7 =# 1 d{  7  sw Y   xY ww)u  階段 10-I:21:00 推群組,@ 今天 due 還沒完成的人,問進度。

    跟 08:00 的差別:
      - 08:00 ping「逾期」(due < today,過期未做)
      - 21:00 ping「今天還沒完成」(due == today,當天還沒做完)

    沒人有今天 due 未完成 → 不推。
    r   r+   r-   Nr/   u7   [evening progress ping] 今天沒待完成任務,不推r3   u-   [evening progress ping] 沒 LINE 群組可推uA   🌆 晚上 9 點,今天還沒完成的任務確認一下進度:
r4   z
@r6      》r7   u   
各位回報一下今天有沒有做完 —
完成的回「庫柏 X 完成」,我幫你標 done。
做不完延期回「庫柏 X 延到 Y/Z」,我幫你改截止日。r5   evening_progress_pingu   晚間 9 點進度 ping(r9   r:   r;   r?   )*rC   r,   rD   r.   r   r   r   r   r   rE   r	   r   rF   rG   rH   rI   rJ   rK   rM   rN   r   r   rO   rP   rQ   rR   rS   rT   r   rU   rV   rW   rX   rY   r[   r]   r^   r_   r   r`   ra   rb   )r,   r.   r'   rc   rd   re   rf   rg   rh   ri   rj   rk   rl   rm   rn   ro   ra   rq   rr   rs   s                       r(   r!   r!      s     )*LL""$E ""bzz4L##D) AB&
 
 79SSU 	 KKQR #""  "uA--/1<<CS!%%c2.55a8  1 #""4 	

6$<#5#5dggkk,6O#PQQZZ\``bB*,-"Qq"I- zz7O!!((G3""&&t,
 

 79SSU 	A #"N CD RREK!'')RMM#!"q~~
s4&\"ALL9QWWIS121K 	 * 
LL	O 99UD  (():):DAA(**b}"96{m5^I\H]]bc(*&1&).&9  iik!! +** { #
 #"8 R-
A #"""@ B* " +***s8  AQP
QB P$P	8P$QPQA%P$7QPQAP$P$P$>PAP$'P( P$QP!C,Q P:QQP<QAQ2P>3Q7QQ QP$QQP$P$!Q$P7*P-+P72	Q<Q>Q QQ	Q	Q	Qc                   K   ddl m}  ddlm} t	        j
                  t              j                         }t	        j                  |t        j                  j                         t              j                  t        j                        }t               4 d{   }|j                  t!        t"              j%                  t"        j&                  j)                  d      t"        j*                  |k(               d{   j-                         j/                         }|j                  t!        t"              j%                  t"        j&                  j)                  d      t"        j0                  dk(  t"        j2                  |k\               d{   j-                         j/                         }|j                  t!        t"              j%                  t"        j&                  j)                  d                   d{   j-                         j/                         }t5               }||z   D ]0  }	|	j6                  xs |	j8                  }
|
s |j;                  |
       2 i }|r|j                  t!        t<              j%                  t<        j>                  jA                  |                   d{   j-                         j/                         }|D ci c]  }|j>                  |jB                   }}|j                  t!        |      j%                  |jD                  dk(  |j&                  j)                  d                   d{   j-                         j/                         }ddd      d{    sytG        d D              }tI        |      }|r||z  d	z  nd}tI              }tG        d
 |D              }tG        d |D              }|r||z  d	z  nd}dg}|dkD  r|jK                  d| d| d|dd       n2r|jK                  dtI        |       d       n|jK                  d       ri }|D ]=  }	|	j6                  xs |	j8                  }
|jM                  |
g       jK                  |	       ? |jK                  d       |jO                         D ]F  \  }
}jQ                  |
d      }djS                  d |D              }|jK                  d| d|        H |D 	cg c]  }	|	j0                  dk7  s|	 }}	|r|jK                  d       i }|D ]=  }	|	j6                  xs |	j8                  }
|jM                  |
g       jK                  |	       ? |jO                         D ]F  \  }
}jQ                  |
d      }djS                  d |D              }|jK                  d| d|        H |jK                  d| d| d|dd|        d jS                  |      }|D ]  }|jT                  s| jW                  |jT                  |       d{   }|s7t               4 d{   }|j;                  tY        d!d"| d#| d$|dd%|jZ                  ||t]        |d&      t]        |d&      d'(             |j_                          d{    ddd      d{     y7 7 7  7 7 c c}w 7 t7 K# 1 d{  7  sw Y   \xY wc c}	w 7 7 7 P7 B# 1 d{  7  sw Y   xY ww))u  22:00 推群組,公告今日完成情況 + 進度%。

    格式:
      🌙 今日工作公告

      今天完成 X / 應完成 Y(Z%)

      ✅ 完成清單:
        • 神狙手阿綠 — 《A》《B》
        • Jonina — 《C》

      ⏳ 還沒完成的(明早 8:00 我會再 ping):
        • 盛豪 — 《D》
        • Robert Su — 《E》

      整體進度:N 件 / 完成 M / 進行中 K(L%)
    r   r+   r-   tzinfoNdoner3   c              3  @   K   | ]  }|j                   d k(  sd  ywrz   r7   NrI   .0rg   s     r(   	<genexpr>z7_run_evening_completion_announcement.<locals>.<genexpr>c  s     Fi188v3E1i   d   c              3  @   K   | ]  }|j                   d k(  sd  ywr|   r}   r~   s     r(   r   z7_run_evening_completion_announcement.<locals>.<genexpr>h  s     E,Q!((f2Dq,r   c              3  @   K   | ]  }|j                   d k(  sd  yw)r1   r7   Nr}   r~   s     r(   r   z7_run_evening_completion_announcement.<locals>.<genexpr>i  s     M<a188}3L<r   u   🌙 今日工作公告
u   今天應完成 u
    / 完成 (z.0fz%)
u   今天完成 u-    件(雖然不是今天 due,但也算進度)
u/   今天沒有任務 due,大家都很閒嗎?😄
u   ✅ 完成:r4   z / c              3  <   K   | ]  }d |j                    d  ywu   《ru   Nr[   r~   s     r(   r   z7_run_evening_completion_announcement.<locals>.<genexpr>       ?Bq#aggYc 2B   u     • u    — u.   
⏳ 還沒完成(明早 8:00 我會再 ping):c              3  <   K   | ]  }d |j                    d  ywr   r   r~   s     r(   r   z7_run_evening_completion_announcement.<locals>.<genexpr>  r   r   u   
📊 整體進度:u    件總計 / 完成 u   %)/ 進行中 r5   evening_completionu   晚間完成公告(/z = z%)r7   )r<   	today_due
today_done	today_pctoverall_pctr?   )0rC   r,   rD   r.   r   r   r   r   combinemintime
astimezoner   utcr   rE   r	   r   rF   rG   rH   rK   rM   rN   rI   completed_atrO   rP   rQ   rR   r   rU   rJ   rY   rV   sumr`   rT   rS   rW   rX   r]   r^   r_   r   ra   roundrb   )r,   r.   r'   today_start_utcrc   	due_today
done_todaytotal_activerf   rg   rh   ri   rj   rk   rl   today_done_counttoday_due_countr   overall_totaloverall_doneoverall_doingr   rm   by_userro   ra   titlespendingrq   rr   rs   s                                  r(   r"   r"     s    $ )*LL""$E&&uhll.?.?.A#NYYZbZfZfgO ""b::4L##D)&
 

 79SSU 	 JJ4L##D)v%!!_4
 
 79SSU 	 !jj4Lt22489
 
79SSU 	
 uZ'A--/1<<C  % ( 	

6$<#5#5dggkk,6O#PQQZZ\``bB79:r!q~~-rI: zz7O!!((G3""&&t,
 

 79SSU 	C #"P  FiFF)nO>M!O3c9STI%ME,EELM<MMM:G<-/#5QK ))E''8
CSBTTUV_`cUddhij	}S_$55cdeGH A--/1<<CsB'..q1  	]#}}GC==j1DZZ?B??FLL6$uVH56 ' $:)Qqxx6'9q)G:FGA--/1<<CsB'..q1  }}GC==j1DZZ?B??FLL6$uVH56 ' 
LL'6J<.XYZefiYjjx  zG  yH  I  J99UD  (():):DAA(**b}"612B1C1_DUUXYbcfXggij(*%4&6%*9a%8',[!'<
 
 iik!! +** { #


 R:
C #"""X ;( B* " +***s;  B[<Z)[<A [=Z,>B[Z/A-[=Z2>A[A$[1Z52$[Z84A[	Z=
 [*[<5[ 6E6[<,[[D[<[[<[<-[ .[<1A [&["[&[<![$"[<,[/[2[5[8[ [<[	[
[[< [<"[&$[<&[9	,[/-[9	4[<c           	     x  K   t        j                  t        j                  t              j	                         t         j
                  j                         t              }|j                  t        t              j                  t        j                  dk(  t        j                  |j                  t        j                        k\               d{   j!                         j#                         }|D ]A  }|j$                  st'        |j$                  j)                  d            t'        |       k(  sA y y7 gw)u&   今天有沒有 ping 過這個 task。rx   	task_pingNtask_idTF)r   r   r   r   r   r   r   rE   r	   r   rF   r@   
created_atr   r   r   rM   rN   rB   strrX   )r   rc   today_startrowsrs        r(   _already_pinged_todayr     s     ""8<<#4#9#9#;X\\=N=N=PY\]K**}	'';6$$(>(>x||(LL

  wy 	 77s177;;y12c'lB  s   CD:D81D:0D:4D:c                   K   ddl m}  t        j                  t              j                         }|t        d      z
  }t               4 d{   }|j                  t        t              j                  t        j                  j                  d      t        j                  j                  g d      t        j                   j#                  d      t        j$                  j#                  d                   d{   j'                         j)                         }g }|D ]H  }|j                   |k  r|j+                  |df       &|j                   |k(  s6|j+                  |df       J |s't,        j/                  d	       	 ddd      d{    y|D ch c]  \  }}|j$                   }}}|j                  t        t0              j                  t0        j2                  j                  |      t0        j                  j                  d                   d{   j'                         j)                         }	|	D 
ci c]  }
|
j2                  |
 }}
i }|D ]{  \  }}|j5                  |j$                        }
|
r|
j6                  s0t9        |j2                  |       d{   rO|j;                  |
j2                  g       j+                  ||f       } |j=                         D ]0  \  }}||   }
d
|
j>                   d}|D ]J  \  }}|dk(  rdnd}dddddj5                  |j@                  d      }|| d|jB                   d| d| dz  }L |dz  }| jE                  |
j6                  |       d{   }|s|D ]S  \  }}|jG                  tI        d|d|
j>                   d|jB                   tK        |j2                        |d             U |jM                          d{    t,        j/                  d|
j>                  tO        |             3 ddd      d{    y7 7 77 c c}}w 7 !c c}
w 7 7 7 ^7 ## 1 d{  7  sw Y   yxY ww)uH   掃任務,逾期 / 今天到期且 assignee 有綁 LINE → 推一則。r   r+   r7   rZ   Nr/   u   逾期u   今天到期u"   [ping] 沒有需要 ping 的任務u   ⏰ u   ,任務提醒:

u   🔴u   🟡u   ⚡u   🔥 u   💤)urgenthighmediumlowu    《ru    r5   uG   
做完直接跟我說「庫柏 X 任務完成」,我幫你改狀態。r   u   提醒 :)r   labelr@   user_idrA   rB   u   [ping] 推給 %s,%d 件任務)(rC   r,   r   r   r   r   r   r   rE   r	   r   rF   rG   rH   rI   rJ   rK   rL   rP   rM   rN   rT   r   r   r   rU   rX   line_user_idr   rS   rW   rY   priorityr[   r_   rR   r   r   rb   r`   )r,   r'   	yesterdayrc   rd   target_tasksrg   _assignee_idsusersrk   user_mapper_userr   rh   rW   rq   emojiprirs   s                       r(   _run_ping_checkr     s    (LL""$E	q))I ""bzz4L##D) AB$$T*  ''-	
 
 79SSU 	 02AzzE!##QM2u$##Q$78	  KK<=) #"". 3??,$!Q,?zz4Ltww{{<8$//:M:Md:ST
 
79SSU 	 &++UADD!GU+ 8:$HAuQ]]+AANN*144444b)00!U< % #..*JCA!..));<D!5"'8"3!&"VTXXYZYcYcegh5'aggYc%#bAA " ^_D",,Q^^TBBB!DAqFF=&1 #")!..)9177) D*-add)a@	  " iik!!;Q^^SQVZX+ +Q #""
 #. @
 , 5 C "y #"""s   AQ$P/Q$B*Q;P2<AQ-QQ$P5Q$QP8/A.QP>$QQAQ%Q&CQ9Q	:QA+Q,Q-1QQ$)Q*Q$2Q5Q$8QQ	QQQ$Q!QQ!Q$c                 p  K   ddl m}  ddlm} t	               4 d{   }|j                  t        t              j                  t        j                  j                  d      t        j                  j                  d      t        j                  j                  d      t        j                  dk7               d{   j                         j!                         }ddd      d{    D ]  }	  ||       d{   }|j#                  dd      }|s)d|j$                   d	| }| j'                  |j                  |       d{   }|rvt	               4 d{   }|j)                  t+        d
|j,                  d|j$                   d|dd d             |j/                          d{    ddd      d{     y7 7 7 # 1 d{  7  sw Y   xY w7 7 7 7 :7 ,# 1 d{  7  sw Y   <xY w# t0        $ r$ t2        j5                  d|j$                         Y Bw xY ww)u-   每個綁了 LINE 的人收到 daily_brief。r   r+   )generate_daily_briefNTr   briefu   ☀️ 早安 z

brief_generatedu   早晨簡報推送給 morning_briefx   )channelpreviewr   zmorning brief for %s failed)rC   r,   app.services.daily_briefr   r   rE   r	   r   rF   	is_activerH   rG   r   rL   password_hashrM   rN   rX   rY   r_   rR   r   rU   rb   r   r   r    )	r,   r   rc   r   rk   result
brief_textrq   rs   s	            r(   _run_morning_briefsr     s    (= ""bzz4L""4(##D)!!((.""b(	
 
 79SSU 	 #" 	L/22FGR0J#ANN#34
|DD",,Q^^TBBB,.."FF=&7 !"88H I*9jQURUFVW	  ))+%% /.  #
 #""" 3
 C. & /...  	L:ANNK	Ls  H6G
H6BG=G> GH6)G*	H64H?G' HH61H
G)HG+ H#AG12G-3G17HG/HH6GH6G$GG$ H6'H)H+H-G1/H1H	7G:8H	?H)H3/H62H33H6c                 j
  K   ddl } ddlm} ddlm} t               4 d{   }|j                  t        |      j                  |j                  dk(  |j                  j                  d                   d{   j                         j                         }|s't        j                  d       	 ddd      d{    yt!        j"                  t$              j'                         }t!        j(                  |t         j*                  j-                         t$              j/                  t0        j2                        }|j                  t        t4              j                  t4        j                  j                  d      t4        j6                  |k\               d{   j                         j                         }|j                  t        t4              j                  t4        j                  j                  d      t4        j8                  j;                  d      t4        j8                  |k\               d{   j                         j                         }|j                  t        t4              j                  t4        j                  j                  d      t4        j<                  dk(               d{   j                         j                         }	ddd      d{    t>        j@                  syd	tC               d
tC               dtC        	       ddjE                  d |dd D              z   dz   djE                  d |dd D              z   }
	 | jG                  t>        j@                        }|jH                  jK                  t>        jL                  ddd|
dg       d{   }ddjE                  d |jN                  D              jQ                         z   }D ]  }|jV                  s|jY                  |jV                  |       d{   }|s7t               4 d{   }|j[                  t]        d d!|j^                   d"|j^                  d#$             |ja                          d{    ddd      d{     y7 z7 %7 7 7 k7 7 # 1 d{  7  sw Y   xY w7 # tR        $ r@ t        jU                  d       dtC        |       dtC        |       dtC        |	       d}Y $w xY w7 7 7 7 # 1 d{  7  sw Y   AxY ww)%uG   推團隊 wrap-up 到所有 LINE 群組(目前可能只有一個群)。r   Nr-   r+   r3   u   [wrap] 沒 LINE 群,跳過rx   r1   u   今天建了 u    個新任務,完成 u    個,目前進行中 u    個。

今天新建:
r5   c              3  :   K   | ]  }d |j                      ywz- Nr   r~   s     r(   r   z$_run_evening_wrap.<locals>.<genexpr>_  s     &O!AGG9~   r   u   

今天完成:
c              3  :   K   | ]  }d |j                      ywr   r   r~   s     r(   r   z$_run_evening_wrap.<locals>.<genexpr>`  s     *WCVaRy>CVr   api_keyi  u   你是庫柏 — 山水話團隊 AI 同事。寫一則 18:00 wrap-up 訊息推到 LINE 群,提綱挈領、口語、4-6 行內。讓老闆 + 員工知道今天團隊整體狀況。如果沒進度 / 沒完成 → 直接說明天加油,不要硬擠。userrolecontentmodel
max_tokenssystemmessagesu   🌙 今日 wrap-up

r   c              3  T   K   | ]   }|j                   d k(  s|j                   " ywrq   Ntyperq   r   bs     r(   r   z$_run_evening_wrap.<locals>.<genexpr>n  s$     2d<aSTSYSY]cSc166<   ((u   wrap-up Claude 失敗u   🌙 今日 wrap-up

建了 u    件任務、完成 u    件、進行中 u    件。明天加油 💪r   u   晚間 wrap-up 推到群 evening_wrap)r   r<   r?   )1	anthropicrD   r.   rC   r,   r   rE   r	   rF   rV   rG   rH   rM   rN   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rL   rI   r
   ANTHROPIC_API_KEYr`   r]   AsyncAnthropicr   createCLAUDE_MODEL_HAIKUr   stripr   r    r^   r_   rR   r   ra   rb   )r   r.   r,   rc   groupsr'   today_utc_starttasks_todaycompleted_todayr1   summary_inputclientresprq   rr   rs   s                   r(   _run_evening_wrapr   -  sX    *( ""b

7O!!((G3""&&t,
 

 79SSU 	 KK45 #"" S!&&("**5(,,2C2C2EcR]]^f^j^jkZZ4L##D)?2
 

 79SSU 	 "$4L##D)!!((.!!_4"
 
 79SSU 	  ZZ4L##D)},
 

 79SSU 	? #"N %%
K())>s??S>T U{+, -	!YY&O{2A&OO	P 	 "&*W?SUTUCV*W!W	X 
))(2L2L)M__++--X  &-@A , 	
 	
 )2772d4<<2d+d+j+j+ll ",,R->->EEB,.."FF=&7";BGG9 E*8"''R 
 ))+%% /..	 I #
 # 


? #"""b	
  
01+&'';C<P;Q R[)**BD 	
 F. & /...sZ  T3RT3AR09R:8R02T3=R!>T3CR0R$BR0<R'=A?R0<R*= R0T3(R-)A7T3!AS	 5S67S	 -T3?T3TT3&T34T5T38ATTTT3TT3R0!T3$R0'R0*R0-T30S6R97S>T3S	 	ATT3TT3T3TT3T0	#T&$T0	+T3c                
  K   ddl }ddlm} ddlm} ddlm} t               4 d{   }|j                  t        t              j                  t        j                  dk(  t        j                  |k\        j                  t        j                  j                                      d{   j!                         j#                         } |       }|D ]&  }	|	j$                  s||	j$                  xx   dz  cc<   ( i |r|j                  t        t&              j                  t&        j(                  j+                  t-        |j/                                                  d{   j!                         j#                         }
|
D ci c]  }|j(                  |j0                   c}|D 	cg c](  }	|	j2                  xs i j5                  dd      dkD  s'|	* }}	 |       }|D ]1  }	|	j2                  xs i j5                  d	      }|s%||xx   dz  cc<   3 ddd      d{    s
d
|  dddifS j7                  d      }g }|dd D ]  }	j5                  |	j$                  d      }|j9                  d| d|	j2                  xs i j5                  d	      xs d d|	j2                  xs i j5                  d      xs |	j:                           dj=                  |      }d}r{d}|dd D ]q  }	|	j2                  xs i }|dj5                  |	j$                  d       d|j5                  d      dd  d|j5                  di g      d   j5                  dd       dz  }s d}t>        j@                  r	 |jC                  t>        j@                        }|jD                  jG                  t>        jH                  d d!|  d"d#d$|  d%| d&dj=                  fd'tK        |      D              z   |z   d(g)       d{   }dj=                  d* |jL                  D              jO                         }|szd,|  d-tW        |       d.}tK        |dd/ d      D ]'  \  }\  }}|d0| d1j5                  |d       d2| d3z  }) r-|d4d5j=                  d6 |j7                  d/      D               z  }d,|  d7tW        |       d8}||z   tW        |      |tY              tW        |      d9fS 7 7 B7 c c}w c c}	w 7 # 1 d{  7  sw Y   xY w7 # tP        $ r tR        jU                  |  d+       Y w xY ww):u_   共用邏輯:撈 since_dt 後的 reflection_note,生成 LINE 貼文。
    回 (text, stats)。r   Nr+   r-   )Counterreflection_noter7   similar_counttagu   🌱 ua   覆盤

這段時間群組裡還沒有人分享體悟。下週多分享一些學到的事吧 💡countr      r4   z- [z][u   其他z] rA   r5   r   uh   

⚠ 系統發現以下體悟跟過去 30 天的某些體悟很像(可能在重複學同一個教訓):
z  - [?(   u    (相似度 
similar_toscorez)
r   i  u~   你是庫柏 — 山水話團隊 AI 同事。下面是團隊這段時間在 LINE 群組分享的體悟列表。請寫一則「u  覆盤總結」推到 LINE 群,500 字內。結構:
1. 一句話定調這段期間整體認知方向(從哪 → 學到什麼)
2. 共通主題 top 3(用 bullet,每點 15 字內)
3. 認知提升亮點(挑 1-2 則最深的體悟,引用作者 + 一句話)
4. 「踩坑警訊」:如有重複學同一教訓的訊號,點名提醒
5. 結尾鼓勵 1 行
口語、不裝、直接、要像同事在說話而非報告。r   u   【u   體悟列表】
u   

【貢獻者排名】
c              3  h   K   | ])  \  }\  }}d |dz    dj                  |d       d| d + yw)  r7   . r  : u    則N)rX   )r   irh   nri   s       r(   r   z_build_recap.<locals>.<genexpr>  sG      M0KHS! !#1Q3%r)--C*@)AA3dK0Ks   /2r   r   c              3  T   K   | ]   }|j                   d k(  s|j                   " ywr   r   r   s     r(   r   z_build_recap.<locals>.<genexpr>  s      L<a166V;K166<r   u   覆盤 Sonnet 失敗u   📊 u   覆盤

共 u    則體悟。
貢獻 top 3:
   r  r  r	  u    則
u   
主要 tag:z, c              3  &   K   | ]	  \  }}|  y w)N )r   rg   r   s      r(   r   z_build_recap.<locals>.<genexpr>  s     -V;UCAaa;Us   u   覆盤總結
共 u     則體悟,系統幫你整理:

)r   	top_userstagsr   )-r   rC   r,   rD   r.   collectionsr   r   rE   r	   r   rF   r@   r   order_bydescrM   rN   r   r   rU   rJ   listkeysrY   rB   rX   most_commonrT   rA   r]   r
   r   r   r   r   CLAUDE_MODEL_SONNET	enumerater   r   r   r   r    r`   dict)period_labelsince_dtr   r,   r.   r   rc   notesr   r  rj   rk   with_similartag_counterrg   top_contributorssummary_input_linesauthorr   repeat_warnings_textextrq   r   r   r
  rh   cheaderri   s                               @r(   _build_recapr'    s     (*# ""bzz=!U++/@@((H4 Xm..3356
 
 79SSU 	 9Ayy#q(#  	

t""477;;tHMMO/D#EF wy  8::r!q~~-r:I $)X5aQWW],?,?QR,SVW,W5X iAB##E*AA!# 7 #"@ |n  %H  I  LS  UV  KW  W  	W  ++A. 3BZqyy*5""&QWW]//6B(C2qww}RTFYFYZcFdFqhihqhqErs	
 
 II12M  Mbq!A''-RC eIMM!))S,I+J"SWWU^M_`cacMdLeeqruryry  {G  JL  IM  sN  OP  sQ  sU  sU  V]  _b  sc  rd  dg  %h  h  " D!!	D--h6P6P-QF//22&&2^ 4V	V $*,'8 H0 1II M09:J0KM MM )	)  0  D. 77L4<<LLRRTD
 |nN3u:,>\]$%5bq%91=KAxQb2immC56b6BBD >mDII-V;;R;RST;U-V$V#WXXD \N"4SZL@bcFD=CJ=M$($5LHY[ [ [ #
  ; Y/ #"""t0  	D~-ABC	Ds   %US*UA?T +S-,8T %BT &S0'$T S3)T 0(S8S8/T T U'S=(EU:BT  T4T 5B6U-T 0T 3
T =U TT	TUT !T>:U=T>>Uc                L  K   ddl m} ddlm} t	               4 d {   }|j                  t        |      j                  |j                  dk(  |j                  j                  d                    d {   j                         j                         }d d d       d {    D ]  }|j                  s|j                  |j                  |        d {   }|s7t	               4 d {   }|j                  t!        || d|j"                   d|j%                  dd       dd	|j"                  i|
             |j'                          d {    d d d       d {     y 7 N7 7 # 1 d {  7  sw Y   xY w7 7 7 77 )# 1 d {  7  sw Y   xY ww)Nr   r+   r-   r3   u    推到群 r   r   u    則體悟)r<   r?   )rC   r,   rD   r.   r   rE   r	   rF   rV   rG   rH   rM   rN   r^   r_   rR   r   ra   rX   rb   )	rq   stats
recap_typer,   r.   rc   r   rr   rs   s	            r(   _push_recap_to_groupsr+    s`    (* ""b

7O!!((G3""&&t,
 

 79SSU 	 #"   (():):DAA(**b}",)l+bggYa		'RS@T?UU`a)277<e< 
 iik!! +**  #
 #""" B* " +***s   F$E+F$AE25E.6 E2F$!E0"5F$FF$F$-F	.F$1A"FFFF$#F$F$.E20F$2F8E;9F F$	F$FF$F!	FF!	F$c                    K   t        j                  t        j                        t	        d      z
  } t        d|        d {   \  }}t        ||d       d {    y 7 7 w)N   r   u   本週weekly_recapr*  r   r   r   r   r   r'  r+  sincerq   r)  s      r(   _run_weekly_recapr3    sP     LL&)::E$Xu55KD%
e
GGG 6G$   A A%A!A%A#A%#A%c                    K   t        j                  t        j                        t	        d      z
  } t        d|        d {   \  }}t        ||d       d {    y 7 7 w)Nr  r   u   本月monthly_recapr/  r0  r1  s      r(   _run_monthly_recapr7    sP     LL&);;E$Xu55KD%
e
HHH 6Hr4  )returnNone)r   r   r8  bool)r  r   r  r   r8  ztuple[str, dict])rq   r   r)  r  r*  r   )&__doc__
__future__r   r   loggingr   r   r   r   uuidr   
sqlalchemyr	   
app.configr
   app.databaser   app.models.agent_activityr   app.models.taskr   app.models.userr   	getLoggerr   r   r)   r   r!   r"   r   r   r   r   r'  r+  r3  r7  r      r(   <module>rG     s    #   8 8    * 3     
		+	, yq!"4Jx^"BZ"zF"R DYX!LRT&xh[V"4HIrF  