|
import os |
|
import gradio as gr |
|
import git |
|
import tempfile |
|
import shutil |
|
from datetime import datetime |
|
from typing import List, Dict, Tuple, Optional |
|
import re |
|
|
|
class TranslationTracker: |
|
def __init__(self): |
|
self.repo_url = "https://github.com/huggingface/transformers.git" |
|
self.repo_path = None |
|
self.en_docs_path = None |
|
self.ko_docs_path = None |
|
self.repo = None |
|
|
|
def clone_repo(self, progress=gr.Progress()): |
|
"""Transformers 레포지토리를 클론합니다.""" |
|
try: |
|
|
|
temp_dir = tempfile.mkdtemp() |
|
progress(0.1, desc="레포지토리 클론 준비 중...") |
|
|
|
|
|
progress(0.2, desc="레포지토리 클론 중...") |
|
self.repo = git.Repo.clone_from(self.repo_url, temp_dir, depth=1) |
|
self.repo_path = temp_dir |
|
|
|
|
|
self.en_docs_path = os.path.join(self.repo_path, "docs", "source", "en") |
|
self.ko_docs_path = os.path.join(self.repo_path, "docs", "source", "ko") |
|
|
|
progress(1.0, desc="레포지토리 클론 완료") |
|
return f"레포지토리 클론 완료: {self.repo_path}" |
|
except Exception as e: |
|
return f"레포지토리 클론 실패: {str(e)}" |
|
|
|
def cleanup(self): |
|
"""임시 디렉토리 정리""" |
|
if self.repo_path and os.path.exists(self.repo_path): |
|
shutil.rmtree(self.repo_path) |
|
self.repo_path = None |
|
self.repo = None |
|
|
|
def get_last_commit_date(self, file_path: str) -> Optional[datetime]: |
|
"""파일의 마지막 커밋 날짜를 가져옵니다.""" |
|
try: |
|
|
|
if not os.path.exists(file_path): |
|
return None |
|
|
|
|
|
rel_path = os.path.relpath(file_path, self.repo_path) |
|
|
|
|
|
for commit in self.repo.iter_commits(paths=rel_path, max_count=1): |
|
return commit.committed_datetime |
|
|
|
return None |
|
except Exception: |
|
return None |
|
|
|
def get_translation_status(self, progress=gr.Progress()) -> List[Dict]: |
|
"""모든 영어 문서와 해당하는 한글 번역 상태를 확인합니다.""" |
|
if not self.repo_path: |
|
return [{"error": "레포지토리가 클론되지 않았습니다. 먼저 클론을 수행하세요."}] |
|
|
|
results = [] |
|
en_md_files = [] |
|
|
|
|
|
progress(0.1, desc="영어 문서 스캔 중...") |
|
for root, _, files in os.walk(self.en_docs_path): |
|
for file in files: |
|
if file.endswith(".md"): |
|
en_md_files.append(os.path.join(root, file)) |
|
|
|
total_files = len(en_md_files) |
|
|
|
|
|
for i, en_file in enumerate(en_md_files): |
|
progress((i + 1) / total_files, desc=f"번역 상태 확인 중 ({i+1}/{total_files})...") |
|
|
|
|
|
rel_path = os.path.relpath(en_file, self.en_docs_path) |
|
ko_file = os.path.join(self.ko_docs_path, rel_path) |
|
|
|
|
|
file_name = os.path.basename(en_file) |
|
|
|
|
|
en_commit_date = self.get_last_commit_date(en_file) |
|
|
|
|
|
ko_commit_date = self.get_last_commit_date(ko_file) |
|
|
|
|
|
if ko_commit_date is None: |
|
status = "미번역" |
|
outdate = False |
|
else: |
|
if en_commit_date > ko_commit_date: |
|
status = "번역됨 (업데이트 필요)" |
|
outdate = True |
|
else: |
|
status = "번역됨 (최신)" |
|
outdate = False |
|
|
|
|
|
results.append({ |
|
"file_name": file_name, |
|
"en_path": rel_path, |
|
"ko_path": rel_path if os.path.exists(ko_file) else "없음", |
|
"en_last_commit": en_commit_date.strftime("%Y-%m-%d %H:%M:%S") if en_commit_date else "알 수 없음", |
|
"ko_last_commit": ko_commit_date.strftime("%Y-%m-%d %H:%M:%S") if ko_commit_date else "없음", |
|
"status": status, |
|
"outdate": outdate |
|
}) |
|
|
|
|
|
results.sort(key=lambda x: x["file_name"]) |
|
return results |
|
|
|
def create_ui(): |
|
"""Gradio UI 생성""" |
|
tracker = TranslationTracker() |
|
|
|
with gr.Blocks(title="Transformers 문서 번역 추적기") as app: |
|
gr.Markdown("# Transformers 문서 번역 추적기") |
|
gr.Markdown("HuggingFace Transformers 레포지토리의 문서 번역 상태를 확인합니다.") |
|
|
|
with gr.Row(): |
|
clone_btn = gr.Button("레포지토리 클론", variant="primary") |
|
status_btn = gr.Button("번역 상태 확인", variant="secondary") |
|
cleanup_btn = gr.Button("정리", variant="stop") |
|
|
|
status_output = gr.Textbox(label="상태") |
|
|
|
with gr.Tabs(): |
|
with gr.TabItem("모든 문서"): |
|
all_table = gr.DataFrame( |
|
headers=["파일명", "영어 경로", "한글 경로", "영어 마지막 커밋", "한글 마지막 커밋", "상태"], |
|
datatype=["str", "str", "str", "str", "str", "str"], |
|
label="번역 상태" |
|
) |
|
|
|
with gr.TabItem("번역 필요"): |
|
untranslated_table = gr.DataFrame( |
|
headers=["파일명", "영어 경로", "상태"], |
|
datatype=["str", "str", "str"], |
|
label="번역이 필요한 문서" |
|
) |
|
|
|
with gr.TabItem("업데이트 필요"): |
|
outdated_table = gr.DataFrame( |
|
headers=["파일명", "영어 경로", "영어 마지막 커밋", "한글 마지막 커밋"], |
|
datatype=["str", "str", "str", "str"], |
|
label="업데이트가 필요한 문서" |
|
) |
|
|
|
|
|
clone_btn.click(tracker.clone_repo, outputs=status_output) |
|
|
|
def process_translation_status(): |
|
results = tracker.get_translation_status() |
|
if results and "error" in results[0]: |
|
return status_output.update(results[0]["error"]), None, None, None |
|
|
|
|
|
all_data = [[r["file_name"], r["en_path"], r["ko_path"], r["en_last_commit"], r["ko_last_commit"], r["status"]] for r in results] |
|
|
|
|
|
untranslated = [[r["file_name"], r["en_path"], r["status"]] for r in results if r["status"] == "미번역"] |
|
|
|
|
|
outdated = [[r["file_name"], r["en_path"], r["en_last_commit"], r["ko_last_commit"]] for r in results if r["outdate"]] |
|
|
|
return "번역 상태 조회 완료", all_data, untranslated, outdated |
|
|
|
status_btn.click( |
|
process_translation_status, |
|
outputs=[status_output, all_table, untranslated_table, outdated_table] |
|
) |
|
|
|
cleanup_btn.click( |
|
lambda: (tracker.cleanup(), "정리 완료"), |
|
outputs=status_output |
|
) |
|
|
|
return app |
|
|
|
def main(): |
|
app = create_ui() |
|
app.launch() |
|
|
|
if __name__ == "__main__": |
|
main() |