
    i                       U d Z ddlmZ ddlZddlZddlmZ ddlmZmZm	Z	 ddl
mZ ddlmZ ddlmZmZ d	Zd
ZdZded<   dZded<   ddddddZded<    e	 ed            Zd(dZd)dZd*dZd+dZd,dZd-d Zed!k(  r eej@                        d"kD  r eej@                  d"         n ee      Z! eej@                        d#kD  r eej@                  d#         n ee      Z"e!jG                         s) e$d$e! ejJ                  %        ejL                  d"        e$d&e!         ee!      Z'e's e$d'        ejL                  d        ee'        ee'e"       yy).u?  Telegram HTML 내보내기 파일을 conversation_memory.py 호환 JSONL로 변환.

사용법:
    python html_to_jsonl.py [INPUT_HTML] [OUTPUT_JSONL]

기본값:
    INPUT_HTML  = /home/jay/.cokacdir/workspace/autoset/messages.html
    OUTPUT_JSONL = /home/jay/workspace/memory/groupchat/test-import-2026-03-15.jsonl
    )annotationsN)Counter)datetime	timedeltatimezone)Path)Optional)BeautifulSoupTagz3/home/jay/.cokacdir/workspace/autoset/messages.htmlzA/home/jay/workspace/memory/groupchat/test-import-2026-03-15.jsonli intCHAT_IDgeneralstr	TOPIC_TAG)u   제이회장님F)	   잼민이T)	   코덱스T)	   클로디T)u   아누T)JJongsr   r   r   u   아누(ANU) AI비서zdict[str, tuple[str, bool]]
SENDER_MAP	   )hoursc                    | j                  dd      j                         }	 t        j                  |d      }|S # t        $ r Y yw xY w)ui   '15.03.2026 14:52:14 UTC+09:00' 형식을 datetime으로 변환.

    파싱 실패 시 None 반환.
    UTC z%d.%m.%Y %H:%M:%S %zN)replacestripr   strptime
ValueError)title
normalizeddts      B/home/jay/workspace/services/multimodel-bot/tools/html_to_jsonl.pyparse_timestampr#   2   sL     ub)//1Jz+AB	 s   : 	AAc                R    | j                         }t        j                  ||df      S )u   HTML 발신자 이름을 (정규화 이름, is_bot) 으로 변환.

    매핑에 없는 이름은 원본 그대로 + is_bot=False 로 처리.
    F)r   r   get)raw_namestrippeds     r"   resolve_senderr(   A   s&    
 ~~H>>(Xu$566    c                t    | j                  d      D ]  }|j                  d        | j                  d      S )u   text div 내 HTML 태그를 제거하고 순수 텍스트만 반환.

    a 태그는 href 대신 텍스트만 남긴다. <br> 태그는 개행으로 처리.
    br
r   )	separator)find_allreplace_withget_text)text_divr+   s     r"   extract_textr2   J   s>     % 
r**r)   c                   t        | dd      5 }t        |d      }ddd       g }d}j                  dd	      }|t        d
t        j
                         |S |j                  dd	      D ]H  }t        |j                  d      xs g       }d|v r'd|vr,|j                  dd	      }|Bd|v r|}	n,|j                  dd	      }
|
|}	n|
j                  d      }	|	}|	sx|j                  dd	      }||j                  d      xs d}t        t        |            }|t        d|t        j
                         |j                  dd	      }|t        |      j                         }|st        |	      \  }}|||j                         |t         t"        d}|j%                  |       K |S # 1 sw Y   xY w)u@   HTML 파일을 파싱하여 JSONL 레코드 리스트를 반환.rutf-8encodingzhtml.parserNr   divhistory)class_u/   [WARN] .history div를 찾을 수 없습니다.filemessageclassservicedefaultbodyjoined	from_nameT)r   dater   u&   [WARN] 타임스탬프 파싱 실패: text)senderrE   	timestampis_botchat_id	topic_tag)openr
   findprintsysstderrr.   setr%   r0   r#   r   r2   r   r(   	isoformatr   r   append)	html_pathfhsouprecordslast_sender_rawhistory_divmsg_divclassesbody_div
sender_rawfrom_name_divdate_div
title_attrtsr1   rE   sender_namerH   records                      r"   parse_html_to_recordsrc   Z   s    	iw	/ 02R/0 GO ))E))4K?cjjQ''i'@ >gkk'*0b1  G#<<f<5 w(J$MM%MDM$,
*33$3?
", ==v=6\\'*0b
S_-:::.IPSPZPZ[ ==v=6H%++- -Z8V ""
 	v}>@ NY0 0s   F;;Gc           
     "   t        |       }t        d | D              }||z
  }t        d | D              }t        dd        t        d       t        d        t        d|d       t        |rd|dd	||z  d
z  ddnd       t        |rd|dd	||z  d
z  ddnd       t                t        d       |j	                         D ]4  \  }t        fd| D              }|rdnd}t        d| d d|d       6 t        d d       y)u%   변환 결과 통계를 출력한다.c              3  ,   K   | ]  }|d    s	d  yw)rH      N .0r4   s     r"   	<genexpr>zprint_stats.<locals>.<genexpr>   s     6!!H+A6s   
c              3  &   K   | ]	  }|d      yw)rF   Nrg   rh   s     r"   rj   zprint_stats.<locals>.<genexpr>   s     %Caak%Cs   r,   z2==================================================u   변환 통계u   총 메시지 수  : ,u   봇 메시지     :  (d   z.1fz%)u   봇 메시지     : 0u   사람 메시지   : u   사람 메시지   : 0u   발신자별 메시지 수:c              3  :   K   | ]  }|d    k(  s|d     yw)rF   rH   Nrg   )ri   r4   rF   s     r"   rj   zprint_stats.<locals>.<genexpr>   s      KQQx[F5JQx[Ks   
u   [봇]u   [사람]z   z: N)lensumr   rM   most_commonany)	rV   total	bot_counthuman_countsender_countercountrH   labelrF   s	           @r"   print_statsr{      s3   LE6w66I)#K%%C7%CCN	Bxj/	/	XJ	!%
+,	SX 1R	E0AC0G/LB
O^uv	X]!+a;3F3LS2QQS
Tc{|	G	
'('335 0K'KK!z5'6("U1I./0 
XJb/r)   c                   |j                   j                  dd       t        |dd      5 }| D ]+  }|j                  t	        j
                  |d      dz          - 	 d	d	d	       t        d
| dt        |       dd       y	# 1 sw Y   &xY w)u.   레코드 리스트를 JSONL 파일로 저장.T)parentsexist_okwr5   r6   F)ensure_asciir,   Nu   저장 완료: rm   rl   u   줄))parentmkdirrK   writejsondumpsrM   rq   )rV   output_pathrT   rb   s       r"   write_jsonlr      s    TD9	k3	1 DR 	DFHHTZZU;dBC	DD 
OK=3w<*:$
?@D Ds   1BB__main__rf      u2   [ERROR] 입력 파일을 찾을 수 없습니다: r;   u   파싱 중: u+   [WARN] 변환된 메시지가 없습니다.)r   r   returnzOptional[datetime])r&   r   r   ztuple[str, bool])r1   r   r   r   )rS   r   r   
list[dict])rV   r   r   None)rV   r   r   r   r   r   )(__doc__
__future__r   r   rN   collectionsr   r   r   r   pathlibr   typingr	   bs4r
   r   DEFAULT_INPUTDEFAULT_OUTPUTr   __annotations__r   r   TZ_KSTr#   r(   r2   rc   r{   r   __name__rq   argv
input_pathr   existsrM   rO   exitrV   rg   r)   r"   <module>r      so   #  
  2 2   " FT 	3  )$$$,+
'  
)!$	%7+ Nl8A z&)#((ma&7chhqk"T-=PJ'*388}q'8$sxx{#d>>RKB:,OVYV`V`a	L
%&#J/G;<%! r)   