import openai import streamlit as st import os import datetime import pandas as pd import re from summarize import summarize_text from search import search_markdown_files DOCS_DIR = "docs" # 요약 결과를 저장하는 함수 def save_summary_to_markdown(summary_text): timestamp = datetime.datetime.now().strftime("%Y%m%d-%H%M%S") filename = f"summary_{timestamp}.md" summaries_dir = os.path.join(DOCS_DIR, "summaries") os.makedirs(summaries_dir, exist_ok=True) filepath = os.path.join(summaries_dir, filename) with open(filepath, "w", encoding="utf-8") as f: f.write(summary_text) return os.path.join("summaries", filename) # 페이지 설정 st.set_page_config(page_title="AI 위키 포털", page_icon="🌳") st.title("📚 AI-Tree Lite 포털") # 탭 구성 tab1, tab2, tab3, tab4, tab5 = st.tabs(["🔍 검색", "🧠 요약", "📤 문서 등록", "📈 요약 대시보드", "🧩 태그 클러스터링"]) # 🔍 검색 탭 with tab1: keyword = st.text_input("검색할 키워드를 입력", "") if st.button("검색") and keyword: results = search_markdown_files(DOCS_DIR, keyword) st.subheader("검색 결과:") if results: for result in results: st.markdown(f"📄 **{result['filename']}** (줄 {result['line']})") st.write(f"…{result['text']}…") else: st.info("검색 결과가 없습니다.") # 🧠 요약 탭 with tab2: md_files = [f for f in os.listdir(DOCS_DIR) if f.endswith(".md")] selected_file = st.selectbox("요약할 Markdown 파일 선택", md_files) if st.button("요약하기") and selected_file: with open(os.path.join(DOCS_DIR, selected_file), "r", encoding="utf-8") as f: text = f.read() summary = summarize_text(text) st.subheader("📝 요약 결과") st.text_area("요약 내용", summary, height=200) st.markdown("### 🤔 요약 내용에 대해 AI에게 질문하기") user_question = st.text_input("❓ 궁금한 점을 입력해 보세요:", "") if st.button("📬 질문하기") and user_question: with st.spinner("AI가 답변 중입니다..."): qa_prompt = f"""다음은 요약된 문서 내용이야:\n\n{summary}\n\n사용자의 질문:\n{user_question}\n\n답변:""" try: qa_response = openai.ChatCompletion.create( model="gpt-3.5-turbo", messages=[ {"role": "system", "content": "너는 요약된 내용을 바탕으로 사용자의 질문에 친절하게 답변해주는 AI야."}, {"role": "user", "content": qa_prompt} ] ) answer = qa_response["choices"][0]["message"]["content"] st.markdown(f"💡 **AI의 답변:**\n\n{answer}") except Exception as e: st.error(f"⚠️ 질문 처리 실패: {e}") if st.button("📏 저장하기"): saved_file = save_summary_to_markdown(summary) st.success(f"✅ 저장 완료: `{saved_file}` 에 저장되었습니다.") if st.button("🏷️ 태그 추천받기"): with st.spinner("AI가 태그를 추천 중입니다..."): prompt = f"다음 내용을 바탕으로 태그를 3~5개 추천해줘.\n\n내용:\n{summary}\n\n태그:" try: response = openai.ChatCompletion.create( model="gpt-3.5-turbo", messages=[ {"role": "system", "content": "너는 요약된 내용을 분석해서 적절한 주제 태그를 추천하는 AI야."}, {"role": "user", "content": prompt} ] ) tags = response["choices"][0]["message"]["content"] st.markdown(f"🏷️ **추천 태그:** {tags}") except Exception as e: st.error(f"⚠️ 태그 추천 실패: {e}") # 📤 문서 등록 탭 with tab3: st.markdown("### 📅 Markdown 문서 업로드 또는 직접 작성") uploaded_file = st.file_uploader("📁 파일 업로드", type=["md"]) new_title = st.text_input("✏️ 새 문서 제목 (예: my-note.md)") new_content = st.text_area("📝 문서 내용 직접 입력", height=200) if st.button("📏 저장하기"): if uploaded_file: file_path = os.path.join(DOCS_DIR, uploaded_file.name) if os.path.exists(file_path): st.warning("⚠️ 같은 이름의 파일이 이미 존재합니다. 기존 파일을 덮어씁니다.") with open(file_path, "wb") as f: f.write(uploaded_file.read()) st.success(f"✅ 업로드 완료: `{uploaded_file.name}`") elif new_title and new_content: if not new_title.endswith(".md"): new_title += ".md" file_path = os.path.join(DOCS_DIR, new_title) with open(file_path, "w", encoding="utf-8") as f: f.write(new_content) st.success(f"✅ 작성 완료: `{new_title}` 저장되었습니다.") else: st.error("❌ 업로드할 파일 또는 새 문서 제목/내용을 입력하세요.") # 📈 요약 대시보드 탭 with tab4: st.markdown("### 📊 저장된 요약 문서 대시보드") summaries_dir = os.path.join(DOCS_DIR, "summaries") if not os.path.exists(summaries_dir): st.info("아직 저장된 요약이 없습니다.") else: files = [f for f in os.listdir(summaries_dir) if f.endswith(".md")] data = [] for file in files: filepath = os.path.join(summaries_dir, file) with open(filepath, "r", encoding="utf-8") as f: content = f.read() length = len(content) timestamp_match = re.search(r"summary_(\d{8}-\d{6})", file) timestamp = timestamp_match.group(1) if timestamp_match else "알 수 없음" tag_match = re.search(r"(?i)태그\s*[::]\s*(.+)", content) tags = tag_match.group(1) if tag_match else "없음" data.append({ "📄 파일명": file, "📅 생성시각": timestamp, "🔠 길이(문자수)": length, "🏷️ 태그": tags }) df = pd.DataFrame(data) st.dataframe(df, use_container_width=True) st.markdown(f"총 요약 문서 수: **{len(df)}개**") # 🧩 태그 클러스터링 탭 with tab5: st.markdown("## 🧩 태그 기반 클러스터링") summaries_dir = os.path.join(DOCS_DIR, "summaries") if not os.path.exists(summaries_dir): st.info("📂 아직 저장된 요약 문서가 없습니다.") else: files = [f for f in os.listdir(summaries_dir) if f.endswith(".md")] clusters = {} for file in files: filepath = os.path.join(summaries_dir, file) with open(filepath, "r", encoding="utf-8") as f: content = f.read() match = re.search(r"(?i)태그\s*[::]\s*(.+)", content) tags = [tag.strip() for tag in match.group(1).split(",")] if match else ["기타"] for tag in tags: if tag not in clusters: clusters[tag] = [] clusters[tag].append(file) st.markdown(f"🔍 총 클러스터 수: **{len(clusters)}개**") for tag, file_list in sorted(clusters.items(), key=lambda x: -len(x[1])): with st.expander(f"🏷️ {tag} ({len(file_list)}개 문서)", expanded=False): for fname in file_list: st.markdown(f"• `{fname}`")