옵시디언(Obsidian)은 텍스트 기반 노트 관리 도구로, 그래프 뷰(Graph View)를 통해 노트 간의 연결을 시각적으로 탐색할 수 있는 강력한 기능을 제공합니다. 이 글에서는 파이썬과 KiwiPiePy를 활용하여 자동으로 키워드를 추출하고 옵시디언 노트 메타데이터에 태그를 추가하는 방법을 코드와 함께 상세히 설명합니다.
코드 개요
이 코드의 주요 기능은 다음과 같습니다:
- 텍스트 키워드 추출: KiwiPiePy 라이브러리와 TextRank 알고리즘을 사용하여 노트 내용에서 중요한 키워드를 추출합니다. Kiwi는 한국어 텍스트 분석에 최적화된 라이브러리로, 복잡한 형태소를 정확히 분리하여 의미 있는 명사를 추출하는 데 적합합니다.
- 태그 업데이트: 기존 태그와 추출한 키워드를 병합하여 노트의 메타데이터에 태그를 추가합니다.
- 폴더 내 파일 처리: 지정된 폴더 내 모든
.md
파일을 대상으로 작업을 수행합니다.
TextRank는 TF-IDF와 같은 통계적 방법론과 달리 단어 간의 연결성을 기반으로 가중치를 계산합니다. 따라서 문맥 속에서 중요도가 높은 단어를 더 효과적으로 추출할 수 있습니다.
코드 상세 설명
주요 라이브러리 및 초기 설정
import os
from kiwipiepy import Kiwi
from collections import defaultdict
kiwi = Kiwi()
stopwords = {'수학', '을'}
Kiwi: 한국어 형태소 분석을 위한 라이브러리로, 명사와 고유 명사를 추출하는 데 사용됩니다. 한국어의 복잡한 문법 구조를 처리하기 위해 Kiwi를 선택하였으며, 이는 형태소를 정확히 분석하여 키워드 추출 과정에서 불필요한 단어를 배제합니다.
stopwords
는 키워드 추출 시 제외할 불용어를 정의합니다. 예를 들어, 코드는 명사만을 키워드로 설정하게 되어있지만 "을"과 같은 조사가 명사로 인식되는 경우가 있었습니다. 이 때는 불용어를 설정하여 주제와 관련 없는 단어를 걸러낼 수 있습니다.
텍스트에서 키워드 추출하기
def extract_keywords_textrank(text, top_n=20):
kiwi_tokens = kiwi.tokenize(text)
kiwi_keywords = [token.form for token in kiwi_tokens if token.tag in ('NNG', 'NNP') and token.form not in stopwords]
graph = defaultdict(list)
for i, word in enumerate(kiwi_keywords):
for j in range(i+1, min(i+5, len(kiwi_keywords))):
graph[word].append(kiwi_keywords[j])
graph[kiwi_keywords[j]].append(word)
scores = {word: 1.0 for word in kiwi_keywords}
d = 0.85
for _ in range(10):
new_scores = {}
for word in scores:
new_scores[word] = (1 - d) + d * sum(scores[neighbor] / len(graph[neighbor]) for neighbor in graph[word])
scores = new_scores
sorted_keywords = sorted(scores.items(), key=lambda x: x[1], reverse=True)
top_keywords = [keyword for keyword, score in sorted_keywords[:top_n] if round(score, 2) > 3]
return top_keywords
텍스트 분석 과정:
- Kiwi를 사용해 문장을 형태소 단위로 분리합니다. 이는 한국어 문장의 조사나 어미를 정확히 처리하여 키워드로 적합한 단어만 추출하기 위함입니다.
- 키워드를 연결 그래프에 추가하여 관계를 모델링합니다. 각 키워드는 최대 5개까지 이웃 단어와 연결되며, 이는 TextRank 알고리즘의 기본 구조를 형성합니다.
- TextRank 알고리즘으로 각 키워드의 중요도를 계산합니다. 알고리즘은 Google의 PageRank 방식을 차용하여 단어의 연결 관계를 기반으로 가중치를 부여합니다.
왜 TextRank를 사용했는가?
TextRank는 단어 간의 연결성을 활용하므로 문맥상 중요한 단어를 더 잘 식별할 수 있습니다. TF-IDF가 더 빨랐지만 단순 빈도와 문서 내 분포만을 고려하기 때문에 문맥을 반영하지 못하는 경우가 있었습니다.
키워드 선정 기준:
최종적으로 중요도가 3점 이상인 키워드만 태그로 선정하였습니다. 이는 테스트를 통해 3점 이상인 단어들이 본문과 잘 맞는 태그로 사용된다는 결론을 바탕으로 설정한 기준입니다.
파일 처리 및 태그 업데이트
def process_file(file_path):
with open(file_path, 'r', encoding='utf-8') as file:
lines = file.readlines()
if '---\n' in lines:
metadata_start = lines.index('---\n')
try:
metadata_end = lines.index('---\n', metadata_start + 1)
except ValueError:
metadata_end = metadata_start
metadata = lines[:metadata_end + 1]
content = ''.join(lines[metadata_end + 1:])
else:
metadata = ['---\n', 'tags:\n', '---\n']
content = ''.join(lines)
existing_tags = []
for line in metadata:
if line.startswith('tags:'):
existing_tags = [tag.strip() for tag in line.split(':')[1].strip().split('-') if tag.strip()]
break
keywords = extract_keywords_textrank(content)
new_tags = existing_tags + [keyword for keyword in keywords if keyword not in existing_tags]
for i, line in enumerate(metadata):
if line.startswith('tags:'):
metadata[i] = 'tags:\n' + '\n'.join([f' - {tag}' for tag in new_tags]) + '\n'
break
else:
metadata.insert(1, 'tags:\n' + '\n'.join([f' - {tag}' for tag in new_tags]) + '\n')
with open(file_path, 'w', encoding='utf-8') as file:
file.writelines(metadata + lines[metadata_end + 1:] if '---\n' in lines else metadata + lines)
메타데이터와 본문 처리:
- 노트의 메타데이터(
tags
)와 본문 내용을 분리합니다. - 기존 태그와 새로 추출된 키워드를 병합해 중복을 제거합니다.
- 새롭게 생성된 태그를 메타데이터에 추가한 뒤 파일을 업데이트합니다.
이 과정에서 사용자는 메타데이터 구조를 자신에게 맞게 수정할 수 있습니다.
폴더 내 모든 파일 처리
folder_path = 'Obsidian/4. Archives'
for root, dirs, files in os.walk(folder_path):
for file in files:
if file.endswith('.md'):
file_path = os.path.join(root, file)
process_file(file_path)
사용자가 작업할 폴더 경로를 folder_path
에 지정하면, 해당 폴더와 하위 디렉토리에 포함된 모든 .md
파일에 대해 자동으로 태그 추가 작업을 수행합니다. 사용자 환경에 맞게 folder_path
를 수정하세요.
옵시디언에서의 활용
자동 태그 추가: 코드 실행 후 노트를 열어 보면 메타데이터에 태그가 추가된 것을 확인할 수 있습니다. 이를 통해 노트의 주요 주제를 태그 형태로 정리할 수 있습니다.
그래프 뷰 활용: 추가된 태그를 기반으로 옵시디언의 그래프 뷰에서 노트 간 연결성을 시각화할 수 있습니다. 키워드를 중심으로 관련 노트를 빠르게 탐색할 수 있습니다. 옵시디언에서 백링크로 노트를 연결해서 second brain을 만드는데는 시간이 오래걸리지만, 태그로 노트를 연결하면 빠르고 편리하게 노트간의 연결을 만들 수 있습니다.
결론
이 코드는 옵시디언에서 자동으로 태그를 생성하여 효율적으로 노트를 관리할 수 있도록 돕습니다. 키워드를 활용한 태그 생성은 수작업을 줄이고, 그래프 뷰에서 관계성을 쉽게 파악하는 데 유용합니다. 필요에 따라 코드를 수정하여 개인 워크플로우에 맞게 활용해 보세요.
You know what's cooler than magic? Math.
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!