Spaces:
Running
Running
| import json | |
| import time | |
| from pathlib import Path | |
| from typing import Dict, Any, Optional | |
| # Prosty storage w pliku JSON (działa w Space tak długo, jak instancja żyje) | |
| STORAGE_PATH = Path(__file__).resolve().parent.parent / "storage" / "habits.json" | |
| STORAGE_PATH.parent.mkdir(parents=True, exist_ok=True) | |
| # Opcjonalne: zaawansowany pipeline z reels-agent (transkrypcja, summary, Nebius) | |
| try: | |
| from . import transcriber, summarizer # type: ignore | |
| except Exception: | |
| transcriber = None | |
| summarizer = None | |
| def _load_db() -> Dict[str, Any]: | |
| if not STORAGE_PATH.exists(): | |
| return {} | |
| try: | |
| with STORAGE_PATH.open("r", encoding="utf-8") as f: | |
| return json.load(f) | |
| except Exception: | |
| return {} | |
| def _save_db(db: Dict[str, Any]) -> None: | |
| with STORAGE_PATH.open("w", encoding="utf-8") as f: | |
| json.dump(db, f, ensure_ascii=False, indent=2) | |
| def _build_initial_step(link: str, category: str) -> str: | |
| """ | |
| Tu próbujemy użyć starego pipeline'u (reels-agent): | |
| - transkrypcja | |
| - summary → konkretna akcja | |
| Jeśli te funkcje nie istnieją / wywalą się → fallback na prosty tekst. | |
| """ | |
| # Fallback – zawsze działa | |
| fallback = "Obejrzyj materiał i zapisz 1 konkretną rzecz, którą dziś wdrożysz." | |
| # Jeśli nie ma modułów – wracamy fallback | |
| if transcriber is None or summarizer is None: | |
| return fallback | |
| try: | |
| # PRZYKŁADOWA KONWENCJA – dopasujesz w razie czego u siebie: | |
| # transcriber.transcribe_link(link) -> str (pełna transkrypcja) | |
| # summarizer.summarize_to_action(text, category) -> str (krótka akcja) | |
| if hasattr(transcriber, "transcribe_link") and hasattr(summarizer, "summarize_to_action"): | |
| text = transcriber.transcribe_link(link) # type: ignore[attr-defined] | |
| action = summarizer.summarize_to_action(text, category) # type: ignore[attr-defined] | |
| if isinstance(action, str) and action.strip(): | |
| return action.strip() | |
| except Exception: | |
| # Nie zabijamy Space’a – po prostu wracamy prostą wersję | |
| return fallback | |
| return fallback | |
| def create_contract(uid: str, link: str, category: str) -> Dict[str, Any]: | |
| """ | |
| Tworzy / nadpisuje kontrakt nawyku: | |
| - uid: ID usera (np. szef_1_career) | |
| - link: IG/YT/TikTok | |
| - category: 'career' / 'health' / 'relationships' / ... | |
| Zwraca dict gotowy do wysłania jako JSON przez MCP. | |
| """ | |
| db = _load_db() | |
| initial_step = _build_initial_step(link, category) | |
| contract = { | |
| "uid": uid, | |
| "link": link, | |
| "category": category, | |
| "created_at": int(time.time()), | |
| "streak": 0, | |
| "last_done_at": None, | |
| "next_step": initial_step, | |
| "history": [], # lista wykonanych kroków | |
| } | |
| db[uid] = contract | |
| _save_db(db) | |
| return contract | |
| def get_contract(uid: str) -> Optional[Dict[str, Any]]: | |
| db = _load_db() | |
| return db.get(uid) | |
| def complete_step(uid: str, note: Optional[str] = None) -> Dict[str, Any]: | |
| """ | |
| User zrobił zadanie → zwiększamy streak, dopisujemy do historii | |
| i generujemy kolejny krok (na razie prosty). | |
| """ | |
| db = _load_db() | |
| if uid not in db: | |
| raise ValueError(f"Contract with uid={uid} not found") | |
| contract = db[uid] | |
| now = int(time.time()) | |
| # aktualizacja streak | |
| contract["streak"] = int(contract.get("streak") or 0) + 1 | |
| contract["last_done_at"] = now | |
| # dopisanie historii | |
| contract.setdefault("history", []) | |
| contract["history"].append( | |
| { | |
| "ts": now, | |
| "done_step": contract.get("next_step"), | |
| "note": note, | |
| } | |
| ) | |
| # nowy krok - tutaj możesz później wpiąć bardziej zaawansowany plan_generator | |
| link = contract.get("link", "") | |
| category = contract.get("category", "general") | |
| contract["next_step"] = _build_initial_step(link, category) | |
| db[uid] = contract | |
| _save_db(db) | |
| return contract | |
| def get_next_step(uid: str) -> Dict[str, Any]: | |
| """ | |
| Zwraca aktualny kontrakt i next_step dla danego uid. | |
| """ | |
| contract = get_contract(uid) | |
| if not contract: | |
| raise ValueError(f"Contract with uid={uid} not found") | |
| return { | |
| "uid": contract["uid"], | |
| "link": contract["link"], | |
| "category": contract["category"], | |
| "streak": contract.get("streak", 0), | |
| "next_step": contract.get("next_step"), | |
| "last_done_at": contract.get("last_done_at"), | |
| } |