Spaces:
Sleeping
Sleeping
| import os | |
| import json | |
| import time | |
| from datetime import datetime | |
| # 디렉터리 경로 설정 | |
| PERSONAS_DIR = "data/user_personas" | |
| CONVERSATIONS_DIR = "data/conversation_logs" | |
| def ensure_directories(): | |
| """필요한 디렉터리가 존재하는지 확인하고, 없으면 생성합니다.""" | |
| for dir_path in [PERSONAS_DIR, CONVERSATIONS_DIR]: | |
| try: | |
| os.makedirs(dir_path, exist_ok=True) | |
| except Exception as e: | |
| print(f"디렉토리 생성 중 오류: {str(e)}") | |
| # 허깅페이스 환경에서는 임시 디렉토리 사용 | |
| temp_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "temp_data") | |
| os.makedirs(temp_dir, exist_ok=True) | |
| return False | |
| return True | |
| def save_persona(persona_data): | |
| """ | |
| 페르소나 데이터를 JSON 파일로 저장합니다. | |
| Args: | |
| persona_data: 저장할 페르소나 데이터 | |
| Returns: | |
| 저장된 파일 경로 | |
| """ | |
| if not ensure_directories(): | |
| print("경고: 디렉토리 생성에 실패했습니다. 세션 데이터만 유지됩니다.") | |
| persona_data["_temp_storage_warning"] = "임시 스토리지만 사용 가능합니다. 페르소나는 세션이 종료되면 사라집니다." | |
| return "temp_persona" | |
| # 파일명 생성 (이름_타임스탬프.json) | |
| name = persona_data.get("기본정보", {}).get("이름", "unnamed").replace(" ", "_") | |
| timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") | |
| filename = f"{name}_{timestamp}.json" | |
| file_path = os.path.join(PERSONAS_DIR, filename) | |
| try: | |
| # JSON 파일로 저장 | |
| with open(file_path, "w", encoding="utf-8") as f: | |
| json.dump(persona_data, f, ensure_ascii=False, indent=2) | |
| return file_path | |
| except Exception as e: | |
| print(f"페르소나 저장 오류: {str(e)}") | |
| persona_data["_storage_error"] = str(e) | |
| return "failed_to_save" | |
| def load_persona(file_path): | |
| """ | |
| JSON 파일에서 페르소나 데이터를 로드합니다. | |
| Args: | |
| file_path: 페르소나 파일 경로 | |
| Returns: | |
| 로드된 페르소나 데이터 | |
| """ | |
| # 임시 저장 케이스 처리 | |
| if file_path == "temp_persona" or file_path == "failed_to_save": | |
| return None | |
| try: | |
| with open(file_path, "r", encoding="utf-8") as f: | |
| data = json.load(f) | |
| return data | |
| except Exception as e: | |
| print(f"페르소나 로딩 오류: {str(e)}") | |
| return None | |
| def list_personas(): | |
| """ | |
| 저장된 모든 페르소나 목록을 가져옵니다. | |
| Returns: | |
| 페르소나 목록 (테이블 형식) | |
| """ | |
| ensure_directories() | |
| personas = [] | |
| # 디렉터리 내 모든 JSON 파일 확인 | |
| for filename in os.listdir(PERSONAS_DIR): | |
| if filename.endswith(".json"): | |
| file_path = os.path.join(PERSONAS_DIR, filename) | |
| try: | |
| with open(file_path, "r", encoding="utf-8") as f: | |
| data = json.load(f) | |
| # 필요한 정보 추출 | |
| name = data.get("기본정보", {}).get("이름", "무명") | |
| object_type = data.get("기본정보", {}).get("유형", "") | |
| created = data.get("기본정보", {}).get("생성일시", "") | |
| personas.append([name, object_type, created, filename]) | |
| except Exception as e: | |
| print(f"파일 읽기 오류 ({filename}): {str(e)}") | |
| # 최신 순으로 정렬 | |
| personas.sort(key=lambda x: x[2], reverse=True) | |
| return personas | |
| def save_conversation(conversation_data): | |
| """ | |
| 대화 데이터를 JSON 파일로 저장합니다. | |
| Args: | |
| conversation_data: 저장할 대화 데이터 | |
| Returns: | |
| 저장된 파일 경로 | |
| """ | |
| if not ensure_directories(): | |
| print("경고: 디렉토리 생성에 실패했습니다. 대화 데이터를 저장할 수 없습니다.") | |
| return "temp_conversation" | |
| # 페르소나 정보 추출 | |
| persona = conversation_data.get("persona", {}) | |
| name = persona.get("기본정보", {}).get("이름", "unnamed").replace(" ", "_") | |
| # 페르소나별 대화 저장 디렉터리 | |
| persona_conv_dir = os.path.join(CONVERSATIONS_DIR, name) | |
| try: | |
| os.makedirs(persona_conv_dir, exist_ok=True) | |
| except Exception as e: | |
| print(f"대화 저장 디렉토리 생성 오류: {str(e)}") | |
| return "failed_to_save_conv" | |
| # 파일명 생성 (타임스탬프.json) | |
| timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") | |
| filename = f"conversation_{timestamp}.json" | |
| file_path = os.path.join(persona_conv_dir, filename) | |
| try: | |
| # JSON 파일로 저장 | |
| with open(file_path, "w", encoding="utf-8") as f: | |
| # 메시지 내용만 저장하여 파일 크기 최적화 | |
| simplified_data = { | |
| "persona_name": name, | |
| "persona_type": persona.get("기본정보", {}).get("유형", ""), | |
| "start_time": conversation_data.get("start_time", ""), | |
| "current_time": conversation_data.get("current_time", ""), | |
| "duration_seconds": conversation_data.get("duration_seconds", 0), | |
| "messages": [{ | |
| "role": msg["role"], | |
| "content": msg["content"], | |
| "timestamp": msg.get("timestamp", "") | |
| } for msg in conversation_data.get("messages", [])] | |
| } | |
| json.dump(simplified_data, f, ensure_ascii=False, indent=2) | |
| return file_path | |
| except Exception as e: | |
| print(f"대화 저장 오류: {str(e)}") | |
| return "failed_to_save_conv" | |
| def list_conversations(persona_name=None): | |
| """ | |
| 저장된 대화 목록을 가져옵니다. | |
| Args: | |
| persona_name: 특정 페르소나의 대화만 필터링 (선택 사항) | |
| Returns: | |
| 대화 목록 (테이블 형식) | |
| """ | |
| ensure_directories() | |
| conversations = [] | |
| # 모든 페르소나 디렉터리 탐색 | |
| for persona_dir in os.listdir(CONVERSATIONS_DIR): | |
| # 특정 페르소나만 필터링 | |
| if persona_name and persona_name != persona_dir: | |
| continue | |
| persona_path = os.path.join(CONVERSATIONS_DIR, persona_dir) | |
| if os.path.isdir(persona_path): | |
| # 디렉터리 내 모든 대화 파일 확인 | |
| for filename in os.listdir(persona_path): | |
| if filename.endswith(".json"): | |
| file_path = os.path.join(persona_path, filename) | |
| try: | |
| with open(file_path, "r", encoding="utf-8") as f: | |
| data = json.load(f) | |
| # 필요한 정보 추출 | |
| persona_name = data.get("persona_name", "무명") | |
| start_time = data.get("start_time", "") | |
| duration = data.get("duration_seconds", 0) | |
| msg_count = len(data.get("messages", [])) | |
| conversations.append([ | |
| persona_name, | |
| start_time, | |
| f"{int(duration // 60)}분 {int(duration % 60)}초", | |
| msg_count, | |
| file_path | |
| ]) | |
| except Exception as e: | |
| print(f"대화 파일 읽기 오류 ({file_path}): {str(e)}") | |
| # 최신 순으로 정렬 | |
| conversations.sort(key=lambda x: x[1], reverse=True) | |
| return conversations | |
| def load_conversation(file_path): | |
| """ | |
| JSON 파일에서 대화 데이터를 로드합니다. | |
| Args: | |
| file_path: 대화 파일 경로 | |
| Returns: | |
| 로드된 대화 데이터 | |
| """ | |
| try: | |
| with open(file_path, "r", encoding="utf-8") as f: | |
| data = json.load(f) | |
| return data | |
| except Exception as e: | |
| print(f"대화 로딩 오류: {str(e)}") | |
| return None | |
| def analyze_persona_trait_distribution(): | |
| """ | |
| 저장된 모든 페르소나의 성격 특성 분포를 분석합니다. | |
| Returns: | |
| 특성별 평균값, 최소값, 최대값, 중앙값을 포함한 분석 결과 | |
| """ | |
| ensure_directories() | |
| traits_data = { | |
| "온기": [], | |
| "능력": [], | |
| "신뢰성": [], | |
| "친화성": [], | |
| "창의성": [], | |
| "유머감각": [] | |
| } | |
| # 모든 페르소나 파일에서 성격 특성 수집 | |
| for filename in os.listdir(PERSONAS_DIR): | |
| if filename.endswith(".json"): | |
| file_path = os.path.join(PERSONAS_DIR, filename) | |
| try: | |
| with open(file_path, "r", encoding="utf-8") as f: | |
| data = json.load(f) | |
| # 성격 특성 값 추출 | |
| for trait, values in traits_data.items(): | |
| trait_value = data.get("성격특성", {}).get(trait) | |
| if trait_value is not None: | |
| values.append(trait_value) | |
| except Exception as e: | |
| print(f"파일 분석 오류 ({filename}): {str(e)}") | |
| # 분석 결과 계산 | |
| analysis = {} | |
| for trait, values in traits_data.items(): | |
| if values: | |
| analysis[trait] = { | |
| "평균": sum(values) / len(values), | |
| "최소": min(values), | |
| "최대": max(values), | |
| "중앙값": sorted(values)[len(values) // 2], | |
| "페르소나 수": len(values) | |
| } | |
| else: | |
| analysis[trait] = { | |
| "평균": 0, | |
| "최소": 0, | |
| "최대": 0, | |
| "중앙값": 0, | |
| "페르소나 수": 0 | |
| } | |
| return analysis | |
| def get_conversation_statistics(persona_name=None): | |
| """ | |
| 대화 데이터의 통계 정보를 분석합니다. | |
| Args: | |
| persona_name: 특정 페르소나의 대화만 필터링 (선택 사항) | |
| Returns: | |
| 대화 통계 정보 | |
| """ | |
| ensure_directories() | |
| stats = { | |
| "총_대화_수": 0, | |
| "총_메시지_수": 0, | |
| "평균_대화_시간": 0, | |
| "평균_메시지_수": 0, | |
| "페르소나별_대화": {} | |
| } | |
| total_duration = 0 | |
| # 모든 페르소나 디렉터리 탐색 | |
| for persona_dir in os.listdir(CONVERSATIONS_DIR): | |
| # 특정 페르소나만 필터링 | |
| if persona_name and persona_name != persona_dir: | |
| continue | |
| persona_path = os.path.join(CONVERSATIONS_DIR, persona_dir) | |
| if os.path.isdir(persona_path): | |
| persona_stats = { | |
| "대화_수": 0, | |
| "메시지_수": 0, | |
| "총_대화_시간": 0 | |
| } | |
| # 디렉터리 내 모든 대화 파일 확인 | |
| for filename in os.listdir(persona_path): | |
| if filename.endswith(".json"): | |
| file_path = os.path.join(persona_path, filename) | |
| try: | |
| with open(file_path, "r", encoding="utf-8") as f: | |
| data = json.load(f) | |
| # 통계 누적 | |
| msg_count = len(data.get("messages", [])) | |
| duration = data.get("duration_seconds", 0) | |
| stats["총_대화_수"] += 1 | |
| stats["총_메시지_수"] += msg_count | |
| total_duration += duration | |
| persona_stats["대화_수"] += 1 | |
| persona_stats["메시지_수"] += msg_count | |
| persona_stats["총_대화_시간"] += duration | |
| except Exception as e: | |
| print(f"대화 파일 분석 오류 ({file_path}): {str(e)}") | |
| # 페르소나별 평균 계산 | |
| if persona_stats["대화_수"] > 0: | |
| persona_stats["평균_메시지_수"] = persona_stats["메시지_수"] / persona_stats["대화_수"] | |
| persona_stats["평균_대화_시간"] = persona_stats["총_대화_시간"] / persona_stats["대화_수"] | |
| stats["페르소나별_대화"][persona_dir] = persona_stats | |
| # 전체 평균 계산 | |
| if stats["총_대화_수"] > 0: | |
| stats["평균_대화_시간"] = total_duration / stats["총_대화_수"] | |
| stats["평균_메시지_수"] = stats["총_메시지_수"] / stats["총_대화_수"] | |
| return stats |