| |
| |
|
|
| import time |
| import threading |
| from dataclasses import dataclass |
| from typing import Optional, Callable |
|
|
| from .config import AuraConfig |
| from .perception import PerceptionEngine, UserContext, DeviceMode, TimeOfDay |
| from .decision import ValueNetwork, AntiSpamFunnel, ValueScore |
| from .scheduler import HeartbeatScheduler, DualSystemScheduler, FastSystem |
| from .memory import MemoryGraph, MemoryItem |
| from .generation import ContentGenerator, GenerationInput, GenerationMode |
| from .control import ControlPanel, ThermostatMode, SceneMode |
| from .ethics import PrivacyLedger, RedTeamSimulator |
| from .interaction import ExpressionLayer, ExpressionOutput, NotificationLevel |
|
|
|
|
| class AuraEngine: |
| """ |
| Project Aura 主引擎 |
| |
| 整合所有模块,提供统一的主动交互接口。 |
| 使用方式: |
| engine = AuraEngine() |
| engine.start() # 启动心跳循环 |
| engine.on_tick() # 手动触发一次决策 |
| """ |
|
|
| def __init__(self, config: AuraConfig = None): |
| self.config = config or AuraConfig() |
| |
| |
| self.perception = PerceptionEngine() |
| self.memory = MemoryGraph() |
| self.value_net = ValueNetwork() |
| self.antispam = AntiSpamFunnel() |
| self.fast = FastSystem() |
| self.scheduler = DualSystemScheduler() |
| self.generator = ContentGenerator(self.config) |
| self.expression = ExpressionLayer() |
| self.control = ControlPanel() |
| self.privacy = PrivacyLedger() |
| |
| |
| self._heartbeat = HeartbeatScheduler() |
| self._heartbeat.set_callback(self._on_heartbeat) |
| |
| |
| self._running = False |
| self._on_message: Optional[Callable] = None |
|
|
| def set_message_callback(self, callback: Callable[[ExpressionOutput], None]): |
| """设置消息输出回调""" |
| self._on_message = callback |
|
|
| def load_model(self): |
| """加载 DeepSeek R1""" |
| self.generator.load_model() |
|
|
| def start(self): |
| """启动系统""" |
| if self._running: |
| return |
| self._running = True |
| self._heartbeat.start() |
| print("[Aura] ✅ 系统已启动") |
|
|
| def stop(self): |
| """停止系统""" |
| self._running = False |
| self._heartbeat.stop() |
| self.generator.unload() |
| print("[Aura] ⏹ 系统已停止") |
|
|
| def user_interacted(self, text: str = "", mood: str = ""): |
| """用户发生交互时调用""" |
| self.perception.update(is_active_session=True) |
| if text: |
| |
| from .perception import UserMood |
| detected = self.perception.detect_mood_from_text(text) |
| if detected != UserMood.UNKNOWN: |
| self.perception.update(mood=detected.value) |
| |
| item = MemoryItem( |
| id=f"conv_{int(time.time())}", |
| content=text[:200], |
| memory_type="conversation", |
| tags=[mood] if mood else [], |
| ) |
| self.memory.add(item) |
|
|
| def user_went_idle(self): |
| """用户进入空闲状态""" |
| self.perception.update(is_active_session=False) |
|
|
| def _on_heartbeat(self): |
| """心跳回调""" |
| self.on_tick() |
|
|
| def on_tick(self): |
| """执行一次完整的决策循环""" |
| if not self._running: |
| return |
|
|
| |
| ctx = self.perception.tick() |
| |
| |
| if isinstance(ctx.device_mode, str): |
| from .perception import DeviceMode |
| ctx.device_mode = DeviceMode(ctx.device_mode) |
| if isinstance(ctx.time_of_day, str): |
| from .perception import TimeOfDay |
| try: |
| ctx.time_of_day = TimeOfDay(ctx.time_of_day) |
| except: |
| pass |
| if isinstance(ctx.mood, str): |
| from .perception import UserMood |
| try: |
| ctx.mood = UserMood(ctx.mood) |
| except: |
| pass |
| |
| |
| decision_ctx = { |
| "user_id": ctx.user_id, |
| "idle_minutes": ctx.idle_minutes, |
| "time_of_day": ctx.time_of_day.value, |
| "device_mode": ctx.device_mode.value, |
| "is_active_session": ctx.is_active_session, |
| "mood": ctx.mood.value, |
| "last_conversation_topic": ctx.last_conversation_topic or "", |
| "upcoming_events": ctx.upcoming_events, |
| } |
|
|
| |
| score = self.value_net.evaluate( |
| idle_minutes=ctx.idle_minutes, |
| time_of_day=ctx.time_of_day.value, |
| device_mode=ctx.device_mode.value, |
| is_active_session=ctx.is_active_session, |
| mood=ctx.mood.value, |
| topic_match=0.5 if ctx.last_conversation_topic else 0.0, |
| upcoming_events=ctx.upcoming_events, |
| ) |
|
|
| |
| threshold = self.control.get_decision_threshold() |
| |
| |
| topic = ctx.last_conversation_topic or "" |
| allowed, reason = self.antispam.filter(score, topic=topic) |
| if not allowed: |
| return |
|
|
| |
| if not self.control.can_act_on_topic(topic): |
| return |
|
|
| |
| if score.score >= threshold: |
| mode = self._select_mode(score, ctx) |
| gen_input = GenerationInput( |
| mode=mode, |
| user_context=decision_ctx, |
| topic=topic, |
| user_mood=ctx.mood.value, |
| memory_context=[m.content for m in self.memory.recall_recent(5)], |
| ) |
| result = self.generator.generate(gen_input) |
|
|
| |
| output = self.expression.render(result.text, result.confidence) |
| |
| |
| if result.confidence > 0: |
| self.privacy.record_access( |
| data_type="model_inference", |
| purpose=f"主动{result.mode}", |
| is_local=True, |
| ) |
|
|
| |
| self.antispam.record_action(topic=topic) |
| self.perception.update(is_active_session=True) |
|
|
| |
| if self._on_message: |
| self._on_message(output) |
| else: |
| print(f"\n[Aura] 💬 [{mode.value}] {result.text}") |
|
|
| def _select_mode(self, score: ValueScore, ctx: UserContext) -> GenerationMode: |
| """根据场景选择合适的生成模式""" |
| if score.urgency > 0.7 and ctx.time_of_day == TimeOfDay.NIGHT: |
| return GenerationMode.CARING |
| if ctx.last_conversation_topic and score.relevance > 0.5: |
| return GenerationMode.CONTINUE_TOPIC |
| if ctx.upcoming_events: |
| return GenerationMode.REMINDING |
| if score.urgency > 0.5: |
| return GenerationMode.CARING |
| return GenerationMode.CHECK_IN |
|
|