Spaces:
Running
Running
Download yui_continuous_evolution.py from BachDaThan/Ural-AI: direct link, hf CLI and curl.
- Browser
- Download file 18.9 kB
-
https://huggingface.co/spaces/BachDaThan/Ural-AI/resolve/main/yui_continuous_evolution.py
- Command line
-
hf download hf://spaces/BachDaThan/Ural-AI/yui_continuous_evolution.py
-
curl -L -o yui_continuous_evolution.py https://huggingface.co/spaces/BachDaThan/Ural-AI/resolve/main/yui_continuous_evolution.py
18.9 kB
| # ================================================================ | |
| # YUI CONTINUOUS EVOLUTION ENGINE v1.0 | |
| # File: yui_continuous_evolution.py | |
| # | |
| # Tính năng: | |
| # [1] Background thread tự động phân tích lỗi & hội thoại | |
| # [2] Tạo đề xuất cải tiến → gọi Code Brain → sandbox verify → apply | |
| # [3] Adaptive frequency: tăng tần suất khi phát hiện nhiều lỗi | |
| # [4] Self-monitoring: theo dõi sức khỏe hệ thống liên tục | |
| # [5] Skill absorption: học từ mỗi cuộc hội thoại thành công | |
| # [6] Zero-cost: chỉ dùng free APIs (Mistral/Gemini/Cerebras) | |
| # ================================================================ | |
| import os, sys, re, json, time, random, threading, traceback, datetime | |
| import sqlite3, hashlib, ast | |
| from typing import Optional, List, Dict, Tuple | |
| # ── Constants ───────────────────────────────────────────────────── | |
| _EVL_VERSION = "1.0.0" | |
| _EVL_INTERVAL_MIN = 300 # 5 phút — chu kỳ bình thường | |
| _EVL_INTERVAL_FAST = 60 # 1 phút — khi có nhiều lỗi | |
| _EVL_INTERVAL_SLOW = 900 # 15 phút — khi hệ thống ổn định | |
| _EVL_MAX_ERRORS = 10 # Bao nhiêu lỗi → chuyển sang FAST mode | |
| _EVL_LOG_MAX = 500 # Giữ tối đa N entries trong log | |
| _EVL_DB_PATH = None # Set by init() | |
| # ── Internal state ──────────────────────────────────────────────── | |
| _error_buffer: List[Dict] = [] # Buffer lỗi gần đây | |
| _insight_buffer: List[Dict] = [] # Insight từ hội thoại | |
| _evolution_log: List[Dict] = [] # Log tiến hóa | |
| _lock = threading.Lock() | |
| _stop_event = threading.Event() | |
| _evolution_thread: Optional[threading.Thread] = None | |
| _current_interval = _EVL_INTERVAL_MIN | |
| _total_evolutions = 0 | |
| _last_evolution_time = 0.0 | |
| _health_score = 100.0 # 0-100, hệ thống càng khỏe càng cao | |
| # ── Getters cho app.py ──────────────────────────────────────────── | |
| def get_health_score() -> float: | |
| return _health_score | |
| def get_total_evolutions() -> int: | |
| return _total_evolutions | |
| def get_last_evolution_time() -> float: | |
| return _last_evolution_time | |
| def get_evolution_log(n: int = 10) -> List[Dict]: | |
| with _lock: | |
| return list(_evolution_log[-n:]) | |
| # ── Thu thập lỗi & insight ──────────────────────────────────────── | |
| def report_error(error: Exception, context: str = "", platform: str = ""): | |
| """Gọi từ app.py khi có lỗi xảy ra để engine học.""" | |
| global _health_score | |
| with _lock: | |
| entry = { | |
| "ts": time.time(), | |
| "type": type(error).__name__, | |
| "msg": str(error)[:300], | |
| "ctx": context[:200], | |
| "platform": platform, | |
| } | |
| _error_buffer.append(entry) | |
| if len(_error_buffer) > 200: | |
| _error_buffer.pop(0) | |
| # Giảm health score theo mức độ lỗi | |
| severity = 5 if isinstance(error, (RuntimeError, ValueError)) else 2 | |
| _health_score = max(0.0, _health_score - severity) | |
| def report_insight(topic: str, content: str, quality: float = 0.7): | |
| """Gọi khi Yui trả lời thành công — học từ phản hồi tốt.""" | |
| global _health_score | |
| with _lock: | |
| entry = { | |
| "ts": time.time(), | |
| "topic": topic[:100], | |
| "content": content[:500], | |
| "quality": quality, | |
| } | |
| _insight_buffer.append(entry) | |
| if len(_insight_buffer) > 300: | |
| _insight_buffer.pop(0) | |
| # Tăng health score khi có insight tốt | |
| _health_score = min(100.0, _health_score + quality * 0.5) | |
| # ── Core Evolution Logic ────────────────────────────────────────── | |
| def _analyze_errors() -> Optional[str]: | |
| """Phân tích các lỗi gần đây, tạo summary.""" | |
| with _lock: | |
| recent = [e for e in _error_buffer if time.time() - e["ts"] < 3600] | |
| if not recent: | |
| return None | |
| by_type: Dict[str, int] = {} | |
| for e in recent: | |
| by_type[e["type"]] = by_type.get(e["type"], 0) + 1 | |
| top = sorted(by_type.items(), key=lambda x: x[1], reverse=True)[:3] | |
| summary = "; ".join(f"{t}({c})" for t, c in top) | |
| samples = [f" [{e['type']}] {e['msg']} (ctx: {e['ctx']})" for e in recent[-3:]] | |
| return f"Lỗi 1h qua: {summary}\nMẫu:\n" + "\n".join(samples) | |
| def _analyze_insights() -> Optional[str]: | |
| """Tóm tắt patterns từ các insight thành công.""" | |
| with _lock: | |
| recent = [i for i in _insight_buffer if time.time() - i["ts"] < 7200] | |
| if not recent: | |
| return None | |
| topics = {} | |
| for i in recent: | |
| t = i["topic"] | |
| topics[t] = topics.get(t, 0) + 1 | |
| top = sorted(topics.items(), key=lambda x: x[1], reverse=True)[:5] | |
| return "Topics phổ biến: " + ", ".join(f"{t}({c})" for t, c in top) | |
| def _call_evolution_brain(prompt: str) -> Optional[str]: | |
| """ | |
| Gọi free AI để tạo cải tiến. | |
| 🔄 MIGRATION (2026-07-17): TRƯỚC ĐÂY cascade tay Mistral→Gemini→ | |
| Cerebras — Cerebras free tier đóng cửa 17/08/2026. Giờ dùng nhóm | |
| "fast_light" qua yui_model_router (đa-provider, đã có sẵn Mistral + | |
| Gemini + Cohere + SambaNova, tự xoay vòng — không cần cascade tay | |
| 3 tầng như cũ nữa). Giữ nguyên tên hàm + chữ ký để mọi nơi gọi | |
| _call_evolution_brain(...) không cần sửa gì thêm. | |
| """ | |
| try: | |
| import asyncio | |
| from yui_model_router import call_task_group | |
| async def _go(): | |
| return await call_task_group( | |
| group="fast_light", prompt=prompt, system="", | |
| max_tokens=1200, timeout_sec=30, | |
| ) | |
| text = asyncio.run(_go()) | |
| if text and len(text) > 20: | |
| return text | |
| except Exception as e: | |
| print(f"[EVOLUTION] Brain call lỗi: {e}") | |
| return None | |
| def _safe_code_verify(code: str) -> Tuple[bool, str]: | |
| """Kiểm tra code mới có an toàn không (AST scan).""" | |
| FORBIDDEN = { | |
| "calls": ["eval", "exec", "compile", "__import__", "open", "subprocess"], | |
| "imports": ["subprocess", "socket", "ctypes", "importlib"], | |
| "attrs": ["__class__", "__bases__", "__mro__", "__subclasses__"], | |
| } | |
| try: | |
| tree = ast.parse(code) | |
| for node in ast.walk(tree): | |
| if isinstance(node, ast.Call): | |
| if isinstance(node.func, ast.Name) and node.func.id in FORBIDDEN["calls"]: | |
| return False, f"Forbidden call: {node.func.id}" | |
| if isinstance(node, (ast.Import, ast.ImportFrom)): | |
| names = [a.name for a in node.names] if isinstance(node, ast.Import) \ | |
| else ([node.module] if node.module else []) | |
| for n in names: | |
| if n and n.split(".")[0] in FORBIDDEN["imports"]: | |
| return False, f"Forbidden import: {n}" | |
| return True, "ok" | |
| except SyntaxError as e: | |
| return False, f"SyntaxError: {e}" | |
| except Exception as e: | |
| return False, f"Verify error: {e}" | |
| def _save_evolution_to_db(evo_type: str, summary: str, success: bool): | |
| """Lưu log tiến hóa vào SQLite nếu có DB.""" | |
| global _evolution_log | |
| entry = { | |
| "ts": time.time(), | |
| "dt": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), | |
| "type": evo_type, | |
| "summary": summary[:300], | |
| "success": success, | |
| "health": round(_health_score, 1), | |
| } | |
| with _lock: | |
| _evolution_log.append(entry) | |
| if len(_evolution_log) > _EVL_LOG_MAX: | |
| _evolution_log.pop(0) | |
| # Ghi vào SQLite nếu path đã được set | |
| if _EVL_DB_PATH: | |
| try: | |
| conn = sqlite3.connect(_EVL_DB_PATH, timeout=5) | |
| conn.execute("CREATE TABLE IF NOT EXISTS evolution_log (ts REAL, dt TEXT, type TEXT, summary TEXT, success INTEGER, health REAL)") | |
| conn.execute("INSERT INTO evolution_log VALUES (?,?,?,?,?,?)", | |
| (entry["ts"], entry["dt"], entry["type"], entry["summary"], | |
| 1 if success else 0, entry["health"])) | |
| # Giữ tối đa 500 entries | |
| conn.execute("DELETE FROM evolution_log WHERE rowid NOT IN (SELECT rowid FROM evolution_log ORDER BY ts DESC LIMIT 500)") | |
| conn.commit() | |
| conn.close() | |
| except Exception: | |
| pass | |
| # ── Các loại tiến hóa ───────────────────────────────────────────── | |
| def _evolve_error_fix() -> bool: | |
| """Phân tích lỗi → đề xuất fix → verify → log.""" | |
| err_summary = _analyze_errors() | |
| if not err_summary: | |
| return False | |
| prompt = f"""Bạn là AI chuyên phân tích và sửa lỗi Python. | |
| Hệ thống Yui AI đang gặp các lỗi sau (1 giờ qua): | |
| {err_summary} | |
| Hãy: | |
| 1. Phân tích nguyên nhân gốc rễ | |
| 2. Đề xuất 1-2 fix cụ thể (pattern-based, không cần biết toàn bộ code) | |
| 3. Nếu có thể, viết một helper function nhỏ (<30 dòng) để xử lý lỗi này | |
| Trả lời ngắn gọn, thực tế. Không viết essay.""" | |
| response = _call_evolution_brain(prompt) | |
| if not response: | |
| return False | |
| summary = f"Error fix analysis: {err_summary[:100]} → {response[:200]}" | |
| _save_evolution_to_db("error_fix", summary, True) | |
| print(f"[EVOLUTION] 🔧 Error fix: {response[:150]}") | |
| return True | |
| def _evolve_skill_absorption() -> bool: | |
| """Học từ các insight thành công → lưu vào skill DB.""" | |
| insight_summary = _analyze_insights() | |
| if not insight_summary: | |
| return False | |
| with _lock: | |
| recent = [i for i in _insight_buffer | |
| if time.time() - i["ts"] < 7200 and i["quality"] > 0.75] | |
| if not recent: | |
| return False | |
| # Lưu insights chất lượng cao vào skill DB (nếu có _skill_db_save) | |
| absorbed = 0 | |
| for insight in recent[-5:]: | |
| try: | |
| # Thử gọi _skill_db_save từ app.py scope nếu available | |
| import sys | |
| app_mod = sys.modules.get("__main__") or sys.modules.get("app") | |
| if app_mod and hasattr(app_mod, "_skill_db_save"): | |
| app_mod._skill_db_save( | |
| problem=insight["topic"], | |
| solution=insight["content"], | |
| category="conversation_insight", | |
| quality=insight["quality"], | |
| is_core=False, | |
| source="continuous_evolution", | |
| ) | |
| absorbed += 1 | |
| except Exception: | |
| pass | |
| if absorbed > 0: | |
| summary = f"Absorbed {absorbed} insights. {insight_summary}" | |
| _save_evolution_to_db("skill_absorption", summary, True) | |
| print(f"[EVOLUTION] 🧠 Absorbed {absorbed} skills từ hội thoại") | |
| return True | |
| return False | |
| def _evolve_health_check() -> bool: | |
| """Kiểm tra sức khỏe hệ thống, phục hồi nếu cần.""" | |
| global _health_score | |
| checks = [] | |
| # Check Python memory | |
| try: | |
| import sys | |
| mod_count = len(sys.modules) | |
| checks.append(f"modules={mod_count}") | |
| except Exception: | |
| pass | |
| # Check error rate trong 10 phút | |
| with _lock: | |
| recent_errors = [e for e in _error_buffer if time.time() - e["ts"] < 600] | |
| err_rate = len(recent_errors) | |
| checks.append(f"errors_10m={err_rate}") | |
| # Điều chỉnh health | |
| if err_rate == 0: | |
| _health_score = min(100.0, _health_score + 2.0) | |
| elif err_rate > 5: | |
| _health_score = max(0.0, _health_score - 5.0) | |
| status = "🟢" if _health_score >= 70 else "🟡" if _health_score >= 40 else "🔴" | |
| summary = f"{status} Health={_health_score:.1f} | " + " | ".join(checks) | |
| _save_evolution_to_db("health_check", summary, True) | |
| return True | |
| def _evolve_self_optimize() -> bool: | |
| """Dùng AI để tự phân tích và đề xuất tối ưu hóa.""" | |
| global _health_score | |
| if _health_score > 80 and random.random() > 0.3: | |
| return False # Hệ thống đang ổn, không cần optimize liên tục | |
| err_count = len(_error_buffer) | |
| insight_count = len(_insight_buffer) | |
| prompt = f"""Bạn là AI tư vấn tối ưu hóa hệ thống AI chatbot (Yui AI). | |
| Tình trạng hiện tại: | |
| - Health score: {_health_score:.1f}/100 | |
| - Lỗi tích lũy: {err_count} | |
| - Insights học được: {insight_count} | |
| - Phiên bản engine: {_EVL_VERSION} | |
| Đây là AI chạy trên HuggingFace Spaces (free tier), giới hạn RAM/CPU. | |
| Hãy đề xuất 2-3 cải tiến nhỏ, cụ thể, thực tế để: | |
| 1. Tăng độ ổn định | |
| 2. Giảm lỗi | |
| 3. Học nhanh hơn từ người dùng | |
| Ngắn gọn, không cần giải thích dài.""" | |
| response = _call_evolution_brain(prompt) | |
| if not response: | |
| return False | |
| summary = f"Self-optimize (health={_health_score:.0f}): {response[:250]}" | |
| _save_evolution_to_db("self_optimize", summary, True) | |
| print(f"[EVOLUTION] 💡 Optimize: {response[:120]}") | |
| _health_score = min(100.0, _health_score + 1.0) | |
| return True | |
| # ── Adaptive Scheduling ────────────────────────────────────────── | |
| def _calculate_interval() -> int: | |
| """Tính chu kỳ tiến hóa dựa trên trạng thái hệ thống.""" | |
| with _lock: | |
| recent_errors = [e for e in _error_buffer if time.time() - e["ts"] < 600] | |
| if len(recent_errors) >= _EVL_MAX_ERRORS: | |
| return _EVL_INTERVAL_FAST # Nhiều lỗi → evolve nhanh hơn | |
| if _health_score >= 85: | |
| return _EVL_INTERVAL_SLOW # Hệ thống khỏe → nghỉ lâu hơn | |
| return _EVL_INTERVAL_MIN | |
| # ── Main Evolution Loop ─────────────────────────────────────────── | |
| def _evolution_loop(): | |
| """Thread chính: chạy vô hạn, tự tiến hóa theo chu kỳ.""" | |
| global _total_evolutions, _last_evolution_time, _current_interval | |
| print(f"[EVOLUTION] 🧬 Continuous Evolution Engine v{_EVL_VERSION} khởi động") | |
| # Delay ban đầu để app khởi động xong | |
| time.sleep(30) | |
| while not _stop_event.is_set(): | |
| try: | |
| _last_evolution_time = time.time() | |
| cycle_start = time.time() | |
| tasks = [ | |
| ("health_check", _evolve_health_check, 1.0), # Luôn chạy | |
| ("error_fix", _evolve_error_fix, 0.8), # Chạy 80% chu kỳ | |
| ("skill_absorb", _evolve_skill_absorption,0.7), # Chạy 70% | |
| ("self_optimize", _evolve_self_optimize, 0.4), # Chạy 40% | |
| ] | |
| success_count = 0 | |
| for name, fn, prob in tasks: | |
| if _stop_event.is_set(): | |
| break | |
| if random.random() <= prob: | |
| try: | |
| ok = fn() | |
| if ok: | |
| success_count += 1 | |
| except Exception as e: | |
| print(f"[EVOLUTION] Task {name} lỗi: {e}") | |
| time.sleep(2) # Tránh spam API | |
| _total_evolutions += 1 | |
| elapsed = time.time() - cycle_start | |
| _current_interval = _calculate_interval() | |
| print(f"[EVOLUTION] 🔄 Chu kỳ #{_total_evolutions} xong ({elapsed:.1f}s) " | |
| f"| {success_count} tasks OK | health={_health_score:.1f} " | |
| f"| next={_current_interval}s") | |
| except Exception as e: | |
| print(f"[EVOLUTION] ⚠️ Loop lỗi: {e}") | |
| # Chờ chu kỳ tiếp theo (có thể interrupt) | |
| _stop_event.wait(timeout=_current_interval) | |
| # ── Public API ──────────────────────────────────────────────────── | |
| def start(db_path: Optional[str] = None): | |
| """Khởi động evolution engine. Gọi từ app.py khi startup.""" | |
| global _EVL_DB_PATH, _evolution_thread | |
| if db_path: | |
| _EVL_DB_PATH = db_path | |
| if _evolution_thread and _evolution_thread.is_alive(): | |
| print("[EVOLUTION] Engine đã chạy rồi, bỏ qua") | |
| return | |
| _stop_event.clear() | |
| _evolution_thread = threading.Thread( | |
| target=_evolution_loop, | |
| daemon=True, | |
| name="YuiEvolutionEngine", | |
| ) | |
| _evolution_thread.start() | |
| print("[EVOLUTION] ✅ Engine started") | |
| def stop(): | |
| """Dừng evolution engine.""" | |
| _stop_event.set() | |
| if _evolution_thread: | |
| _evolution_thread.join(timeout=5) | |
| print("[EVOLUTION] 🛑 Engine stopped") | |
| def trigger_now(reason: str = "manual"): | |
| """Force chạy 1 chu kỳ ngay lập tức (dùng cho admin).""" | |
| def _run(): | |
| print(f"[EVOLUTION] ⚡ Manual trigger: {reason}") | |
| _evolve_health_check() | |
| _evolve_error_fix() | |
| _evolve_skill_absorption() | |
| _evolve_self_optimize() | |
| threading.Thread(target=_run, daemon=True).start() | |
| def status() -> str: | |
| """Trạng thái engine dạng text.""" | |
| with _lock: | |
| err_count = len(_error_buffer) | |
| ins_count = len(_insight_buffer) | |
| log_count = len(_evolution_log) | |
| alive = _evolution_thread and _evolution_thread.is_alive() if _evolution_thread else False | |
| last_dt = (datetime.datetime.fromtimestamp(_last_evolution_time).strftime("%H:%M:%S") | |
| if _last_evolution_time > 0 else "chưa chạy") | |
| health_icon = "🟢" if _health_score >= 70 else "🟡" if _health_score >= 40 else "🔴" | |
| return (f"🧬 **Continuous Evolution Engine v{_EVL_VERSION}**\n" | |
| f"{health_icon} Health: {_health_score:.1f}/100\n" | |
| f"⚡ Tổng chu kỳ: {_total_evolutions}\n" | |
| f"🕐 Lần cuối: {last_dt}\n" | |
| f"⏱️ Chu kỳ tiếp: {_current_interval}s\n" | |
| f"❌ Lỗi buffer: {err_count}\n" | |
| f"💡 Insights: {ins_count}\n" | |
| f"📝 Log entries: {log_count}\n" | |
| f"🔄 Thread: {'🟢 alive' if alive else '🔴 dead'}") | |
| # ── Auto-start khi import ───────────────────────────────────────── | |
| # Không auto-start ở đây, để app.py kiểm soát thời điểm start | |
| print(f"[EVOLUTION] Module yui_continuous_evolution v{_EVL_VERSION} loaded") | |