from flask import Flask, render_template import json import os import time import datetime import logging from model.brainmap import get_brainmap from model.journal import read_journal_entries from model.dreams import load_dreams from model.tokenizer import Tokenizer from model.abstraction import cluster_vocab from model.scheduler import get_time_until_next_action, get_next_action_label from context.context import load_context from reader.reader import get_books, load_progress app = Flask(__name__, static_folder="static") tokenizer = Tokenizer() next_cycle_time = time.time() + 900 # Example: 15 minutes from now def load_loss_data(): path = "data/logs/loss.log" if not os.path.exists(path): return [] with open(path, "r", encoding="utf-8") as f: lines = f.readlines() return [float(line.strip().split(",")[1]) for line in lines[-50:]] def load_vocab_growth(): path = "data/logs/vocab_growth.log" if not os.path.exists(path): return [] with open(path, "r", encoding="utf-8") as f: lines = f.readlines() data = [] for line in lines: timestamp, vocab_size = line.strip().split(",") # Reformat timestamp to human-readable readable_time = datetime.datetime.fromtimestamp(float(timestamp)).strftime("%H:%M:%S") data.append((readable_time, int(vocab_size))) return data def get_vocab_size(): path = "data/memory/vocab.json" if not os.path.exists(path): return 0 with open(path, "r", encoding="utf-8") as f: vocab = json.load(f) return len(vocab) def update_next_cycle(seconds): global next_cycle_time next_cycle_time = time.time() + seconds def get_status_summary(): progress_data = load_progress() progress = progress_data.get("progress", {}) current_book = None current_line = 0 # Find the book with the highest progress (e.g., currently being read) if progress: completed = set(progress_data.get("completed", [])) in_progress = {k: v for k, v in progress.items() if k not in completed} if in_progress: current_book = max(in_progress.items(), key=lambda x: x[1])[0] current_line = in_progress[current_book] current_line = progress[current_book] total_lines = 1 if current_book: book_path = os.path.join("data", "books", current_book) if os.path.exists(book_path): with open(book_path, "r", encoding="utf-8") as f: total_lines = len(f.readlines()) else: current_book = None current_line = 0 return { "current_book": current_book, "current_line": current_line, "percent_done": round((current_line / total_lines) * 100, 2) if total_lines > 0 else 0, "memory_size": len(load_context()), "vocab_size": get_vocab_size(), "brainmap_size": len(get_brainmap()), "journal_count": len(read_journal_entries()), "dream": load_dreams()[-1] if load_dreams() else None, "next_action_label": get_next_action_label(), "next_cycle": get_time_until_next_action() } @app.route("/") def index(): status = get_status_summary() return render_template("index.html", status=status) @app.route("/growth") def growth(): brainmap_size = len(get_brainmap()) memory_size = len(load_context()) vocab_growth = load_vocab_growth() return render_template("growth.html", vocab_size=get_vocab_size(), brainmap_size=brainmap_size, memory_size=memory_size, vocab_growth=vocab_growth) @app.route("/brainmap") def brainmap(): try: with open("data/memory/brainmap_cache.json", "r", encoding="utf-8") as f: cached = json.load(f) nodes = cached.get("nodes", []) links = cached.get("links", []) except Exception as e: print(f"[Dashboard] Failed to load brainmap cache: {e}") nodes, links = [], [] return render_template("brainmap.html", nodes=nodes, links=links) @app.route("/journal") def journal(): entries = read_journal_entries() return render_template("journal.html", entries=entries) @app.route("/concepts") def concepts(): clusters = cluster_vocab(n_clusters=10) return render_template("concepts.html", clusters={i: cluster for i, cluster in enumerate(clusters) }) @app.route("/dreams") def dreams(): dreams = load_dreams() recent = dreams[-20:][::-1] # Last 20 dreams, newest first return render_template("dreams.html", dreams=recent) @app.route("/health") def health(): vocab_size = get_vocab_size() brainmap_size = len(get_brainmap()) books = get_books() progress_data = load_progress() dreams = load_dreams() entries = read_journal_entries() completed_books = progress_data.get("completed", []) total_books = len(books) finished_books = len(completed_books) dream_count = len(dreams) journal_count = len(entries) last_dream = dreams[-1]["sentence"] if dream_count > 0 else "None yet." last_entry = entries[-1] if journal_count > 0 else "None yet." # print(f"[Health Monitor] Total Books: {total_books} | Finished Books: {finished_books}") return render_template("health.html", vocab_size=vocab_size, brainmap_size=brainmap_size, total_books=total_books, finished_books=finished_books, dream_count=dream_count, journal_count=journal_count, last_dream=last_dream, last_entry=last_entry) def run_dashboard(): log = logging.getLogger('werkzeug') log.setLevel(logging.ERROR) app.run(host="0.0.0.0", port=5000, debug=False, use_reloader=False)