import streamlit as st import re from typing import List, Tuple, Dict from subjectless_predicates_122725_v2 import DOUBT_PREDICATES, SUPPORT_PREDICATES, analyze_objectivity from korean_sentence_splitter import KoreanSentenceSplitter def highlight_objectivity(text: str) -> str: if not text: return "" splitter = KoreanSentenceSplitter() sentences = splitter.split(text) highlighted_sentences = [] for sent in sentences: matches = [] # Find doubt matches for cat, pattern in DOUBT_PREDICATES.items(): for match in pattern.finditer(sent): matches.append((match.start(), match.end(), "doubt", cat)) # Find support matches for cat, pattern in SUPPORT_PREDICATES.items(): for match in pattern.finditer(sent): matches.append((match.start(), match.end(), "support", cat)) # Sort matches by start position, then by length (descending) to handle potential overlaps matches.sort(key=lambda x: (x[0], -(x[1] - x[0]))) # Filter overlapping matches (keep the longest or first) filtered_matches = [] if matches: last_end = -1 for start, end, mtype, cat in matches: if start >= last_end: filtered_matches.append((start, end, mtype, cat)) last_end = end # Build highlighted sentence last_idx = 0 h_sent = "" for start, end, mtype, cat in filtered_matches: # Add text before match h_sent += sent[last_idx:start] # Add highlighted match match_text = sent[start:end] if mtype == "doubt": color = "#ffcccc" # Light red border = "#ff0000" h_sent += f'{match_text}' else: color = "#ccffcc" # Light green border = "#00aa00" h_sent += f'{match_text}' last_idx = end h_sent += sent[last_idx:] highlighted_sentences.append(h_sent) return " ".join(highlighted_sentences) def clear_input(): st.session_state.main_text_input = "" def main(): st.set_page_config(page_title="뉴스 객관성 술어 분석기", layout="wide") st.title("📰 뉴스 객관성 분석기: 술어 성격 탐지 및 추출") st.markdown(""" 뉴스 객관성 평가를 위해 술어의 성격을 탐지하고 추출하는 기능을 수행합니다. - 빨간색 표시: **객관성 의심 (Objectivity Doubt)** - 발언의 주체가 불분명하여 기자의 주관이 개입되었을 가능성이 높은 표현 - 녹색 표시: **객관성 지지 (Objectivity Support)** - 사실 확인이나 구체적인 출처/데이터를 바탕으로 한 객관적 표현 """, unsafe_allow_html=True) # 세션 상태 초기화 if 'main_text_input' not in st.session_state: st.session_state.main_text_input = """오늘 주가가 크게 오를 것으로 전망된다. 투자자들 사이에서는 이번 상승세가 당분간 이어질 것이라는 분석이 지배적이다. 반면 일각에서는 거품이라는 지적도 나온다. 실제로 통계청 집계에 따르면 지난달 수출은 역대 최고치를 기록했다. 정부 관계자는 경제 지표가 개선되고 있음이 확인됐다고 밝혔다.""" col1, col2 = st.columns([1, 1]) with col1: st.subheader("입력 텍스트") # key를 통해 세션 상태와 직접 연결 input_text = st.text_area("분석할 기사 내용을 입력하세요.", height=400, placeholder="여기에 기사 내용을 붙여넣으세요...", key="main_text_input") btn_col1, btn_col2, _ = st.columns([1, 1, 3]) analyze_clicked = btn_col1.button("분석", type="primary") # 초기화 버튼에 콜백 함수 적용 btn_col2.button("초기화", on_click=clear_input) # 분석 버튼 클릭 시 결과 표시 if analyze_clicked and input_text: with col2: st.subheader("분석 결과") with st.spinner("분석 중..."): highlighted_html = highlight_objectivity(input_text) st.markdown(f'