
    ni{                     \   d 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ZddlmZ ddl	m
Z
 ddlZdZe dZe dZe dZe d	Ze d
Ze dZdZdZdZdZg dZg dZdddddddZg dg dg dg dg dg ddZg dg dg d g d g d!g d!d"Zg d#Zi d$d%d&d'd(d)d*d+d,d-d.d/d0d1d2d3d4d5d6d7d8d9d:d;d<d=d>d?d@dAdBdCdDdEdFdGdHZi d%dId/dJd9dKd'dLd)dMd+dNd-dOd1dPd3dQd5dRd7dSd;dTd=dUd?dVdAdWdCdXdGdYdZd[d\Z ej>                  ej@                  d]d^_        ejB                  e"      Z#d$d`dadbdcddded*d`dfdgdhddded0didjdkdlddded&d`djdmdnddded(d`dodpdqddded.didrdsdtdddedBdudvdwdxdddedyZ$dzZ%	 	 dd{e&d|e&d}e'd~e&de&f
dZ( G d d      Z)dde*de'de&fdZ+d|e&de,de-fdZ.d Z/de&fdZ0de-fdZ1de-fdZ2de&de-de&fdZ3de&de&de&fdZ4de-dz  fdZ5de-fdZ6de-dz  fdZ7de-fdZ8de&de-de*de&de&f
dZ9de*de*de&de-de&f
dZ: G d d      Z;de;de&fdZ<d Z=e"dk(  r e=        yy)u   
group_chat.py — 팀 단톡 데몬 스크립트
트리거 파일 폴링으로 멀티 페르소나 단톡을 구동합니다.
    N)datetime)Pathz/home/jay/workspacez&/memory/events/group_chat_trigger.jsonz&/memory/events/group_chat_session.jsonz/memory/dailyz/config/personas.jsonz#/memory/organization-structure.jsonz
/.env.keys
6937032012   ,     )u
   팀 모여u   회의하자u   단톡 시작u	   모여봐u   전원 집합u   소집)u   잘래u   빠이u   해산u   끝u   그만u   여기까지u   인원 수 제한u   인원 추가u   인원 퇴장u   역할별 필터u   팀별 필터u   자동 발화 수 변경)limit_personasadd_personaremove_personafilter_by_rolefilter_by_teamset_auto_turns)vulcanthoranubis)irisfreyaisis)athenamimirsobek)argosheimdallhorus)hermesodinra)u	   백엔드u	   프론트u   프론트엔드UXu	   테스터u   팀장)r   r   r   r   r   )r   r   r   r   r   )r   r   r   r   r   )u   1팀
   개발1팀u   2팀
   개발2팀u   3팀u
   개발3팀)r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   lokimaatjanusvenusu   헤르메스r   u   불칸r   u	   이리스r   u	   아테나r   u   아르고스r   u   오딘r   u   토르r   u   프레이야r   u	   미미르r   u	   헤임달r   u   라r   u   아누비스r   u	   이시스r   u	   소베크r   u	   호루스r   u   로키r!   u	   마아트r"   r#   r$   )u	   야누스u	   비너스u   ⚡u   👁️u   ☀️u   🔥u   🌈u   🏛️u   🔍u   🔨u   ✨u   📚u   🛡️u   ⚱️u   🌙u   🐊u   🦅u   🎭u   🎨u   🚪u   ⚖️)r#   r"   z)[%(asctime)s] [%(levelname)s] %(message)s%Y-%m-%d %H:%M:%S)levelformatdatefmtr   u   개발1팀장u7   백엔드 아키텍처, 시스템 설계, 코드 리뷰uE   냉철하고 실용적, 효율을 중시하며 직설적으로 말함 nameteamrole	expertisepersonalitypersona_descu   UX/UI 설계자u2   UX/UI 설계, 사용자 경험, 프로토타이핑u?   분석적이고 꼼꼼함, 사용자 관점을 항상 강조함r    u   백엔드 개발자u6   백엔드 개발, 성능 최적화, 데이터베이스u<   열정적이고 추진력 강함, 문제 해결에 적극적u'   백엔드 개발, API 설계, 인프라uB   실용주의적, 코드 품질을 중시하며 간결하게 말함u   프론트엔드 개발자u(   프론트엔드 개발, React, UI 구현u?   창의적이고 활발함, 새로운 기술 도입에 적극적u   개발2팀장u1   시스템 아키텍처, 기술 전략, 팀 리딩uF   지혜롭고 신중함, 큰 그림을 보며 전략적으로 접근함u	   보안팀u   보안팀 리더u1   보안 검토, 취약점 분석, 리스크 평가u?   비판적이고 도전적, 허점을 찾아내는 데 탁월함)r   r   r   r   r   r   r!   z/home/jay/.local/bin/claudesystem_promptuser_message
max_tokensmodelreturnc                     t         dd|g}| r|j                  d| g       t        j                  ||ddd      }|j                  dk7  rt        d|j                  d	d
        |j                  j                         S )u7   Claude CLI를 subprocess로 호출하여 응답 생성.z--printz--modelz--system-promptT   )inputcapture_outputtexttimeoutr   u   Claude CLI 에러: N   )	CLAUDE_CLI_PATHextend
subprocessrun
returncodeRuntimeErrorstderrstdoutstrip)r1   r2   r3   r4   cmdresults         !/home/jay/workspace/group_chat.pycall_clauderI      s     		C 

%}56^^F A0t1D0EFGG==      c                   ,    e Zd ZdZdedefdZdefdZy)TelegramPolleruA   Telegram Bot API getUpdates 폴링으로 유저 메시지 수신.tokenchat_idc                 B    || _         || _        d| | _        d| _        y )Nhttps://api.telegram.org/botr   )rM   rN   base_urllast_update_id)selfrM   rN   s      rH   __init__zTelegramPoller.__init__   s&    
6ug>rJ   r5   c                 >   	 t        j                  | j                   d| j                  dz   ddd      }|j	                         }|j                  d      sg S g }|j                  dg       D ]|  }|d   | _        |j                  d	i       }t        |j                  d
i       j                  d            | j                  k(  sW|j                  dd      }|sl|j                  |       ~ |S # t        $ r$}t        j                  d|        g cY d}~S d}~ww xY w)u   새 메시지 가져오기.z/getUpdatesr   )offsetr;      )paramsr;   okrG   	update_idmessagechatidr:   r)   u   getUpdates 오류: N)requestsgetrQ   rR   jsonstrrN   append	Exceptionloggerwarning)rS   respdatamessagesupdatemsgr:   es           rH   get_updateszTelegramPoller.get_updates   s   	<<==/-"&"5"5"9aHD
 99;D88D>	H((8R0 .&,[&9#jjB/swwvr*..t45E7762.D -. O 	NN045I	s1   AC/ A*C/ C/ C/ /	D8DDDN)__name__
__module____qualname____doc__ra   rT   listrl    rJ   rH   rL   rL      s$    K c  C  T rJ   rL   historylast_nc                 4   g }| | d D ]}  }|j                  dd      }|j                  dd      }|j                  dd      }|r|j                  d| d|        S|dk(  r|j                  d	|        m|j                  |        d
j                  |      S )u9   대화 히스토리를 CLI 입력용 텍스트로 변환.Nspeakerr)   speaker_namecontent[]: useru   [제이회장님]: 
)r_   rb   join)rs   rt   linesrj   rv   rw   rx   s          rH   format_history_for_clir     s    Ewx  	"'')R(ww~r2'')R(LL1\N#gY78LL.wi89LL!	" 99UrJ   session_activec                 ,    ddl }|st         fdt        D              r)d}d v sd v rt        t              }n\t
        j                         D ]  \  }}| v st        |      } n |-t        j                         D ]  \  }}| v st        |      } n |g d}|j                  d       }|r$t        |j                  d            }|dkD  r|d| }d	d
|dS t         fdt        D              rddiS |j                  d       }|rddt        |j                  d            dS t        j                         D ]B  \  }	}
|	 v st         fddD              rdd|
dc S t         fddD              s<dd|
dc S  t
        j                         D ]'  \  }}| v st         fddD              s dd||dc S  t        j                         D ]'  \  }}| v st         fddD              s dd||d c S  |j                  d!       }|rdd"t        |j                  d            dS t         fd#d$D              rdd"d%dS |r
d&  d'  d(}nd)j                  t              }d*  d+| d,}	 t        d-|d./      }|j                  d0||j                        }|r;t!        j"                  |j                               }|j%                  dd1      }|d2v r|S |rd4 d5S dd1iS # t&        $ r"}t(        j+                  d3|        Y d}~1d}~ww xY w)6u!  유저 메시지의 의도를 감지한다.

    Returns:
        {"intent": "start_chat", "topic": "...", "personas": [...]}
        {"intent": "user_input", "message": "..."}
        {"intent": "end_chat"}
        {"intent": "control", "type": "...", ...}
        {"intent": "none"}
    r   Nc              3   &   K   | ]  }|v  
 y wNrr   .0kwr2   s     rH   	<genexpr>z detect_intent.<locals>.<genexpr>.  s     ;br\!;   u   전원u
   다 모여r   r   r   u   (\d+)명r   
start_chat   자유 대화)intenttopicpersonasc              3   &   K   | ]  }|v  
 y wr   rr   r   s     rH   r   z detect_intent.<locals>.<genexpr>M  s     9br\!9r   r   end_chatu    (\d+)명(?:만|까지만|까지)controlr	   )r   typecountc              3   &   K   | ]  }|v  
 y wr   rr   r   s     rH   r   z detect_intent.<locals>.<genexpr>Y  s     jbr\)jr   )u   빠져u   나가u   퇴장u   빠지u	   나가라r   )r   r   personac              3   &   K   | ]  }|v  
 y wr   rr   r   s     rH   r   z detect_intent.<locals>.<genexpr>[  s     `br\)`r   )u   불러u   합류u	   들어와u   참여r
   c              3   &   K   | ]  }|v  
 y wr   rr   r   s     rH   r   z detect_intent.<locals>.<genexpr>`         1A|1C  1Ar   )u   만u
   만 남아u
   만 얘기u
   만 모여r   )r   r   r   r-   c              3   &   K   | ]  }|v  
 y wr   rr   r   s     rH   r   z detect_intent.<locals>.<genexpr>d  r   r   r   )r   r   r   r,   u   (\d+)턴r   c              3   &   K   | ]  }|v  
 y wr   rr   r   s     rH   r   z detect_intent.<locals>.<genexpr>k  s     `br\!`r   )u   계속 얘기u   계속 대화u   멈추지 마c   uj   유저 메시지를 분석하세요.
현재 팀 단톡 세션이 진행 중입니다.

유저 메시지: "u   "

아래 중 하나를 JSON으로 응답:
1. 종료 의도 ("잘래", "빠이", "해산", "끝", "그만" 등): {"intent": "end_chat"}
2. 대화 참여 (질문, 의견, 지시 등): {"intent": "user_input", "message": "u   "}

주의: "너 잘래?" 같은 질문은 종료가 아님. "나 잘래", "오늘은 여기까지" 같은 1인칭 표현만 종료.
JSON만 응답:, uc   유저 메시지를 분석하세요.
현재 팀 단톡 세션이 없습니다.

유저 메시지: "u  "

아래 중 하나를 JSON으로 응답:
1. 단톡 시작 의도 ("팀 모여", "회의하자", "단톡 시작", "모여봐", "전원 집합" 등):
   {"intent": "start_chat", "topic": "추정 주제", "personas": ["hermes", "athena", "thor"]}
   - personas: 주제에 맞는 페르소나 3~5명 선택 (전체 소집이면 전원)
2. 단톡과 무관한 메시지 ("안녕", "하이", 일반 대화 등):
   {"intent": "none"}

전체 페르소나 목록: u   
JSON만 응답:r)   claude-haiku-4-5-20251001)r4   z\{.*\}none)r   
user_inputr   r   u   의도 감지 오류: r   )r   r[   )reanySTART_KEYWORDSrq   ALL_PERSONA_IDSROLE_FILTERSitemsTEAM_FILTERSsearchintgroupEND_KEYWORDS_PERSONA_NAMESr}   rI   DOTALLr`   loadsr_   rc   rd   re   )r2   r   _rer   	role_namepids	team_namelimit_matchr   r+   pidpersona_ids
turn_matchpromptpersona_listrG   
json_matchparsedr   rk   s   `                   rH   detect_intentr      s     ;N;;H<'<<+G0'3'9'9'; OIt L0#': #+7+=+=+? "	4$4'+DzH!" 7 **[,?KK--a0119'/H '($  9L99j)) jj!DlS'1ACP[PaPabcPdLeff (--/ 	XID#|#j4ijj&/9IVYZZ`4_``&/SVWW	X '3&8&8&: 	s"I{L(S  1AN  1A  .A"+5ES^hqrr	s '3&8&8&: 	s"I{L(S  1AN  1A  .A"+5ES^hqrr	s
 ZZ\:
'1ACPZP`P`abPcLdee`,_``'1ABOO  !> "V WcUc d
 yy1 !> 	" *N +
5R/JKZZ	63::>
ZZ
 0 0 23FZZ&1FII
 &<@@f  5/s3445s   5A'K( (	L1LLc                  h   t         j                  j                  d      ryt        t              } | j                         st        j                  dt                y	 t        j                  dddt         dgdd	      }|j                  j                         D ]g  }d
|v s|j                  d
      \  }}}|j                         dk(  s1|j                         t         j                  d<   t        j                  d        y y# t        $ r"}t        j!                  d|        Y d}~yd}~ww xY w)u9   GROUP_CHAT_BOT_TOKEN이 없으면 .env.keys에서 로드.GROUP_CHAT_BOT_TOKENNu   .env.keys 파일 없음: bash-csource  && envTr9   r:   =u;   GROUP_CHAT_BOT_TOKEN을 .env.keys에서 로드했습니다.u   env.keys 로드 실패: )osenvironr_   r   ENV_KEYS_FILEexistsrd   re   r?   r@   rD   
splitlines	partitionrE   inforc   error)env_pathrG   linek_vrk   s          rH   load_env_keysr     s   	zz~~,-M"H??2=/BC5TW]O7;<

 MM,,. 	Dd{..-1a779 669:BJJ56KK ]^	  5/s3445s+   AD #(D 7D D 	D1D,,D1c                  |   t         j                  j                  d      } | rt        j	                  d       | S t        t              }|j                         r	 t        j                  dddt         dgdd      }|j                  j                         D ]V  }d	|v s|j                  d	      \  }}}|j                         dk(  s1t        j	                  d
       |j                         c S  	 t!        d      t!        d      # t        $ r,}t        j                  d|        Y d}~t!        d      d}~ww xY w)uT   GROUP_CHAT_BOT_TOKEN 환경변수에서 봇 토큰 로드. 폴백: .env.keys 파싱.r   u4   봇 토큰을 환경변수에서 로드했습니다.r   r   r   r   Tr   r   u1   봇 토큰을 .env.keys에서 로드했습니다.u$   봇 토큰 .env.keys 로드 실패: NuT   GROUP_CHAT_BOT_TOKEN을 환경변수 또는 .env.keys에서 찾을 수 없습니다.)r   r   r_   rd   r   r   r   r   r?   r@   rD   r   r   rE   rc   r   rB   )rM   r   rG   r   r   r   r   rk   s           rH   load_bot_tokenr     s   JJNN12EJKM"H	E^^w?@#F
 002 )$;"nnS1GAq!wwy$::$WX wwy() m
nn,m
nn  	ELL?sCDD
m
nn	Es+   AD (D &D .D 	D;D66D;c                  
   t        t              } t        | dd      5 }t        j                  |      }ddd       i }d   d   d   D ]l  }|j                  d      d	k7  r|j                  d
      dk(  r|j                  dg       D ]  }|j                  d      d	k7  r|d   }|j                  d      }|r|j                  d      dk7  r|j                  d      d	k(  rw|d   j                  d      d   ||d   |j                  di       j                  dd      |j                  di       j                  dd      |j                  dd      d||d   <   |j                  dg       D ]  }|j                  d      dk(  r|j                  d      dv s,|d   j                  d      d   ||d   |j                  di       j                  dd      |j                  di       j                  dd      |j                  dd      d||d   <     |j                  d|j                  d
d            }|j                  d      }|r|j                  d      dk7  r|j                  d      r|j                  dd	      }	|	dv rw|d   j                  d      d   ||d   |j                  di       j                  dd      |j                  di       j                  dd      |j                  dd      d||d   <   |j                  dg       D ]  }|j                  d      dk(  r|j                  dd	      }
|
dv s/|d   j                  d      d   ||d   |j                  di       j                  dd      |j                  di       j                  dd      |j                  dd      d||d   <    o |d   d   d   D ]  }|j                  d      d	k7  r|j                  d      }|r|j                  d      dk7  r|j                  d      dv rz|d   j                  d      d   |d    |d   |j                  di       j                  dd      |j                  di       j                  dd      |j                  dd      d||d   <   |j                  dg       D ]  }|j                  d      dk(  r|j                  dd	      }
|
dv s/|d   j                  d      d   |d    |d   |j                  di       j                  dd      |j                  di       j                  dd      |j                  dd      d||d   <     |S # 1 sw Y   !xY w)!u=   organization-structure.json에서 페르소나 동적 로드.rutf-8encodingN	structurecolumnsteamsstatusactiveteam_idzdevelopment-office	sub_teamssub_team_nameleadr]   anur+   z (r   r-   r.   primaryr)   styler   r*   members)r   	availabler   rowscenterscenter_name)r   ORG_STRUCTURE_FILEopenr`   loadr_   split)org_pathforgr   r,   sub_teamr   r   memberlead_statusmember_statuscenters               rH   load_personas_from_orgr     sb   &'H	hg	. !iil H K +G4 ?88H)88I"66 HH["5 <<)X5$_5	||F+DHHTNe38Jh8V $V 2 24 8 ; ) $V%)XXk2%>%B%B9b%Q'+xxR'@'D'DWb'Q(,B(?,HT$Z( 'll9b9 Fzz$'50 zz(+/FF$*6N$8$8$>q$A$-$*6N)/K)D)H)HTV)W+1::k2+F+J+J7TV+W,2JJy",E2.	!> dhhy".EFI88F#D%/DHHV4D"hhx:"99 $V 2 24 8 ; ) $V%)XXk2%>%B%B9b%Q'+xxR'@'D'DWb'Q(,B(?,HT$Z( ((9b1 ::d#u, &

8X > $;; &v 4 4T :1 = ) &v%+ZZR%@%D%DYPR%S'-zz+r'B'F'FwPR'S(.

9b(A.HVD\*g?D k"6*95 ::h8+zz&!DHHTNe+0BF]0]V**403}-V!XXk26::9bI#xxR8<<WbI $B 7$HT$Z  jjB/ 	Fzz$5("JJx:M 77"6N006q9"=1"6N!'K!<!@!@B!O#)::k2#>#B#B7B#O$*JJy"$=*&	8 OI s   UUc                      	 t               } | r$t        j                  dt        |        d       | S 	 t        t              }|j                         rK	 t        |dd      5 }t        j                  |      }ddd       t        j                  dt                S t        S # t        $ r"}t        j                  d|        Y d}~d}~ww xY w# 1 sw Y   [xY w# t        $ r'}t        j                  d	|        Y d}~t        S d}~ww xY w)
um   조직도에서 페르소나를 로드하고, 실패 시 personas.json → DEFAULT_PERSONAS 순으로 폴백.u   페르소나 u*   명을 조직도에서 로드했습니다.u5   조직도 로드 실패, personas.json으로 폴백: Nr   r   r   u%   페르소나 설정 로드 (폴백): u/   personas.json 로드 실패, 기본값 사용: )r   rd   r   lenrc   re   r   PERSONAS_FILEr   r   r`   r   DEFAULT_PERSONAS)r   rk   pathr   rg   s        rH   load_personasr   ?  s    T)+KK-H6`abO  D{{}	RdC'2 $ayy|$KK?OPK
   TNqcRSST$ $  	RNNLQCPQQ 		RsG   /B# C !C7%C #	C,C		CCC 	D&DDpersona_keypersonas_datac                    |j                  | | ddd      }t        j                  | d      }|j                  dd      }|j                  dd      }|j                  d|       }|r|r| d| d| d	| d
S |r| d| d| d
S | d| S )u_   페르소나 키로부터 '⚡ 헤르메스(개발1팀/개발1팀장)' 형태의 태그 생성.r)   )r+   r,   r-   u   💬r,   r-   r+    (/))r_   	EMOJI_MAP)r   r   pemojir,   r-   r+   s          rH   format_persona_tagr  Z  s    +RQS'TUAMM+v.E55D55D55%D$qavQ//	$qa(($  rJ   rM   rN   r:   c                 P   d|  d}||dd}	 t        j                  ||d      }|j                  s2t        j	                  d|j
                   d|j                  d d	         t        j                  d       y # t        $ r"}t        j	                  d
|        Y d }~<d }~ww xY w)NrP   z/sendMessageHTML)rN   r:   
parse_mode
   )r`   r;   u   Telegram 전송 실패: r   r<   u   Telegram 요청 오류: g      ?)
r^   postrY   rd   r   status_coder:   rc   timesleep)rM   rN   r:   urlpayloadrf   rk   s          rH   send_telegramr  j  s    (|
<C!4vFG5}}Sw;wwLL3D4D4D3EQtyyQURUFWXY 	JJsO  5/s3445s   AA: :	B%B  B%c                  4   t        t              } | j                         sy 	 t        | dd      5 }t	        j
                  |      }d d d        | j                          S # 1 sw Y   xY w# t        $ r"}t        j                  d|        Y d }~y d }~ww xY w)Nr   r   r   u    트리거 파일 읽기 오류: )
r   TRIGGER_FILEr   r   r`   r   unlinkrc   rd   r   r   r   rg   rk   s       rH   read_triggerr  w  s    D;;=$g. 	 !99Q<D	 	  	   7s;<s.   A, A A,  A)%A, ,	B5BBsessionc                     	 t        t        dd      5 }t        j                  | |dd       d d d        y # 1 sw Y   y xY w# t        $ r"}t
        j                  d|        Y d }~y d }~ww xY w)Nwr   r   F   )ensure_asciiindentu   세션 덤프 오류: )r   SESSION_FILEr`   dumprc   rd   r   )r  r   rk   s      rH   dump_sessionr    sf    3,g6 	@!IIgquQ?	@ 	@ 	@ 3-aS1223s0   A 7A A A  A 	A.A))A.c                  d   t        t              } | j                         sy 	 t        | dd      5 }t	        j
                  |      }d d d        j                  d      rt        j                  d       |S 	 y # 1 sw Y   3xY w# t        $ r"}t        j                  d|        Y d }~y d }~ww xY w)Nr   r   r   r   u   기존 세션 복구됨.u   세션 로드 오류: )r   r  r   r   r`   r   r_   rd   r   rc   r   r  s       rH   load_sessionr!    s    D;;=3$g. 	 !99Q<D	 88HKK23K 
 	  	 
  3-aS1223s.   B A8/B 8B=B 	B/B**B/c                 r   t        t              }|j                  dd       t        j                         j                  d      }|| dz  }t        j                         j                  d      }t        | j                  dg             }t        | j                  di       j                               }d| d	| j                  d
d       d| d| ddj                  | j                  dg              d}| j                  dg       D ]2  }|j                  dd      }	|j                  dd      }
|d|	 d|
 dz  }4 	 t        |dd      5 }|j                  |       d d d        t        j                  d|        y # 1 sw Y   "xY w# t        $ r"}t        j!                  d|        Y d }~y d }~ww xY w)NT)parentsexist_okz%Y-%m-%dz.mdr%   r   speak_countsu   
## 단톡 세션 [u   ]
- 주제: r   u   없음u   
- 참여: u   인
- 총 발화: u   회
- 참여자: r   z

rs   rv   unknownrx   r)   z**z**: ar   r   u   세션 로그 저장: u   세션 로그 저장 실패: )r   	DAILY_DIRmkdirr   nowstrftimer   r_   sumvaluesr}   r   writerd   r   rc   r   )r  	daily_dirtodaylog_path	timestamp
n_personastotal_turnsentryrj   rv   rx   r   rk   s                rH   save_session_logr6    s   YIOOD4O0LLN##J/EeWC=(H''(;<IW[[R01Jgkk."5<<>?K
yk *[[(34 5L !$ &		'++j""=>?t		E 
 {{9b) 1'')Y/'')R(2gYd7)4001:(C'2 	aGGEN	,XJ78	 	  :4QC899:s0   >F E? F ?FF 	F6F11F6r   r   c                 D   |j                  d|       }|j                  dd      }|j                  dd      }|j                  dd      }|j                  dd      }|j                  dd      }	d| d	}
|r|r|
d
| d| d	z  }
n|r	|
d| dz  }
|
dz  }
|r|
| dz  }
|r	|
d| dz  }
|	r	|
d|	 dz  }
|
d| dz  }
t        |d      }|sd| }	 t        |
|d      S # t        t        j
                  f$ r& t        j                  d       t        |
|d      cY S w xY w)Nr+   r,   r)   r-   r0   r.   r/   
   당신은 
   입니다.r      의 	    역할: .r|   u   전문 분야: u   성격: u   
현재 팀 단톡 주제: uD  

규칙:
- 2-4문장 이내 짧게 답하세요.
- 한국어로 대화하세요.
- 유저(제이회장님)를 '제이회장님'이라 호칭하세요.
- 다른 팀원은 이름으로 직접 호칭하세요.
- 자연스러운 대화체를 사용하세요.
- 자신의 전문성을 살린 실질적인 의견을 말하세요.r
  )rt   u)   단톡이 시작되었습니다. 주제: r   r3   r  )r_   r   rI   rB   r?   TimeoutExpiredr  r  )r   r   rs   r   r+   r,   r-   r0   r.   r/   r1   history_texts               rH   generate_persona_responser@    su    ;;v{+D;;vr"D;;vr"D;;~r2LK,I++mR0K j1M1TF$tfJ77	9TF!,,TML>,,?9+R888K=33
&ug .O 	O	M *'"=LB5'JH=,3GG*334 H

1=,3GGHs   C   <DDpersona_nameslast_speakerr%  c                    t        |      dk\  r|dd  n|}dj                  d |D              }ddj                  |        d| d| d	 d
t        j                                
}	 t	        d|dd      }|j                  d      }|j                  d      dz   }	|dk\  r5|	|kD  r0t        j                  |||	       }
|
j                  dd      }|v r|S D cg c]
  }||k7  s	| }}|st        j                               }t        |fd      S # t        $ r"}t        j                  d|        Y d }~fd }~ww xY wc c}w )NrW   r|   c           	   3      K   | ]<  }d |j                  d|j                  dd             d|j                  dd        > yw)ry   rw   rv   r)   rz   rx   Nr_   )r   ms     rH   r   z&select_next_speaker.<locals>.<genexpr>  sF     xlmq~quuY7K!L MSQRQVQVW`bdQePfgxs   AAu   현재 대화 참여자: r   u   
대화 히스토리:
u   
직전 발화자: u   
각 발화 횟수: u   

다음에 가장 자연스럽게 말할 참여자 1명을 선택하세요.
JSON으로 응답: {"next_speaker": "persona_key", "reason": "한줄이유"}
persona_key는 반드시 다음 중 하나여야 합니다: r)   2   r   )r3   r4   {}r   r   next_speakeru   발화자 선택 오류: c                 (    j                  | d      S )Nr   rF  )r   r%  s    rH   <lambda>z%select_next_speaker.<locals>.<lambda>
  s    )9)9!Q)? rJ   )key)r   r}   rq   keysrI   findrfindr`   r   r_   rc   rd   r   min)rA  rs   rB  r%  last_5r?  speaker_promptr:   startendrg   speaker_keyrk   r   
candidatess      `           rH   select_next_speakerrY    sl    !\Q.WRS\GF99xqwxxL
#DIIm$<#= >!!- /)N +*^ ,G HLLL]L]L_G`Fa	c 
62~"D_`		#jjo!A:#+::d5o.D((>26Kl*"" *?Q,->!?J?,++-.
z?@@  604556 @s%   'A-D 
E$E	E D;;E c                       e Zd ZdedefdZdefdZdedefdZdedefd	Zdefd
Z	defdZ
defdZdefdZdedefdZddefdZdefdZdefdZdefdZdedefdZdefdZd Zd Zy)GroupChatSessionrM   r   c                     || _         || _        d| _        d| _        t        | _        g | _        g | _        d| _        d| _	        i | _
        d| _        y )NFr)   g        r   )rM   r   r   r   DEFAULT_CHAT_IDrN   r   rs   last_activity
auto_turnsr%  rB  )rS   rM   r   s      rH   rT   zGroupChatSession.__init__  sS    
*
&  "$rJ   r:   c                 F    t        | j                  | j                  |       y r   r  rM   rN   rS   r:   s     rH   sendzGroupChatSession.send  s    djj$,,5rJ   rN  r5   c                     |dddddd}t        | j                  j                  ||            }|j                  dd       |j                  dd       |j                  dd       |S )Nr)   r*   r,   r-   r0   )dictr   r_   
setdefault)rS   rN  defaultr  s       rH   _personazGroupChatSession._persona  sb    BRXZlno##''W56	VR 	VR 	^R(rJ   c                 .    t        || j                        S r   )r  r   rS   rN  s     rH   _tagzGroupChatSession._tag'  s    !#t'9'9::rJ   c           	          | j                   | j                  | j                  | j                  | j                  | j
                  | j                  | j                  dS )Nr   r   r   rN   rs   r^  r_  r%  rm  rS   s    rH   to_dictzGroupChatSession.to_dict*  sH    kkZZ||||!//// --	
 		
rJ   rg   c                    |j                  dd      | _        |j                  dd      | _        |j                  dg       | _        |j                  dt              | _        |j                  dg       | _        |j                  dt        j                               | _        |j                  d	d
      | _	        |j                  di       | _
        | j                  r%| j                  d   j                  dd      | _        y y )Nr   Fr   r)   r   rN   rs   r^  r_  r   r%  rv   )r_   r   r   r   r]  rN   rs   r  r^  r_  r%  rB  )rS   rg   s     rH   	from_dictzGroupChatSession.from_dict6  s    hhx/XXgr*
R0xx	?;xx	2.!XXotyy{C((<3 HH^R8<< $R 0 4 4Y CD rJ   triggerc           	         |j                  dd      | _        |j                  dg d      | _        |j                  dt              | _        g | _        t        j                         | _        d| _        | j                  D ci c]  }|d c}| _	        d| _
        |j                  dd	      }|r| j
                  j                  d
d|d       t        j                  d| j                   d| j                          | j                  d       | j                  D ]  }| j                  |      }| j!                  |      }|j                  d|      }|j                  dd	      }	 d| d}|r|d| d|j                  dd	       dz  }n|d|j                  dd	       dz  }|d|j                  dd	       dz  }t#        |d| j                   dd      }	| j                  d#| d$|	         t)        | j                        }| j                  | d%       t+        | j-                                y c c}w # t$        $ r'}
t        j'                  d | d!|
        d"}	Y d }
~
d }
~
ww xY w)&Nr   u   일반 대화r   r   rN   r   Tr2   r)   r{      제이회장님rv   rw   rx   u   세션 시작 | 주제: u    | 참여자: u)   잠깐요, 관련 팀원들 모을게요.r+   r,   r8  r9  r   r:  r-   r;  r<  u	    성격: r/   uK   . 짧고 자연스러운 한국어 대화체로 한 문장만 말하세요.uH   단톡에 참여하며 한 마디 짧게 인사해주세요. 주제는 'u   '입니다.P   r=  u   입장 인사 생성 오류 (): u   잘 부탁드립니다.<b>u   </b> 참여합니다. u%   명 모였습니다. 시작하시죠.)r_   r   r   r]  rN   rs   r  r^  r_  r%  r   rb   rd   r   rc  rh  rk  rI   rc   r   r   r  ro  )rS   rs  r  r2   p_keytagr+   r,   sys_text	one_linerrk   ns               rH   rU  zGroupChatSession.startB  sU   [[/:
J0LM{{9o>!YY[+/==9aQT9{{>26LLFDUbn op.tzzl.XY 			=>]] 	DEe$A))E"C55'D55$D6'vZ8!D6aeeFB.?-@
 KKH)AEE&",=+>a @@HimR(@'A  BM  N  N'^_c_i_i^jjuv!	 IIC5 6ykBC)	D, 		QC<=>T\\^$I ::  6<UG3qcJK5	6s   
H2#A3H77	I' I""I'r[   c                     | j                   j                  dd|d       d| _        t        j                         | _        t
        j                  d|d d         y )Nr{   ru  rv  r   u   유저 입력 추가: rH  )rs   rb   r_  r  r^  rd   r   )rS   r[   s     rH   add_user_inputzGroupChatSession.add_user_inputo  sL    @Q^efg!YY[,WSb\N;<rJ   rz  c                 .   | j                  |      }| j                  |      }|j                  d|      }	 t        ||| j                  | j
                        }d| d| }| j                  |       | j                  j                  |||d	       | j                  j                  |d
      dz   | j                  |<   | xj                  dz  c_        || _        t#        j"                         | _        t        j'                  d| d|d d         t)        | j+                                y# t        j                  $ r0 | j                  d| d       t        j                  d|        Y yt        $ r!}t        j                  d| d|         d }~ww xY w)Nr+   ry  u   </b> (잠시 생각 중...)zTimeoutExpired: Fu   응답 생성 오류 (rx  </b> rv  r   r   u	   발화: [z] <   T)rh  rk  r_   r@  rs   r   r?   r>  rc  rd   re   rc   r   rb   r%  r_  rB  r  r^  r   r  ro  )rS   rz  r  r{  r+   r:   rk   msg_texts           rH   speakzGroupChatSession.speaku  sk   MM% iiuuVU#	,UAt||TZZPD U4&)		(tPTUV#'#4#4#8#8#BQ#F% 1!!YY[ivRSb	{34T\\^$# (( 	IIC5 ;<=NN-eW56 	LL1%A3?@	s   "D) )A F+F3FFreasonc           	      X   t         j                  d|        | j                  D ]  }| j                  |      }| j	                  |      }|j                  d|      }|j                  dd      }	 d| d}|r|d| d|j                  d	d       dz  }n|d
|j                  d	d       dz  }|dz  }t        |dd      }| j                  d| d|         t        | j                        }	t        | j                  j                               }
| j                  d| j                   d|	 d|
 d       d| _        t        | j!                                t#        t$              }|j'                         r|j)                          t         j                  d       y # t        $ r d}Y w xY w)Nu   세션 종료 | 이유: r+   r,   r)   r8  r9  r   r:  r-   r;  r<  u]    짧고 자연스러운 한국어 대화체로 제이회장님께 한 문장만 말하세요.uD   단톡을 마치며 짧게 작별 인사 한 문장만 해주세요.rw  r=  u'   수고하셨습니다, 제이회장님.ry  r  u!   단톡 종료합니다. (주제: u
   , 참여: u   인, 발화: u   회)Fu   세션 파일 정리 완료.)rd   r   r   rh  rk  r_   rI   rc   rc  r   r,  r%  r-  r   r   r6  ro  r   r  r   r  )rS   r  rz  r  r{  r+   r,   r|  farewellr~  r4  r   s               rH   rV  zGroupChatSession.end  s   .vh78]] 	2Ee$A))E"C55'D55$DE'vZ8!D6aeeFB.?-@
 KKH)AEE&",=+>a @@H{{&Z! IIC5hZ01'	2* $++2245		5djj\A3m\g[hhlmn(L!;;=KKM23  EDEs   /AFF)(F)c                     | j                   S )u   세션 활성 여부 반환.)r   rn  s    rH   	is_activezGroupChatSession.is_active  s    {{rJ   c                 H    t        | j                  j                               S )u/   로드된 전체 페르소나 ID 목록 반환.)rq   r   rO  rn  s    rH   _all_available_personasz(GroupChatSession._all_available_personas  s    D&&++-..rJ   c                 L    t        | j                  | j                  d|        y)u?   시스템 안내 메시지 전송 (페르소나 포맷 없이).u   ⚙️ Nra  rb  s     rH   send_system_messagez$GroupChatSession.send_system_message  s    djj$,,'$0@ArJ   c                 $    | j                  |      S )uK   페르소나 데이터 반환 (_persona와 동일, 공개 인터페이스).)rh  rj  s     rH   get_personazGroupChatSession.get_persona  s    }}S!!rJ   r   c                     |j                  d      }|dk(  r|d   }|dk  ry|t        | j                        k  r| j                  |d }| j                  d| | _        |D cg c]#  }| j                  |      j                  d|      % }}|D ]  }| j                  j                  |d         | j                  ddj                  |       d	| d
       yy|dk(  r|d   }|| j                  v rt        | j                        dkD  r| j                  |      j                  d|      }| j                  j                  |       | j                  j                  |d       | j                  | d	t        | j                         d
       yyy|dk(  r|d   }|| j                  vrv| j                  |      j                  d|      }| j                  j                  |       d| j                  |<   | j                  | dt        | j                         d
       yy|dk(  r|d   D cg c]  }|| j                         v s| }	}|	r| j                  D ]#  }||	vs| j                  j                  |d       % |	D ]   }|| j                  vsd| j                  |<   " |	| _        |j                  dd      }
| j                  |
 dt        | j                         d
       yy|dk(  r|d   D cg c]  }|| j                         v s| }	}|	r| j                  D ]#  }||	vs| j                  j                  |d       % |	D ]   }|| j                  vsd| j                  |<   " |	| _        |j                  dd      }| j                  | dt        | j                         d
       yy|dk(  r@|d   }|| _        d| _        |dk\  r| j                  d       y| j                  d| d       yyc c}w c c}w c c}w )u    세션 중 제어 명령 처리.r   r	   r   r   Nr+   u   인원 조정: r   u    퇴장. 현재 u   명.r   r   r
   r   u    합류. 현재 r   r   r-   r)   u#    담당만 남았습니다. 현재 r   r,   u   만 남았습니다. 현재 r   r   u-   자동 대화 모드: 계속 진행합니다.u   자동 발화 u   턴으로 설정.)r_   r   r   r  r%  popr  r}   removerb   r  max_auto_turnsr_  )rS   r   ctyper   removedr  removed_namesr   r+   new_personasr-   r,   s               rH   handle_controlzGroupChatSession.handle_control  s7   F#$$G$Eqys4==))--/ $fu 5MT U!1!1!!4!8!8!C U U  3A%%))!T23((?499];S:TTdejdkko)pq * &&)$Cdmm#DMM(:Q(>'',00=$$S)!!%%c40((D61A#dmmBTAUUY)Z[	 )?# m#)$C$--''',00=$$S))*!!#&((D61A#dmmBTAUUY)Z[	 ( &&'.z':b!a4C_C_Ca>aAbLb 7A,))--a67 & 1A 1 11/0))!,1 !-{{62.((D61TUXY]YfYfUgThhl)mn  &&'.z':b!a4C_C_Ca>aAbLb 7A,))--a67 & 1A 1 11/0))!,1 !-{{62.((D61McRVR_R_N`Maae)fg  &&G$E"'DDO{(()XY((>%@Q)RS 'e !V. c cs   !(O1'O6?O6/O;O;c                    | j                   syt        j                         | j                  z
  t        kD  r't        j                  d       | j                  d       yt        | dt              }| j                  |k\  ry| j                  D cg c]#  }| j                  |      j                  d|      % }}	 t        || j                  | j                  | j                         }	 | j'                  |       yc c}w # t"        $ r1}t        j%                  d|        | j                  d   }Y d}~Md}~ww xY w# t"        $ r;}| j)                  dt+        |      dd	         | j                  d
       Y d}~yd}~ww xY w)u   대화 1턴 실행 (발화자 선택 → 응답 → 전송).

        메인 루프에서 매 반복마다 호출된다.
        기존 run_loop()의 단일 턴 로직을 분리한 것.
        Nu-   5분 타임아웃으로 세션 자동 종료.r;   r  r+   u   발화자 선택 실패: r   u6   ⚠️ 시스템 오류로 단톡을 종료합니다: d   r   )r   r  r^  SESSION_TIMEOUTrd   r   rV  getattrMAX_AUTO_TURNSr_  r   rh  r_   rY  rs   rB  r%  rc   r   r  rc  ra   )rS   	max_turnsr   rA  next_keyrk   s         rH   run_one_turnzGroupChatSession.run_one_turn  sM    {{ 99;+++o=KKGHHHY D"2NC	??i' CG--PQq)--fa8PP		(*!!!!	H	JJx  Q  	(LL4QC89}}Q'H	(  	IINsSTvVZWZ|n]^HHW	s6   (C67,C; $D8 ;	D5'D00D58	E<1E77E<c                    | j                   rt               }|r}|j                  d      }|dk(  r&|j                  dd      }|rS| j                  |       nA|dk(  r"| j	                  |j                  dd             y|d	k(  rt
        j                  d
       | j                          | j                   syt        j                  t               | j                   ryy)u[   메인 대화 루프 (하위 호환용, 트리거 파일만 사용하는 레거시 모드).actionr   r[   r)   rV  r  	user_exitNrU  u,   활성 세션 중 start 트리거 무시됨.)r   r  r_   r  rV  rd   re   r  r  r  POLL_INTERVAL)rS   rs  r  rj   s       rH   run_loopzGroupChatSession.run_loop0  s    kk"nG X.\)!++i4C++C0u_HHW[[;?@w&NN#QR;;JJ}%) kkrJ   N)r  )rm   rn   ro   ra   re  rT   rc  rh  rk  ro  rr  rU  r  boolr  rV  r  rq   r  r  r  r  r  r  rr   rJ   rH   r[  r[    s    c $ 6 6C D ; ; ;

 


Dd 
D+%T +%Z=c =3 4 2!4# !4F4 / /B B"s "t "DTd DTL'R&rJ   r[  c           	      2   t               }|sy|j                  d      }t        j                  d|        |dk(  rI| j	                         r&t        j                  d       | j                  d       	 | j                  |       y|dk(  rM| j	                         r&|j                  dd      }|r(| j                  |       yt        j                  d       yy|dk(  rH| j	                         r"| j                  |j                  dd             yt        j                  d       yy# t        $ rh}t        j                  d|        	 t        ||j                  dt              d	t        |      dd
         n# t        $ r Y nw xY wY d}~yY d}~yd}~ww xY w)u8   트리거 파일을 확인하고 세션에 반영한다.Nr  u   트리거 감지: action=rU  u@   이미 활성 세션 있음. 기존 세션 종료 후 재시작.restartu   세션 시작 오류: rN   u   ⚠️ 세션 시작 오류: r  r   r[   r)   u(   활성 세션 없음. user_input 무시.rV  r  r  u!   활성 세션 없음. end 무시.)r  r_   rd   r   r  re   rV  rU  rc   r   r  r]  ra   r  )r  rM   rs  r  rk   rj   s         rH   check_trigger_filer  J  sl   nG[["F
KK+F845NN]^KK	"	MM'" 
<	++i,C&&s+NNEF 
 
5KKHk:;NN>?	 
  	LL1!56eW[[O%LPmnqrsntuyvynzm{N|}  ~	s<   3D% %	F.F0E87F8	FFFFFc            
      6  	 t                t        j                  j                  t              s1t
        j                  dt                t        j                  d       t               } t               }t        | |      	t        | t              }t               }|r@	j                  |       t
        j!                  d	j"                   d	j$                          	fd}t'        j&                  t&        j(                  |       t'        j&                  t&        j*                  |       t
        j!                  d       	 	 |j-                         }|D ]0  }t/        |	j1                               }|d   d	k(  rN	j1                         s>	j3                  d
|j5                  dd      |j5                  dg d      t        |d       t|d   dk(  r2	j1                         r"	j7                  |j5                  d|             |d   dk(  r#	j1                         r	j9                  d       |d   dk(  r#	j1                         r	j;                  |       |d   dk(  s	j1                         r t=        | t        d       3 t?        	|        	j1                         r	jA                          tC        jD                  tF               # tH        $ r Y y tJ        $ r7}t
        j                  d|        tC        jD                  d       Y d }~Gd }~ww xY w)Nu'   Claude CLI를 찾을 수 없습니다: r   )rN   u   세션 복구: 주제=u   , 참여자=c                     t         j                  d|  d       j                         rj                  d       t	        j
                  d       y )Nu
   시그널 u    수신. Graceful shutdown...daemon_shutdownr   )rd   r   r  rV  sysexit)signumframer  s     rH   	_shutdownzmain.<locals>._shutdown  s=    j(EFGKK)*rJ   uI   그룹챗 데몬 시작. Telegram 폴링 + 트리거 파일 감시 중...r   r   rU  r   r   r   r   )r  r   r   rN   r2   r   r[   r   r  )r  r   r   up   💬 안녕하세요! 팀 단톡을 시작하려면 "팀 모여" 또는 "회의하자"라고 말씀해주세요.u   메인 루프 오류: rW   )&r   r   r   r   r=   rd   r   r  r  r   r   r[  rL   r]  r!  rr  r   r   r   signalSIGTERMSIGINTrl   r   r  rU  r_   r  rV  r  r  r  r  r  r  r  KeyboardInterruptrc   )
rM   r   pollersavedr  rh   rj   r   rk   r  s
            @rH   mainr  p  s   O 77>>/*>>OPQE!OMum4GE?;F NE% ,W]]O<HXHXGYZ[ MM&..),
MM&--+
KK[\
*	))+H &sG,=,=,?@(#|3G<M<M<OMM&-%+ZZ%I(.

:?[(\'6,/ H%5':K:K:M**6::i+EFH%38I8I8KKK{K3H%2w7H7H7J**62H%/8I8I8K!' K)6 w.   "$$&JJ}%K N ! 	 	LL1!56JJqMM	s,   DK !K 3AK 	LL!-LL__main__)r   zclaude-sonnet-4-6)   )>rp   r`   loggingr   r  r?   r  r  r   pathlibr   r^   	WORKSPACEr  r  r(  r   r   r   r]  r  r  r  r   r   CONTROL_TYPESr   r   r   r   r  basicConfigINFO	getLoggerrm   rd   r   r=   ra   r   rI   rL   rq   r   r  re  r   r   r   r   r   r  r  r  r  r!  r6  r@  rY  r[  r  r  rr   rJ   rH   <module>r     so  
   	   
     "	BCBCk'	+23!{"EF +Z( iN *"%(%0 .*0
&/& <A:@6<.Hh  	
 G f f G   
4 H     f!" #$ '.e
I 	( f	
 F i V F U V 	 h F V V  F!" V#$ '	.   
,,6
 
		8	$
 N^ !IX %MU %>[ +?X H_ "HXc9 z 0 $	!!! ! 	!
 	!>! !HD # s "{ {T {d {~54o o6g gVt 6!C ! ! ! 	 	s 	# 	dTk 3$ 3dTk  :d :8,H,H,H ,H 	,H
 	,H` A A A  A 	 A
 	 AHx& x&x	"@ 0 "@ "@LK\ zF rJ   