Spaces:
Paused
Paused
| # rag_system.py - RAG ์์คํ ๋ชจ๋ | |
| import os | |
| import json | |
| import torch | |
| import pickle | |
| import numpy as np | |
| # FAISS GPU/CPU ์๋ ์ ํ | |
| try: | |
| # GPU๊ฐ ์๊ณ CUDA๊ฐ ์ฌ์ฉ ๊ฐ๋ฅํ๋ฉด faiss-gpu ์๋ | |
| if torch.cuda.is_available(): | |
| try: | |
| import subprocess | |
| subprocess.run(['pip', 'install', 'faiss-gpu'], check=True, capture_output=True) | |
| import faiss | |
| print("โ faiss-gpu ์ค์น ๋ฐ ๋ก๋ ์ฑ๊ณต") | |
| except: | |
| import faiss | |
| print("โ ๏ธ faiss-gpu ์ค์น ์คํจ, faiss-cpu ์ฌ์ฉ") | |
| else: | |
| import faiss | |
| print("๐ป CPU ํ๊ฒฝ: faiss-cpu ์ฌ์ฉ") | |
| except ImportError: | |
| print("โ FAISS ์ค์น ํ์: pip install faiss-cpu") | |
| import sys | |
| sys.exit(1) | |
| from sentence_transformers import SentenceTransformer | |
| from sklearn.feature_extraction.text import TfidfVectorizer | |
| from sklearn.metrics.pairwise import cosine_similarity | |
| from law_fetcher import HFLawAPIFetcher | |
| from config import RAG_CONFIG, TAX_KEYWORDS, RELEVANCE_KEYWORDS | |
| class HFSpacesTaxRAG: | |
| """HF Spaces ์ต์ ํ ์ทจ๋์ธ RAG ์์คํ """ | |
| def __init__(self, custom_config=None): | |
| print("๐ HF Spaces ์ทจ๋์ธ RAG ์์คํ ์ด๊ธฐํ ์ค...") | |
| # ์ค์ ๋ก๋ (์ปค์คํ ์ค์ ์ง์) | |
| if custom_config: | |
| self.config = custom_config | |
| print("๐ง ์ปค์คํ ์ค์ ์ ์ฉ") | |
| else: | |
| self.config = RAG_CONFIG | |
| self.tax_keywords = TAX_KEYWORDS | |
| # ๋๋ฐ์ด์ค ์ค์ (ํ๊น ํ์ด์ค ์คํ์ด์ค ํ๊ฒฝ ๊ณ ๋ ค) | |
| if torch.cuda.is_available(): | |
| self.device = 'cuda' | |
| else: | |
| self.device = 'cpu' | |
| # ํ๊น ํ์ด์ค ์คํ์ด์ค ํ๊ฒฝ ๊ฐ์ง | |
| self.is_huggingface_space = os.getenv('SPACE_ID') is not None | |
| if self.is_huggingface_space: | |
| print(f"๐ ํ๊น ํ์ด์ค ์คํ์ด์ค ํ๊ฒฝ ๊ฐ์ง - ๋๋ฐ์ด์ค: {self.device}") | |
| else: | |
| print(f"๐ป ๋ก์ปฌ ๊ฐ๋ฐ ํ๊ฒฝ - ๋๋ฐ์ด์ค: {self.device}") | |
| # ์ปดํฌ๋ํธ ์ด๊ธฐํ | |
| self.load_embedding_model() | |
| self.setup_vectorizers() | |
| self.setup_law_fetcher() | |
| # ๋ฐ์ดํฐ ์ด๊ธฐํ | |
| self.initialize_system() | |
| print("โ RAG ์์คํ ์ด๊ธฐํ ์๋ฃ") | |
| def load_embedding_model(self): | |
| """์๋ฒ ๋ฉ ๋ชจ๋ธ ๋ก๋ (ํ๊ฒฝ๋ณ ์ต์ ํ)""" | |
| print("์๋ฒ ๋ฉ ๋ชจ๋ธ ๋ก๋ฉ ์ค...") | |
| # ํ๊ฒฝ์ ๋ฐ๋ฅธ ๋ชจ๋ธ ์ ํ ์ ๋ต | |
| if self.is_huggingface_space and self.device == 'cuda': | |
| # ํ๊น ํ์ด์ค GPU ํ๊ฒฝ: ์ฑ๋ฅ ์ฐ์ | |
| model_priority = self.config['embedding_models'] | |
| else: | |
| # ๋ก์ปฌ CPU ํ๊ฒฝ: ๊ฐ๋ฒผ์ด ๋ชจ๋ธ ์ฐ์ | |
| model_priority = [ | |
| 'paraphrase-multilingual-MiniLM-L12-v2', # ๊ฐ์ฅ ๊ฐ๋ฒผ์ด ๋ชจ๋ธ | |
| 'sentence-transformers/paraphrase-multilingual-mpnet-base-v2', | |
| 'jhgan/ko-sroberta-multitask' | |
| ] | |
| for model_name in model_priority: | |
| try: | |
| print(f"์๋ ์ค: {model_name}") | |
| # ๋ก์ปฌ CPU ํ๊ฒฝ์์๋ ๋ ๋ณด์์ ์ธ ์ค์ | |
| if not self.is_huggingface_space and self.device == 'cpu': | |
| self.embedding_model = SentenceTransformer( | |
| model_name, | |
| device=self.device, | |
| cache_folder='./model_cache' # ๋ก์ปฌ ์บ์ ์ฌ์ฉ | |
| ) | |
| else: | |
| self.embedding_model = SentenceTransformer( | |
| model_name, | |
| device=self.device | |
| ) | |
| print(f"์๋ฒ ๋ฉ ๋ชจ๋ธ ๋ก๋ ์๋ฃ: {model_name}") | |
| return | |
| except Exception as e: | |
| print(f"{model_name} ๋ก๋ ์คํจ: {e}") | |
| continue | |
| raise Exception("๋ชจ๋ ์๋ฒ ๋ฉ ๋ชจ๋ธ ๋ก๋ ์คํจ") | |
| def setup_vectorizers(self): | |
| """๋ฒกํฐ๋ผ์ด์ ์ค์ """ | |
| self.tfidf_vectorizer = TfidfVectorizer( | |
| max_features=1000, | |
| ngram_range=(1, 3), | |
| stop_words=None | |
| ) | |
| # ์ด๊ธฐํ | |
| self.vector_db = None | |
| self.tfidf_matrix = None | |
| self.documents = [] | |
| self.metadata = [] | |
| def setup_law_fetcher(self): | |
| """๋ฒ๋ น ํ์ฒ ์ค์ """ | |
| self.law_fetcher = HFLawAPIFetcher() | |
| def initialize_system(self): | |
| """์์คํ ์ด๊ธฐํ - ๋ฐ์ดํฐ ๋ก๋ ๋๋ ๊ตฌ์ถ""" | |
| if self.load_prebuilt_data(): | |
| print("โ ๊ธฐ์กด ๋ฒกํฐ DB ๋ฐ์ดํฐ ๋ก๋ ์๋ฃ") | |
| else: | |
| print("๐ ์๋ก์ด RAG ์์คํ ๊ตฌ์ถ ์์...") | |
| self.build_system() | |
| def load_prebuilt_data(self): | |
| """๋ฏธ๋ฆฌ ๊ตฌ์ถ๋ ๋ฒกํฐ DB ๋ฐ์ดํฐ ๋ก๋""" | |
| try: | |
| # ๋ฒกํฐ DB ๋ก๋ | |
| if os.path.exists('vector_db.faiss'): | |
| self.vector_db = faiss.read_index('vector_db.faiss') | |
| print(f"โ ๋ฒกํฐ DB ๋ก๋: {self.vector_db.ntotal}๊ฐ ๋ฒกํฐ") | |
| else: | |
| return False | |
| # ๋ฌธ์ ๋ก๋ | |
| if os.path.exists('documents.pkl'): | |
| with open('documents.pkl', 'rb') as f: | |
| self.documents = pickle.load(f) | |
| print(f"โ ๋ฌธ์ ๋ก๋: {len(self.documents)}๊ฐ") | |
| else: | |
| return False | |
| # ๋ฉํ๋ฐ์ดํฐ ๋ก๋ | |
| if os.path.exists('metadata.json'): | |
| with open('metadata.json', 'r', encoding='utf-8') as f: | |
| self.metadata = json.load(f) | |
| print(f"โ ๋ฉํ๋ฐ์ดํฐ ๋ก๋: {len(self.metadata)}๊ฐ") | |
| else: | |
| return False | |
| # TF-IDF ํ๋ ฌ ๊ตฌ์ถ | |
| if self.documents: | |
| self.tfidf_matrix = self.tfidf_vectorizer.fit_transform(self.documents) | |
| print("โ TF-IDF ํ๋ ฌ ๊ตฌ์ถ ์๋ฃ") | |
| return True | |
| except Exception as e: | |
| print(f"โ ๋ฒกํฐ DB ๋ฐ์ดํฐ ๋ก๋ ์คํจ: {e}") | |
| return False | |
| def build_system(self): | |
| """์ ์ฒด ์์คํ ๊ตฌ์ถ (์บ์ ํ์ฉ)""" | |
| print("๐ ๏ธ RAG ์์คํ ๊ตฌ์ถ ์์...") | |
| # 1. ๋ฒ๋ น ๋ฐ์ดํฐ ์์ง (์บ์ ํ์ฉ) | |
| raw_law_data = self.law_fetcher.fetch_laws() | |
| if not raw_law_data: | |
| print("โ ๋ฒ๋ น ๋ฐ์ดํฐ ์์ง ์คํจ") | |
| return False | |
| # 2. ๋ฌธ์ ์ ์ฒ๋ฆฌ | |
| documents = [] | |
| metadata = [] | |
| parsed_law_data = {} | |
| for law_name, raw_data in raw_law_data.items(): | |
| parsed_data = self.law_fetcher._parse_json_response(raw_data) | |
| if parsed_data: | |
| parsed_law_data[law_name] = parsed_data | |
| if not parsed_law_data: | |
| print("โ ๋ฒ๋ น ๋ฐ์ดํฐ ํ์ฑ ์คํจ") | |
| return False | |
| for law_name, law_info in parsed_law_data.items(): | |
| for article_key, article_content in law_info.get('์กฐ๋ฌธ๋ชฉ๋ก', {}).items(): | |
| # ์ทจ๋์ธ ๊ด๋ จ๋ ๊ณ์ฐ | |
| relevance = self._calculate_relevance(article_content) | |
| if relevance > 0.1: | |
| documents.append(article_content) | |
| metadata.append({ | |
| 'law_name': law_name, | |
| 'article_key': article_key, | |
| 'relevance': relevance, | |
| 'length': len(article_content) | |
| }) | |
| if not documents: | |
| print("โ ์ทจ๋์ธ ๊ด๋ จ ๋ฌธ์๊ฐ ์์ต๋๋ค") | |
| return False | |
| print(f"๐ ์ ์ฒ๋ฆฌ ์๋ฃ: {len(documents)}๊ฐ ๋ฌธ์") | |
| # 3. ์๋ฒ ๋ฉ ์์ฑ | |
| try: | |
| embeddings = self.embedding_model.encode( | |
| documents, | |
| show_progress_bar=True, | |
| convert_to_numpy=True, | |
| batch_size=self.config['batch_size'] | |
| ) | |
| print(f"โ ์๋ฒ ๋ฉ ์์ฑ ์๋ฃ: {embeddings.shape}") | |
| except Exception as e: | |
| print(f"โ ์๋ฒ ๋ฉ ์์ฑ ์คํจ: {e}") | |
| return False | |
| # 4. ๋ฒกํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ตฌ์ถ | |
| try: | |
| dimension = embeddings.shape[1] | |
| self.vector_db = faiss.IndexFlatIP(dimension) | |
| faiss.normalize_L2(embeddings) | |
| self.vector_db.add(embeddings.astype('float32')) | |
| self.documents = documents | |
| self.metadata = metadata | |
| print(f"โ ๋ฒกํฐ DB ๊ตฌ์ถ ์๋ฃ: {self.vector_db.ntotal}๊ฐ ๋ฒกํฐ") | |
| except Exception as e: | |
| print(f"โ ๋ฒกํฐ DB ๊ตฌ์ถ ์คํจ: {e}") | |
| return False | |
| # 5. TF-IDF ๊ตฌ์ถ | |
| try: | |
| self.tfidf_matrix = self.tfidf_vectorizer.fit_transform(documents) | |
| print("โ TF-IDF ๊ตฌ์ถ ์๋ฃ") | |
| except Exception as e: | |
| print(f"โ TF-IDF ๊ตฌ์ถ ์คํจ: {e}") | |
| # 6. ๊ตฌ์ถ๋ ๋ฐ์ดํฐ ์ ์ฅ | |
| self._save_built_system() | |
| print("๐ RAG ์์คํ ๊ตฌ์ถ ์๋ฃ!") | |
| return True | |
| def _save_built_system(self): | |
| """๊ตฌ์ถ๋ ์์คํ ์ ์ฅ""" | |
| try: | |
| print("๐พ ๊ตฌ์ถ๋ RAG ์์คํ ์ ์ฅ ์ค...") | |
| if self.vector_db: | |
| faiss.write_index(self.vector_db, 'vector_db.faiss') | |
| print("โ ๋ฒกํฐ DB ์ ์ฅ ์๋ฃ") | |
| if self.documents: | |
| with open('documents.pkl', 'wb') as f: | |
| pickle.dump(self.documents, f) | |
| print("โ ๋ฌธ์ ์ ์ฅ ์๋ฃ") | |
| if self.metadata: | |
| with open('metadata.json', 'w', encoding='utf-8') as f: | |
| json.dump(self.metadata, f, ensure_ascii=False, indent=2) | |
| print("โ ๋ฉํ๋ฐ์ดํฐ ์ ์ฅ ์๋ฃ") | |
| except Exception as e: | |
| print(f"โ ์์คํ ์ ์ฅ ์คํจ: {e}") | |
| def _calculate_relevance(self, content): | |
| """์ทจ๋์ธ ๊ด๋ จ๋ ๊ณ์ฐ""" | |
| content_lower = content.lower() | |
| score = 0.0 | |
| total_possible_score = sum(RELEVANCE_KEYWORDS.values()) | |
| for keyword, weight in RELEVANCE_KEYWORDS.items(): | |
| if keyword in content_lower: | |
| frequency = content_lower.count(keyword) | |
| frequency_multiplier = min(1 + (frequency - 1) * 0.15, 2.0) | |
| score += weight * frequency_multiplier | |
| max_realistic_score = total_possible_score * 0.3 | |
| return min(score / max_realistic_score, 1.0) | |
| def search(self, query, top_k=None): | |
| """ํ์ด๋ธ๋ฆฌ๋ ๊ฒ์""" | |
| if top_k is None: | |
| top_k = self.config['top_k'] | |
| if not self.vector_db or not self.documents: | |
| return [] | |
| print(f"๐ ๊ฒ์ ์ฟผ๋ฆฌ: '{query}'") | |
| try: | |
| # ๋ฒกํฐ ๊ฒ์ | |
| query_embedding = self.embedding_model.encode([query], convert_to_numpy=True) | |
| faiss.normalize_L2(query_embedding) | |
| vector_scores, vector_indices = self.vector_db.search( | |
| query_embedding.astype('float32'), | |
| min(top_k * 2, len(self.documents)) | |
| ) | |
| # TF-IDF ๊ฒ์ | |
| tfidf_scores = [] | |
| if self.tfidf_matrix is not None: | |
| query_tfidf = self.tfidf_vectorizer.transform([query]) | |
| tfidf_similarities = cosine_similarity(query_tfidf, self.tfidf_matrix).flatten() | |
| tfidf_scores = tfidf_similarities | |
| # ๊ฒฐ๊ณผ ์กฐํฉ | |
| results = [] | |
| for i, (v_score, v_idx) in enumerate(zip(vector_scores[0], vector_indices[0])): | |
| if v_score > self.config['similarity_threshold']: | |
| tfidf_score = tfidf_scores[v_idx] if len(tfidf_scores) > v_idx else 0.0 | |
| # ํ์ด๋ธ๋ฆฌ๋ ์ ์ | |
| hybrid_score = ( | |
| self.config['hybrid_weights']['vector'] * float(v_score) + | |
| self.config['hybrid_weights']['tfidf'] * float(tfidf_score) | |
| ) | |
| results.append({ | |
| 'content': self.documents[v_idx], # LLM ํ๋ก์ธ์๊ฐ ๊ธฐ๋ํ๋ ํค ์ด๋ฆ | |
| 'document': self.documents[v_idx], # ํธํ์ฑ์ ์ํด ์ ์ง | |
| 'metadata': self.metadata[v_idx], | |
| 'vector_score': float(v_score), | |
| 'tfidf_score': float(tfidf_score), | |
| 'hybrid_score': hybrid_score | |
| }) | |
| # ํ์ด๋ธ๋ฆฌ๋ ์ ์๋ก ์ ๋ ฌ | |
| results.sort(key=lambda x: x['hybrid_score'], reverse=True) | |
| print(f"๐ ๊ฒ์ ๊ฒฐ๊ณผ: {len(results[:top_k])}๊ฐ ๋ฌธ์ ๋ฐ๊ฒฌ") | |
| return results[:top_k] | |
| except Exception as e: | |
| print(f"โ ๊ฒ์ ์ค๋ฅ: {e}") | |
| return [] | |
| def generate_answer(self, query, search_results): | |
| """๊ฒ์ ๊ฒฐ๊ณผ ๊ธฐ๋ฐ ๋ต๋ณ ์์ฑ""" | |
| if not search_results: | |
| return "๊ด๋ จ๋ ๋ฒ๋ น ์กฐ๋ฌธ์ ์ฐพ์ ์ ์์ต๋๋ค." | |
| answer_parts = [f"**๐ฌ '{query}'์ ๋ํ ๋ต๋ณ์ ๋๋ค.**\n"] | |
| answer_parts.append("๐ **๊ด๋ จ ๋ฒ๋ น:**\n") | |
| for i, result in enumerate(search_results, 1): | |
| metadata = result['metadata'] | |
| hybrid_score = result['hybrid_score'] | |
| answer_parts.append( | |
| f"**{i}. {metadata['law_name']} {metadata['article_key']}** " | |
| f"(๊ด๋ จ๋: {hybrid_score:.3f})\n" | |
| ) | |
| answer_parts.append(f"```\n{result['document'][:300]}...\n```\n") | |
| # ๊ท์น ๊ธฐ๋ฐ ์ถ๊ฐ ์ ๋ณด | |
| self._add_rule_based_info(query, answer_parts) | |
| return '\n'.join(answer_parts) | |
| def _add_rule_based_info(self, query, answer_parts): | |
| """๊ท์น ๊ธฐ๋ฐ ์ถ๊ฐ ์ ๋ณด""" | |
| if any(keyword in query for keyword in ['์ธ์จ', '์ธ์ก', '์ผ๋ง']): | |
| answer_parts.append("\n๐ก **์ทจ๋์ธ ์ธ์จ ์ ๋ณด:**") | |
| answer_parts.append("- **์ฃผํ**: 1~3% (๋ณด์ ์ฃผํ ์์ ๋ฐ๋ผ)") | |
| answer_parts.append("- **์ผ๋ฐ ๋ถ๋์ฐ**: 4%") | |
| answer_parts.append("- **๋์ง**: 3%\n") | |
| if any(keyword in query for keyword in ['์ ๊ณ ', '๊ธฐํ', '์ธ์ ']): | |
| answer_parts.append("\nโฐ **์ ๊ณ ๊ธฐํ:**") | |
| answer_parts.append("- **์ผ๋ฐ ์ทจ๋**: ์ทจ๋์ผ๋ถํฐ 60์ผ ์ด๋ด") | |
| answer_parts.append("- **์์**: ์ทจ๋์ผ์ด ์ํ๋ ๋ฌ์ ๋ง์ผ๋ถํฐ 6๊ฐ์ ์ด๋ด\n") | |
| if any(keyword in query for keyword in ['๊ฐ๋ฉด', 'ํน๋ก', 'ํํ']): | |
| answer_parts.append("\n๐ **์ฃผ์ ๊ฐ๋ฉด ํํ:**") | |
| answer_parts.append("- **1์ธ๋ 1์ฃผํ**: 6์ต์ ์ดํ 50% ๊ฐ๋ฉด") | |
| answer_parts.append("- **์ ํผ๋ถ๋ถ**: ์ถ๊ฐ ๊ฐ๋ฉด ํํ") | |
| answer_parts.append("- **๋์ง**: ์ง์ ์๋์ ๊ฐ๋ฉด\n") | |
| def query(self, user_question): | |
| """์ ์ฒด ์ง์์๋ต ์ฒ๋ฆฌ""" | |
| print(f"\nโ ์ง๋ฌธ: {user_question}") | |
| print("="*60) | |
| # 1. ๊ด๋ จ ๋ฌธ์ ๊ฒ์ | |
| search_results = self.search(user_question, top_k=3) | |
| # 2. ๋ต๋ณ ์์ฑ | |
| answer = self.generate_answer(user_question, search_results) | |
| return { | |
| 'question': user_question, | |
| 'answer': answer, | |
| 'sources': search_results, | |
| 'source_count': len(search_results) | |
| } | |
| def get_cache_info(self): | |
| """์บ์ ์ ๋ณด ๋ฐํ""" | |
| return { | |
| 'cache_dir': self.law_fetcher.cache_dir, | |
| 'cache_count': len(self.law_fetcher.cache_info), | |
| 'cache_info': self.law_fetcher.cache_info | |
| } | |
| # ์ฑ๊ธํค ์ธ์คํด์ค (Flask ์ฑ์์ ์ฌ์ฉ) | |
| _rag_instance = None | |
| def get_rag_system(custom_config=None): | |
| """RAG ์์คํ ์ฑ๊ธํค ์ธ์คํด์ค ๋ฐํ""" | |
| global _rag_instance | |
| if _rag_instance is None or custom_config is not None: | |
| _rag_instance = HFSpacesTaxRAG(custom_config) | |
| return _rag_instance | |
| # Flask ์ฑ์์ ์ฌ์ฉํ ์ ์๋ ๊ฐ๋จํ ํจ์๋ค | |
| def search_tax_law(question): | |
| """์ทจ๋์ธ ๋ฒ๋ น ๊ฒ์ + LLM ์ฒ๋ฆฌ (Flask ์ฑ์ฉ)""" | |
| try: | |
| # LLM ์ฒ๋ฆฌ๊ธฐ import | |
| from llm_processor import get_llm_processor, is_llm_available | |
| print(f"๐ ์ฒ๋ฆฌ ์์: {question}") | |
| # 1. RAG ๊ฒ์ | |
| rag = get_rag_system() | |
| rag_result = rag.query(question) | |
| print(f"๐ RAG ๊ฒ์ ์๋ฃ: {rag_result['source_count']}๊ฐ ๋ฌธ์") | |
| # 2. LLM ์ฒ๋ฆฌ ์๋ | |
| if is_llm_available(): | |
| print("๐ค LLM ์ฒ๋ฆฌ ์๋ ์ค...") | |
| llm = get_llm_processor() | |
| # RAG ๊ฒ์ ๊ฒฐ๊ณผ๋ฅผ LLM์ ์ ๋ฌ | |
| search_results = rag_result.get('sources', []) | |
| final_response = llm.process_with_rag(question, search_results) | |
| print("โ LLM ์ฒ๋ฆฌ ์๋ฃ") | |
| return final_response | |
| else: | |
| print("โ ๏ธ LLM ์ฌ์ฉ ๋ถ๊ฐ, RAG ๊ฒฐ๊ณผ๋ง ๋ฐํ") | |
| return rag_result['answer'] | |
| except Exception as e: | |
| print(f"โ ์ฒ๋ฆฌ ์ค๋ฅ: {e}") | |
| import traceback | |
| traceback.print_exc() | |
| return f"์ง๋ฌธ ์ฒ๋ฆฌ ์ค ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค: {e}" | |
| def search_tax_law_rag_only(question): | |
| """RAG๋ง ์ฌ์ฉํ ๊ฒ์ (LLM ์์ด)""" | |
| try: | |
| rag = get_rag_system() | |
| result = rag.query(question) | |
| return result['answer'] | |
| except Exception as e: | |
| print(f"โ RAG ๊ฒ์ ์ค๋ฅ: {e}") | |
| return f"๋ฒ๋ น ๊ฒ์ ์ค ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค: {e}" | |
| def is_rag_available(): | |
| """RAG ์์คํ ์ฌ์ฉ ๊ฐ๋ฅ ์ฌ๋ถ ํ์ธ""" | |
| try: | |
| rag = get_rag_system() | |
| return rag.vector_db is not None and len(rag.documents) > 0 | |
| except Exception: | |
| return False | |
| def get_system_status(): | |
| """์ ์ฒด ์์คํ ์ํ ํ์ธ""" | |
| try: | |
| from llm_processor import is_llm_available | |
| status = { | |
| 'rag_available': is_rag_available(), | |
| 'llm_available': is_llm_available(), | |
| 'pipeline_complete': is_rag_available() and is_llm_available() | |
| } | |
| if status['rag_available']: | |
| rag = get_rag_system() | |
| status['rag_details'] = { | |
| 'documents': len(rag.documents), | |
| 'device': rag.device, | |
| 'is_hf_space': rag.is_huggingface_space | |
| } | |
| return status | |
| except Exception as e: | |
| return {'error': str(e)} |