406 lines
14 KiB
Python
406 lines
14 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
four_anchors.py — Система четырёх якорей Montana
|
||
|
||
Книга Монтана, Глава 06:
|
||
> "Визуальный якорь — изображение момента"
|
||
> "Пространственно-временной якорь — GPS + timestamp"
|
||
> "Аудиальный якорь — музыка, которая играла"
|
||
> "Дигитальный якорь — текст + контекст"
|
||
|
||
Четыре координаты для любой точки памяти.
|
||
Якоря работают вместе для надёжной верификации.
|
||
|
||
Дополнительно: Totem Protocol
|
||
> "Парный тотем. Два человека знают одинаковую деталь о физическом предмете."
|
||
"""
|
||
|
||
from dataclasses import dataclass, field
|
||
from datetime import datetime, timezone
|
||
from typing import Dict, List, Optional, Tuple
|
||
from enum import Enum
|
||
import hashlib
|
||
|
||
|
||
class AnchorType(Enum):
|
||
"""Типы якорей."""
|
||
VISUAL = "visual" # Изображение, скриншот
|
||
SPATIOTEMPORAL = "spatiotemporal" # GPS + timestamp
|
||
AUDIO = "audio" # Саундтрек момента
|
||
DIGITAL = "digital" # Текст + контекст
|
||
|
||
|
||
@dataclass
|
||
class Anchor:
|
||
"""Якорь памяти."""
|
||
anchor_type: AnchorType
|
||
reference: str # Ссылка или данные
|
||
description: str # Описание
|
||
created_at: str
|
||
verified: bool = False
|
||
|
||
def to_hash(self) -> str:
|
||
data = f"{self.anchor_type.value}:{self.reference}:{self.created_at}"
|
||
return hashlib.sha256(data.encode()).hexdigest()
|
||
|
||
|
||
@dataclass
|
||
class Totem:
|
||
"""
|
||
Тотем — парный физический объект для верификации.
|
||
|
||
Книга Монтана:
|
||
> "Как в 'Начале'. Волчок Кобба — предмет, который знает только он."
|
||
> "Парный тотем. Два человека знают одинаковую деталь."
|
||
"""
|
||
totem_id: str
|
||
object_description: str # "Красные мокасины"
|
||
secret_detail: str # Деталь, которую знают только двое
|
||
owner_a: str # Первый владелец
|
||
owner_b: str # Второй владелец
|
||
created_at: str
|
||
|
||
def verify(self, detail_guess: str) -> bool:
|
||
"""Верифицировать через секретную деталь."""
|
||
return detail_guess.lower().strip() == self.secret_detail.lower().strip()
|
||
|
||
|
||
@dataclass
|
||
class MemoryPoint:
|
||
"""Точка памяти с четырьмя якорями."""
|
||
point_id: str
|
||
visual: Optional[Anchor] = None
|
||
spatiotemporal: Optional[Anchor] = None
|
||
audio: Optional[Anchor] = None
|
||
digital: Optional[Anchor] = None
|
||
totems: List[str] = field(default_factory=list) # ID тотемов
|
||
|
||
@property
|
||
def anchor_count(self) -> int:
|
||
"""Количество установленных якорей."""
|
||
count = 0
|
||
if self.visual:
|
||
count += 1
|
||
if self.spatiotemporal:
|
||
count += 1
|
||
if self.audio:
|
||
count += 1
|
||
if self.digital:
|
||
count += 1
|
||
return count
|
||
|
||
@property
|
||
def is_fully_anchored(self) -> bool:
|
||
"""Все четыре якоря установлены."""
|
||
return self.anchor_count == 4
|
||
|
||
|
||
class FourAnchorsSystem:
|
||
"""
|
||
Система четырёх якорей для координат памяти.
|
||
|
||
Книга Монтана:
|
||
> "Одинаковые трэки в сэте — это переходы в координатах памяти."
|
||
> "Когда ты слушаешь с временной точкой контекста в тексте,
|
||
> тогда ты узнаёшь координату."
|
||
"""
|
||
|
||
def __init__(self):
|
||
self.memory_points: Dict[str, MemoryPoint] = {}
|
||
self.totems: Dict[str, Totem] = {}
|
||
self.audio_map: Dict[str, List[str]] = {} # track → [point_ids]
|
||
|
||
def create_memory_point(self, description: str = "") -> MemoryPoint:
|
||
"""Создать новую точку памяти."""
|
||
point_id = hashlib.sha256(
|
||
f"{datetime.now().isoformat()}:{description}".encode()
|
||
).hexdigest()[:16]
|
||
|
||
point = MemoryPoint(point_id=point_id)
|
||
self.memory_points[point_id] = point
|
||
return point
|
||
|
||
def set_visual_anchor(
|
||
self,
|
||
point_id: str,
|
||
image_url: str,
|
||
description: str = ""
|
||
) -> Anchor:
|
||
"""
|
||
Установить визуальный якорь.
|
||
|
||
Args:
|
||
point_id: ID точки памяти
|
||
image_url: URL или путь к изображению
|
||
description: Описание
|
||
|
||
Returns:
|
||
Anchor
|
||
"""
|
||
anchor = Anchor(
|
||
anchor_type=AnchorType.VISUAL,
|
||
reference=image_url,
|
||
description=description or "Visual moment capture",
|
||
created_at=datetime.now(timezone.utc).isoformat()
|
||
)
|
||
|
||
self.memory_points[point_id].visual = anchor
|
||
return anchor
|
||
|
||
def set_spatiotemporal_anchor(
|
||
self,
|
||
point_id: str,
|
||
latitude: float,
|
||
longitude: float,
|
||
timestamp: str = None
|
||
) -> Anchor:
|
||
"""
|
||
Установить пространственно-временной якорь.
|
||
|
||
Args:
|
||
point_id: ID точки памяти
|
||
latitude: Широта
|
||
longitude: Долгота
|
||
timestamp: ISO timestamp (если None — текущее время)
|
||
|
||
Returns:
|
||
Anchor
|
||
"""
|
||
ts = timestamp or datetime.now(timezone.utc).isoformat()
|
||
reference = f"{latitude},{longitude}@{ts}"
|
||
|
||
anchor = Anchor(
|
||
anchor_type=AnchorType.SPATIOTEMPORAL,
|
||
reference=reference,
|
||
description=f"Location: {latitude}, {longitude}",
|
||
created_at=ts
|
||
)
|
||
|
||
self.memory_points[point_id].spatiotemporal = anchor
|
||
return anchor
|
||
|
||
def set_audio_anchor(
|
||
self,
|
||
point_id: str,
|
||
track_name: str,
|
||
artist: str = "",
|
||
url: str = ""
|
||
) -> Anchor:
|
||
"""
|
||
Установить аудиальный якорь.
|
||
|
||
Книга Монтана:
|
||
> "Музыка как машина времени."
|
||
|
||
Args:
|
||
point_id: ID точки памяти
|
||
track_name: Название трека
|
||
artist: Исполнитель
|
||
url: Ссылка на трек
|
||
|
||
Returns:
|
||
Anchor
|
||
"""
|
||
reference = f"{artist} - {track_name}" if artist else track_name
|
||
if url:
|
||
reference += f" ({url})"
|
||
|
||
anchor = Anchor(
|
||
anchor_type=AnchorType.AUDIO,
|
||
reference=reference,
|
||
description="Soundtrack of the moment",
|
||
created_at=datetime.now(timezone.utc).isoformat()
|
||
)
|
||
|
||
self.memory_points[point_id].audio = anchor
|
||
|
||
# Добавить в audio map для поиска
|
||
track_key = track_name.lower()
|
||
if track_key not in self.audio_map:
|
||
self.audio_map[track_key] = []
|
||
self.audio_map[track_key].append(point_id)
|
||
|
||
return anchor
|
||
|
||
def set_digital_anchor(
|
||
self,
|
||
point_id: str,
|
||
text: str,
|
||
context: str = ""
|
||
) -> Anchor:
|
||
"""
|
||
Установить дигитальный якорь.
|
||
|
||
Args:
|
||
point_id: ID точки памяти
|
||
text: Текст
|
||
context: Контекст (откуда, зачем)
|
||
|
||
Returns:
|
||
Anchor
|
||
"""
|
||
anchor = Anchor(
|
||
anchor_type=AnchorType.DIGITAL,
|
||
reference=text[:500], # Первые 500 символов
|
||
description=context or "Digital text anchor",
|
||
created_at=datetime.now(timezone.utc).isoformat()
|
||
)
|
||
|
||
self.memory_points[point_id].digital = anchor
|
||
return anchor
|
||
|
||
def create_totem(
|
||
self,
|
||
object_description: str,
|
||
secret_detail: str,
|
||
owner_a: str,
|
||
owner_b: str
|
||
) -> Totem:
|
||
"""
|
||
Создать парный тотем.
|
||
|
||
Args:
|
||
object_description: Описание объекта ("Красные мокасины")
|
||
secret_detail: Секретная деталь
|
||
owner_a: Первый владелец
|
||
owner_b: Второй владелец
|
||
|
||
Returns:
|
||
Totem
|
||
"""
|
||
totem_id = hashlib.sha256(
|
||
f"{object_description}:{owner_a}:{owner_b}".encode()
|
||
).hexdigest()[:16]
|
||
|
||
totem = Totem(
|
||
totem_id=totem_id,
|
||
object_description=object_description,
|
||
secret_detail=secret_detail,
|
||
owner_a=owner_a,
|
||
owner_b=owner_b,
|
||
created_at=datetime.now(timezone.utc).isoformat()
|
||
)
|
||
|
||
self.totems[totem_id] = totem
|
||
return totem
|
||
|
||
def find_by_track(self, track_name: str) -> List[MemoryPoint]:
|
||
"""
|
||
Найти точки памяти по треку.
|
||
|
||
Книга Монтана:
|
||
> "Одинаковые трэки в сэте — это переходы в координатах памяти."
|
||
|
||
Args:
|
||
track_name: Название трека
|
||
|
||
Returns:
|
||
Список точек памяти с этим треком
|
||
"""
|
||
track_key = track_name.lower()
|
||
point_ids = self.audio_map.get(track_key, [])
|
||
return [self.memory_points[pid] for pid in point_ids if pid in self.memory_points]
|
||
|
||
def get_anchor_status(self, point_id: str) -> Dict:
|
||
"""Статус якорей для точки памяти."""
|
||
point = self.memory_points.get(point_id)
|
||
if not point:
|
||
return {"error": "Point not found"}
|
||
|
||
return {
|
||
"point_id": point_id,
|
||
"visual": point.visual is not None,
|
||
"spatiotemporal": point.spatiotemporal is not None,
|
||
"audio": point.audio is not None,
|
||
"digital": point.digital is not None,
|
||
"anchor_count": point.anchor_count,
|
||
"fully_anchored": point.is_fully_anchored,
|
||
"totems": len(point.totems)
|
||
}
|
||
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
# DEMO
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
|
||
if __name__ == "__main__":
|
||
system = FourAnchorsSystem()
|
||
|
||
print("=" * 60)
|
||
print("FOUR ANCHORS SYSTEM — Система якорей памяти")
|
||
print("=" * 60)
|
||
print("\n'Четыре координаты для любой точки памяти.'")
|
||
|
||
# Создаём точку памяти
|
||
point = system.create_memory_point("День Юноны")
|
||
|
||
print(f"\n--- СОЗДАНА ТОЧКА ПАМЯТИ ---")
|
||
print(f"ID: {point.point_id}")
|
||
|
||
# Устанавливаем якоря
|
||
print("\n--- УСТАНОВКА ЯКОРЕЙ ---")
|
||
|
||
# 1. Визуальный
|
||
system.set_visual_anchor(
|
||
point.point_id,
|
||
"https://t.me/mylifethoughts369/338",
|
||
"Скриншот момента"
|
||
)
|
||
print("✓ Визуальный якорь установлен")
|
||
|
||
# 2. Пространственно-временной
|
||
system.set_spatiotemporal_anchor(
|
||
point.point_id,
|
||
latitude=55.7558,
|
||
longitude=37.6173
|
||
)
|
||
print("✓ Пространственно-временной якорь установлен")
|
||
|
||
# 3. Аудиальный
|
||
system.set_audio_anchor(
|
||
point.point_id,
|
||
"I'm ready to go through hell with you",
|
||
"Unknown Artist"
|
||
)
|
||
print("✓ Аудиальный якорь установлен")
|
||
|
||
# 4. Дигитальный
|
||
system.set_digital_anchor(
|
||
point.point_id,
|
||
"Это День Юноны сегодня точно",
|
||
"Глава 06, Книга Монтана"
|
||
)
|
||
print("✓ Дигитальный якорь установлен")
|
||
|
||
# Статус
|
||
print("\n--- СТАТУС ЯКОРЕЙ ---")
|
||
status = system.get_anchor_status(point.point_id)
|
||
print(f"Визуальный: {'✓' if status['visual'] else '✗'}")
|
||
print(f"Пространственно-временной: {'✓' if status['spatiotemporal'] else '✗'}")
|
||
print(f"Аудиальный: {'✓' if status['audio'] else '✗'}")
|
||
print(f"Дигитальный: {'✓' if status['digital'] else '✗'}")
|
||
print(f"Полностью закреплено: {'ДА' if status['fully_anchored'] else 'НЕТ'}")
|
||
|
||
# Тотем
|
||
print("\n--- СОЗДАНИЕ ТОТЕМА ---")
|
||
totem = system.create_totem(
|
||
object_description="Красные мокасины",
|
||
secret_detail="красный",
|
||
owner_a="alejandro",
|
||
owner_b="mama"
|
||
)
|
||
print(f"Тотем: {totem.object_description}")
|
||
print(f"Владельцы: {totem.owner_a} ↔ {totem.owner_b}")
|
||
|
||
# Верификация
|
||
print("\n--- ВЕРИФИКАЦИЯ ТОТЕМА ---")
|
||
test_answer = "красный"
|
||
verified = totem.verify(test_answer)
|
||
print(f"Вопрос: 'А мокасины какого у тебя цвета?'")
|
||
print(f"Ответ: '{test_answer}'")
|
||
print(f"Результат: {'✓ ВЕРИФИЦИРОВАНО' if verified else '✗ ПРОВАЛ'}")
|
||
|
||
print("\n" + "=" * 60)
|
||
print("'Парный тотем. Два человека. Одна деталь.'")
|
||
print("=" * 60)
|