
    i2                    D    d Z ddlmZ ddlZddlZddlmZ  G d d      Zy)uy   
knowledge_graph.py
Phase 2: InsightV2 기반 옵시디언 스타일 지식 그래프 빌더
작성자: 루 (개발3팀)
    )annotationsN)defaultdictc                  j    e Zd ZdZdZdZdZdZddZddZ	dddZ
dd	Zdd
ZddZddZddZddZy)KnowledgeGraphu?   인사이트 간 관계를 관리하는 지식 그래프 빌더g?g      ?gffffff?g333333?c                J    || _         || _        || _        i | _        i | _        y)u   
        Args:
            insights_dir: 마크다운 인사이트 파일 저장 경로
            graph_path: graph.json 저장 경로
            index_path: insights_index.json 저장 경로
        N)insights_dir
graph_path
index_path_graph_index)selfr   r	   r
   s       b/home/jay/projects/insuwiki/.worktrees/task-1557.1-dev3/scripts/kakao_knowledge/knowledge_graph.py__init__zKnowledgeGraph.__init__   s*     )$$     c                   t        j                  | j                        j                  dd       |D ]  }| j	                  |        | j                  |      }| j                  ||      | _        t        j                  | j                        j                  j                  dd       t        j                  | j                        j                  t        j                  | j                  dd      d       | j                  |      | _        t        j                  | j                        j                  j                  dd       t        j                  | j                        j                  t        j                  | j                  dd      d       t!        t"              }|D ]  }||j%                  dd	      xx   d
z  cc<   ! t'        |      t'        |      t)        |      dS )uq  InsightV2 dict 리스트로부터 전체 그래프를 구축한다.

        1. 각 인사이트를 마크다운 파일로 저장 (insights/ 디렉토리)
        2. 자동 연결 로직으로 edge 생성
        3. graph.json 저장
        4. insights_index.json 저장

        Returns:
            {"nodes": int, "edges": int, "categories": dict[str, int]}
        T)parentsexist_okF   )ensure_asciiindentutf-8encodingcategory   기타   )nodesedges
categories)pathlibPathr   mkdir_save_insight_as_markdown_build_edges_build_graph_jsonr   r	   parent
write_textjsondumps_build_indexr   r
   r   intgetlendict)r   insightsinsightr   r   s        r   build_from_insightsz"KnowledgeGraph.build_from_insights*   s    	T&&'--dT-J   	4G**73	4 !!(+ ,,Xu=T__%,,224$2OT__%00JJt{{qA 	1 	
 ''1T__%,,224$2OT__%00JJt{{qA 	1 	
 &1%5
 	?Gw{{:x89Q>9	? ]Zz*
 	
r   c                   | j                   sg S | j                   j                  dg       }| j                   j                  dg       D ci c]  }|d   |
 }}|h}|h}g }t        |      D ]  }	t               }
|D ]A  }|d   }|d   }||v r||vr|
j	                  |       '||v s,||vs1|
j	                  |       C |
D ]+  }||v r|j                  ||          |j	                  |       - |
} |S c c}w )u   특정 인사이트의 연결된 인사이트 목록 반환.

        max_depth=1: 직접 연결만
        max_depth=2: 2-hop 연결까지
        r   r   idfromto)r   r,   rangesetaddappend)r   
insight_id	max_depthr   nnodes_by_idvisitedcurrent_frontierresult_next_frontieredgefrmr5   nids                  r   get_relatedzKnowledgeGraph.get_relatedZ   s%    {{I,+/;;??7B+GHaqwzHH'L&0\y! 	-A&)eM +6l$Z**r/@!%%b)++70B!%%c*+ % !+%MM+c"23C !  -	- + Is   	C4c                    | j                   sg S t        | j                   j                  di       j                  |g             S )u    태그로 인사이트 ID 검색by_tagr   listr,   )r   tags     r   search_by_tagzKnowledgeGraph.search_by_tag{   s5    {{IDKKOOHb155c2>??r   c                    | j                   sg S t        | j                   j                  di       j                  |g             S )u&   카테고리로 인사이트 ID 검색by_categoryrI   )r   r   s     r   search_by_categoryz!KnowledgeGraph.search_by_category   s5    {{IDKKOOM26::8RHIIr   c                2   |j                  dd      }|j                  dd      }|j                  dd      }|j                  dd      }|j                  dg       }|j                  dg       }|j                  d	d      }|j                  d
d      }	|j                  dd      }
|j                  dd      }|j                  dg       }|j                  dd      }|j                  dd      }ddj                  |      z   dz   }ddj                  |      z   dz   }dd| d| d| d| d| d| d| d|	 d|
 dg}dj                  |      }g }|dk(  rm|j                  d        |j                  |       |j                  d!       |}|D ]!  }|s||v s|j                  |d"| d#d$      }# |j                  |       n"|j                  d%       |j                  |       |j                  d&       |D ]  }|j                  d'|         |r-|j                  d(       |D ]  }|j                  d)| d#        dj                  |      }|dz   |z   dz   }t	        j
                  | j                        | d*z  }|j                  |d+,       |S )-uw   단일 인사이트를 마크다운 파일로 저장.

        파일 형식 (YAML frontmatter + 마크다운)
        r3   unknowntitle typer   tagsrelated_topicsexpert
confidencemediumsource_datesummary
key_pointsquestionanswer[z, ]z---zid: ztitle: ztype: z
category: ztags: z	related: zexpert: zconfidence: zsource_date: 
qau
   
## 질문u
   
## 답변z[[z]]r   u
   
## 요약u   
## 핵심 포인트z- u   
## 관련 인사이트z- [[.mdr   r   )r,   joinr9   replacer    r!   r   r'   )r   r0   r:   rR   ityper   rU   relatedrW   rX   rZ   r[   r\   r]   r^   	tags_yamlrelated_yamlfrontmatter_linesfrontmatter
body_linesanswer_textrK   pointrelbodycontentout_paths                              r   r#   z(KnowledgeGraph._save_insight_as_markdown   s   
 "++dI6
[["-[[,J3[[,$4b9kk(B/!++lH=
";;}b9{{9b1";;|R8
J3kk(B/ $))D/)C/	TYYw//#5 :,eWUG
#YK ~&vh:,'K=)
 ii 12 !#
D=m,h'm, K L3+-"-"5"5cRuB<"KKL k*m,g& 	12 	,E5'l+	,
 89 2!!DR.12 yy$$t+d2<< 1 12
|35GGGg6r   c                   i }t        |      }t        |      D ]  }t        |dz   |      D ]  }||   }||   }|d   }|d   }	t        |j                  dg             }
t        |j                  dg             }|
|z  r't	        ||	g      df}||vr||	d| j
                  d||<   |j                  dd      }|j                  dd      }|r.|r,||k(  r't	        ||	g      df}||vr||	d| j                  d||<   t        |j                  d	g             }t        |j                  d	g             }t        ||z        d
k\  r't	        ||	g      df}||vr||	d| j                  d||<   |j                  dd      }|j                  dd      }|sd|sh||k(  sot	        ||	g      df}||vs||	d| j                  d||<     t        |j                               S )u<  자동 연결 로직으로 edge를 생성한다.

        4가지 연결 방법:
        1. 태그 기반: 같은 태그를 가진 인사이트끼리 연결 (relation: "shared_tag")
        2. 카테고리 기반: 같은 카테고리/서브카테고리 연결 (relation: "same_category")
        3. 키워드 중복: related_topics 교집합 2개 이상이면 연결 (relation: "related_topic")
        4. 전문가 기반: 같은 expert가 답변한 인사이트 연결 (relation: "same_expert")

        중복 엣지 제거 (A→B와 B→A는 하나만 유지)
        r   r3   rU   
shared_tag)r4   r5   relationweightr   rS   same_categoryrV   r   related_topicrW   same_expert)r-   r6   r7   r,   	frozensetWEIGHT_SHARED_TAGWEIGHT_SAME_CATEGORYWEIGHT_RELATED_TOPICWEIGHT_SAME_EXPERTrJ   values)r   r/   seenr<   ijabid_aid_btags_atags_bkeycat_acat_brt_art_bexpert_aexpert_bs                      r   r$   zKnowledgeGraph._build_edges   s     #%Mq 9	A1q5!_ 8QKQKww QUU62./QUU62./F?$dD\2LAC$$("&(4&*&<&<	%S	 j"-j"-Uu~$dD\2ODC$$("&(7&*&?&?	%S	 155!1267155!1267td{#q($dD\2ODC$$("&(7&*&?&?	%S	 552.552.X-A$dD\2MBC$$("&(5&*&=&=	%S	g89	v DKKM""r   c                   |D cg c]M  }|d   |j                  dd      |j                  dd      |j                  dd      |j                  dg       dO }}t        t              }t        t              }|D ]<  }||j                  dd      xx   d	z  cc<   ||j                  dd
      xx   d	z  cc<   > ||t        |      t        |      t	        |      t	        |      ddS c c}w )u   graph.json 구조 생성.r3   rR   rS   r   rT   rU   )r3   rR   r   rT   rU   r   r   rQ   )total_nodestotal_edgesr   types)r   r   stats)r,   r   r+   r-   r.   )r   r/   r   r0   r   r   r   s          r   r%   z KnowledgeGraph._build_graph_json!  s     $	
  dm Wb1#KK
B7FB/FB/	
 	
 &1%5
 +C 0 	7Gw{{:x89Q>9'++fi01Q61	7
 "5z"5z":.e		
 		
#	
s   AC'c                b   i }t        t              }t        t              }t        t              }t        t              }|D ]  }|d   }|j                  dd      }	|j                  dd      }
|j                  dd      }|j                  dd      | d	d
||<   ||	   j                  |       |j                  dg       D ]  }||   j                  |        |
r||
   j                  |       ||   j                  |        |t	        |      t	        |      t	        |      t	        |      dS )u"   빠른 조회용 인덱스 생성.r3   r   r   rW   rS   rT   rQ   rR   rc   )rR   filerU   )by_idrN   rH   	by_expertby_type)r   rJ   r,   r9   r.   )r   r/   r   rN   rH   r   r   r0   iidr   rW   rf   rK   s                r   r*   zKnowledgeGraph._build_index?  s2   !#'24'8"-d"3%0%6	#.t#4 	'G$-C{{:x8H[[2.FKK	2E !Wb1%sE#J
 !((-{{62. (s""3'( &!((-EN!!#&'	', ,6liG}
 	
r   N)r   strr	   r   r
   r   )r/   
list[dict]returnr.   )r   )r:   r   r;   r+   r   r   )rK   r   r   	list[str])r   r   r   r   )r0   r.   r   zpathlib.Path)r/   r   r   r   )r/   r   r   r   r   r.   )__name__
__module____qualname____doc__r{   r|   r}   r~   r   r1   rF   rL   rO   r#   r$   r%   r*    r   r   r   r      sT    I &.
`B@JHTJ#X
<#
r   r   )r   
__future__r   r(   r    collectionsr   r   r   r   r   <module>r      s$    #   #T
 T
r   