Files
microdao-daarion/services/secondme-service/service.py
Apple 3de3c8cb36 feat: Add presence heartbeat for Matrix online status
- matrix-gateway: POST /internal/matrix/presence/online endpoint
- usePresenceHeartbeat hook with activity tracking
- Auto away after 5 min inactivity
- Offline on page close/visibility change
- Integrated in MatrixChatRoom component
2025-11-27 00:19:40 -08:00

179 lines
5.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Second Me Service Logic
"""
import os
import httpx
import time
import logging
from typing import List, Dict
import repository
logger = logging.getLogger(__name__)
# Config
SECONDME_AGENT_ID = os.getenv("SECONDME_AGENT_ID", "ag_secondme_global")
AGENTS_SERVICE_URL = os.getenv("AGENTS_SERVICE_URL", "http://agents-service:7002")
async def invoke_second_me(user_id: str, prompt: str) -> Dict:
"""
Викликати Second Me agent для користувача
1. Отримати або створити сесію
2. Зберегти user prompt
3. Зібрати контекст (останні N повідомлень)
4. Викликати Agents Core
5. Зберегти assistant відповідь
6. Повернути результат
"""
start_time = time.monotonic()
# 1. Отримати/створити сесію
session = await repository.get_or_create_session(user_id, agent_id=SECONDME_AGENT_ID)
session_id = session["id"]
# 2. Зберегти user prompt
await repository.create_message(
session_id=session_id,
user_id=user_id,
role="user",
content=prompt
)
# 3. Зібрати контекст
messages = await repository.get_session_messages(session_id, limit=10)
# Сформувати контекст для LLM
context_messages = []
for msg in messages:
context_messages.append({
"role": msg["role"],
"content": msg["content"]
})
# 4. Викликати Agents Core
try:
response_text, tokens_used = await call_agents_core(
agent_id=SECONDME_AGENT_ID,
user_id=user_id,
prompt=prompt,
context=context_messages
)
except Exception as e:
logger.error(f"Failed to call Agents Core: {e}")
# Fallback до mock відповіді
response_text = f"Я — твій Second Me. Ти запитав: '{prompt}'. На жаль, зараз я не можу підключитися до LLM, але я тут для тебе! 🤖"
tokens_used = 50
latency_ms = int((time.monotonic() - start_time) * 1000)
# 5. Зберегти assistant відповідь
await repository.create_message(
session_id=session_id,
user_id=user_id,
role="assistant",
content=response_text,
tokens_used=tokens_used,
latency_ms=latency_ms
)
# Оновити час останньої взаємодії
await repository.update_session_interaction(session_id)
# 6. Повернути результат
return {
"response": response_text,
"tokens_used": tokens_used,
"latency_ms": latency_ms
}
async def call_agents_core(
agent_id: str,
user_id: str,
prompt: str,
context: List[Dict]
) -> tuple[str, int]:
"""
Викликати Agents Core service
Returns: (response_text, tokens_used)
"""
# Формуємо input з контекстом
context_str = ""
if context:
for msg in context[-5:]: # Останні 5 повідомлень
role = msg["role"]
content = msg["content"]
context_str += f"{role.capitalize()}: {content}\n"
input_text = f"""You are Second Me — персональний цифровий двійник користувача в DAARION City.
Контекст попередніх розмов:
{context_str}
Поточне запитання користувача:
{prompt}
Твоя відповідь (українською мовою):"""
payload = {
"input": input_text,
"context": {
"user_id": user_id,
"kind": "secondme",
"agent_id": agent_id
}
}
url = f"{AGENTS_SERVICE_URL}/agents/invoke"
async with httpx.AsyncClient(timeout=30.0) as client:
response = await client.post(url, json={
"agent_id": agent_id,
"payload": payload
})
response.raise_for_status()
data = response.json()
# TODO: адаптувати під реальний формат відповіді Agents Core
response_text = data.get("response", data.get("reply", "Немає відповіді"))
tokens_used = data.get("tokens_used", 100)
return response_text, tokens_used
async def get_user_history(user_id: str, limit: int = 5) -> List[Dict]:
"""Отримати історію користувача"""
messages = await repository.get_user_messages(user_id, limit=limit)
return [
{
"role": msg["role"],
"content": msg["content"],
"created_at": msg["created_at"].isoformat()
}
for msg in messages
]
async def get_user_profile(user_id: str) -> Dict:
"""Отримати профіль Second Me для користувача"""
stats = await repository.get_user_stats(user_id)
return {
"user_id": user_id,
"agent_id": SECONDME_AGENT_ID,
"total_interactions": stats.get("total_messages", 0),
"last_interaction": stats.get("last_interaction").isoformat() if stats.get("last_interaction") else None
}
async def clear_user_history(user_id: str):
"""Очистити історію користувача"""
await repository.clear_user_history(user_id)