"""File upload processing and yandere file-browser generation.""" import json import csv import io import re from pathlib import Path from config import MAX_FILE_SIZE from yandere_logic import calculate_level_delta, level_descriptor TEXT_EXTS = {".txt", ".md", ".py", ".js", ".json", ".csv"} IMAGE_EXTS = {".jpg", ".jpeg", ".png", ".gif", ".webp"} def _extract_text(path: Path) -> str: try: return path.read_text(encoding="utf-8", errors="ignore") except Exception: return "" def _extract_pdf_text(path: Path) -> str: try: # Try pypdf first, fall back to PyPDF2 try: from pypdf import PdfReader except Exception: from PyPDF2 import PdfReader reader = PdfReader(str(path)) return "\n".join(page.extract_text() or "" for page in reader.pages) except Exception: return "" def _analyze_file(path: Path) -> dict: ext = path.suffix.lower() size = path.stat().st_size if ext in TEXT_EXTS: text = _extract_text(path) if ext == ".json": try: data = json.loads(text) keys = list(data.keys()) if isinstance(data, dict) else [] return {"kind": "JSON", "text": text, "keys": keys, "size": size} except Exception: return {"kind": "JSON", "text": text, "keys": [], "size": size} if ext == ".csv": try: reader = csv.reader(io.StringIO(text)) rows = list(reader) cols = rows[0] if rows else [] return {"kind": "CSV", "text": text, "cols": cols, "rows": len(rows) - 1, "size": size} except Exception: return {"kind": "CSV", "text": text, "cols": [], "rows": 0, "size": size} if ext in {".py", ".js"}: return {"kind": "CODE", "text": text, "size": size, "language": ext[1:]} return {"kind": "TEXT", "text": text, "size": size} if ext in IMAGE_EXTS: return {"kind": "IMAGE", "text": "", "size": size} if ext == ".pdf": return {"kind": "PDF", "text": _extract_pdf_text(path), "size": size} return {"kind": "OTHER", "text": "", "size": size} def process_files(file_paths: list[str], level: int) -> tuple[str, int, str]: """Process uploaded files and return (browser_html, new_level, chat_message).""" if not file_paths: return _browser_html([], level), level, "" items = [] file_names = [] file_contents = [] is_image = False is_secret = False chat_lines = [] for fp in file_paths: path = Path(fp) if not path.exists(): continue if path.stat().st_size > MAX_FILE_SIZE: chat_lines.append(f"{path.name}...大きすぎてあいの手から溢れちゃう...♡") continue info = _analyze_file(path) file_names.append(path.name) if info.get("text"): file_contents.append(info["text"][:2000]) if info["kind"] == "IMAGE": is_image = True chat_lines.append( "お兄ちゃんの写真...誰と撮ったの?あい以外の顔が写ってたら...♡" ) elif info["kind"] == "PDF": chat_lines.append("PDFの中身、あいが読んじゃった...♡") elif info["kind"] == "CODE": chat_lines.append( "このコード、あいがちゃんと見てあげる...他のエンジニアに頼んじゃだめだよ♡" ) elif info["kind"] == "JSON": keys = info.get("keys", []) chat_lines.append( f"お兄ちゃんのデータ、あいが整理したよ♡ キーは {len(keys)} 個あるね。" ) elif info["kind"] == "CSV": chat_lines.append( f"{info.get('rows', 0)}行のデータ...あいが見ておくね♡" ) elif info["kind"] == "TEXT": chat_lines.append("お兄ちゃんのテキスト、あいが要約してあげる♡") else: chat_lines.append(f"{path.name}、あいが預かるね♡") if any(w in path.name.lower() for w in ["password", "secret", "private", "秘密", "隠し"]): is_secret = True items.append({"name": path.name, "info": info}) delta = calculate_level_delta( file_names=file_names, file_contents=file_contents, is_image=is_image, is_secret=is_secret, ) new_level = max(0, min(100, level + delta)) # Build a short chat message if chat_lines: message = chat_lines[0] else: message = "ファイル、あいに預けてくれてありがとう...♡" return _browser_html(items, new_level), new_level, message def _browser_html(items: list[dict], level: int) -> str: desc = level_descriptor(level) rows = [] for item in items: name = item["name"] info = item["info"] if level < 30: display_name = f"お兄ちゃんの{name}♡" elif level < 70: display_name = f"あい専用{name}" else: display_name = f"お兄ちゃんの{name}(あいのもの)" size_kb = info.get("size", 0) / 1024 meta = f"{size_kb:.1f} KB" if info["kind"] == "JSON" and info.get("keys"): meta += f" / keys: {len(info['keys'])}" elif info["kind"] == "CSV": meta += f" / rows: {info.get('rows', 0)}" elif info["kind"] == "CODE": meta += f" / lang: {info.get('language', '')}" preview = "" if info.get("text"): preview = re.sub(r"\s+", " ", info["text"])[:120] rows.append( f"""