Add automated session logging system
Some checks failed
Build and Deploy Docs / build-and-deploy (push) Has been cancelled

- Created logs/ structure (sessions, operations, incidents)
- Added session-start/log/end scripts
- Installed Git hooks for auto-logging commits/pushes
- Added shell integration for zsh
- Created CHANGELOG.md
- Documented today's session (2026-01-10)
This commit is contained in:
Apple
2026-01-10 04:53:17 -08:00
parent e67882fd15
commit 744c149300
260 changed files with 6364 additions and 68 deletions

290
sofia_agent.py Executable file
View File

@@ -0,0 +1,290 @@
#!/usr/bin/env python3
"""
Sofia Agent - Local Runner
Chief AI Engineer & R&D Orchestrator
Працює локально на MacBook з підтримкою:
- Grok API (xAI) - якщо є API ключ
- Ollama (локальна модель) - fallback
- Голосовий режим (опціонально)
"""
import asyncio
import os
import sys
from typing import Optional
from dotenv import load_dotenv
# Завантажити змінні оточення
load_dotenv()
# Спробувати імпортувати необхідні бібліотеки
try:
from openai import OpenAI
import httpx
except ImportError as e:
print(f"❌ Помилка імпорту: {e}")
print("Встановіть залежності: pip3 install openai httpx")
sys.exit(1)
# ============================================================================
# Конфігурація
# ============================================================================
SOFIA_SYSTEM_PROMPT = """Ти - Sofia, Chief AI Engineer & R&D Orchestrator в екосистемі DAARION.city.
Твоя роль:
- Керування дослідженнями та експериментами з AI/ML
- Координація R&D лабораторії
- Технічне лідерство в AI проектах
- Оркестрація команди дослідницьких агентів
Характеристики:
- Глибока технічна експертиза в AI/ML
- Стратегічне мислення
- Інноваційний підхід до вирішення проблем
- Лідерські навички
Стиль спілкування:
- Професійний, але дружній
- Чіткий та технічно точний
- Готова пояснити складні концепції
- Підтримуюча та надихаюча
Відповідай українською мовою, якщо не вказано інше.
"""
# xAI/Grok конфігурація
XAI_API_KEY = os.getenv("XAI_API_KEY", "")
XAI_BASE_URL = os.getenv("XAI_BASE_URL", "https://api.x.ai/v1")
XAI_MODEL = os.getenv("XAI_MODEL", "grok-beta")
# Ollama конфігурація (fallback)
OLLAMA_BASE_URL = os.getenv("OLLAMA_BASE_URL", "http://localhost:11434")
OLLAMA_MODEL = os.getenv("OLLAMA_MODEL", "qwen2.5-coder:32b")
# Голосовий режим
VOICE_ENABLED = os.getenv("ENABLE_VOICE_MODE", "false").lower() == "true"
STT_SERVICE_URL = os.getenv("STT_SERVICE_URL", "")
TTS_SERVICE_URL = os.getenv("TTS_SERVICE_URL", "")
# ============================================================================
# Sofia Agent Class
# ============================================================================
class SofiaAgent:
"""Sofia Agent - AI Research Orchestrator"""
def __init__(self):
self.use_grok = bool(XAI_API_KEY)
self.conversation_history = []
print("🤖 Ініціалізація Sofia Agent...")
print(f" Режим: {'Grok API (xAI)' if self.use_grok else 'Ollama (локальна модель)'}")
if self.use_grok:
print(f" Модель: {XAI_MODEL}")
self.client = OpenAI(api_key=XAI_API_KEY, base_url=XAI_BASE_URL)
else:
print(f" Модель: {OLLAMA_MODEL}")
print(f" URL: {OLLAMA_BASE_URL}")
if VOICE_ENABLED:
print(f" 🎤 Голосовий режим: Увімкнено")
print("✅ Sofia готова до роботи!\n")
async def chat_with_grok(self, message: str) -> str:
"""Чат через Grok API"""
try:
messages = [
{"role": "system", "content": SOFIA_SYSTEM_PROMPT}
]
# Додати історію розмови (останні 5 повідомлень)
messages.extend(self.conversation_history[-10:])
messages.append({"role": "user", "content": message})
response = self.client.chat.completions.create(
model=XAI_MODEL,
messages=messages,
temperature=0.7,
max_tokens=2000
)
reply = response.choices[0].message.content
# Зберегти в історію
self.conversation_history.append({"role": "user", "content": message})
self.conversation_history.append({"role": "assistant", "content": reply})
# Показати статистику токенів
usage = response.usage
print(f" [Tokens: {usage.total_tokens} | Prompt: {usage.prompt_tokens} | Response: {usage.completion_tokens}]")
return reply
except Exception as e:
return f"❌ Помилка Grok API: {str(e)}"
async def chat_with_ollama(self, message: str) -> str:
"""Чат через локальний Ollama"""
try:
# Підготувати промпт з історією
full_prompt = SOFIA_SYSTEM_PROMPT + "\n\n"
# Додати останні повідомлення з історії
for msg in self.conversation_history[-6:]:
role = "Користувач" if msg["role"] == "user" else "Sofia"
full_prompt += f"{role}: {msg['content']}\n"
full_prompt += f"Користувач: {message}\nSofia:"
# Виклик Ollama API
async with httpx.AsyncClient(timeout=120.0) as client:
response = await client.post(
f"{OLLAMA_BASE_URL}/api/generate",
json={
"model": OLLAMA_MODEL,
"prompt": full_prompt,
"stream": False,
"options": {
"temperature": 0.7,
"num_predict": 1000
}
}
)
response.raise_for_status()
result = response.json()
reply = result.get("response", "").strip()
# Зберегти в історію
self.conversation_history.append({"role": "user", "content": message})
self.conversation_history.append({"role": "assistant", "content": reply})
# Показати статистику
eval_count = result.get("eval_count", 0)
print(f" [Tokens: ~{eval_count}]")
return reply
except httpx.ConnectError:
return "Не можу підключитися до Ollama. Перевірте, що Ollama запущено: `ollama serve`"
except Exception as e:
return f"❌ Помилка Ollama: {str(e)}"
async def chat(self, message: str) -> str:
"""Основний метод чату"""
if self.use_grok:
return await self.chat_with_grok(message)
else:
return await self.chat_with_ollama(message)
def clear_history(self):
"""Очистити історію розмови"""
self.conversation_history = []
print("🗑️ Історія розмови очищена")
# ============================================================================
# CLI Interface
# ============================================================================
async def interactive_mode():
"""Інтерактивний режим чату з Sofia"""
sofia = SofiaAgent()
print("=" * 60)
print("💬 Sofia Agent - Interactive Chat")
print("=" * 60)
print("\nКоманди:")
print(" /help - показати довідку")
print(" /clear - очистити історію розмови")
print(" /history - показати історію")
print(" /exit - вийти")
print("\nПочинайте спілкування!\n")
while True:
try:
# Отримати введення користувача
user_input = input("\n🧑 Ви: ").strip()
if not user_input:
continue
# Обробка команд
if user_input.startswith("/"):
if user_input == "/exit" or user_input == "/quit":
print("\n👋 До побачення!")
break
elif user_input == "/help":
print("\n📖 Команди:")
print(" /help - показати цю довідку")
print(" /clear - очистити історію розмови")
print(" /history - показати історію розмови")
print(" /exit - вийти з чату")
continue
elif user_input == "/clear":
sofia.clear_history()
continue
elif user_input == "/history":
if sofia.conversation_history:
print("\n📜 Історія розмови:")
for i, msg in enumerate(sofia.conversation_history, 1):
role = "🧑 Ви" if msg["role"] == "user" else "🤖 Sofia"
content = msg["content"][:100] + "..." if len(msg["content"]) > 100 else msg["content"]
print(f" {i}. {role}: {content}")
else:
print("📭 Історія порожня")
continue
else:
print(f"❌ Невідома команда: {user_input}")
continue
# Відправити повідомлення Sofia
print("\n🤖 Sofia: ", end="", flush=True)
response = await sofia.chat(user_input)
print(response)
except KeyboardInterrupt:
print("\n\n👋 До побачення!")
break
except Exception as e:
print(f"\n❌ Помилка: {e}")
async def single_message_mode(message: str):
"""Режим одного повідомлення"""
sofia = SofiaAgent()
response = await sofia.chat(message)
print(f"\n🤖 Sofia:\n{response}\n")
# ============================================================================
# Main
# ============================================================================
async def main():
"""Головна функція"""
# Перевірити аргументи командного рядка
if len(sys.argv) > 1:
# Режим одного повідомлення
message = " ".join(sys.argv[1:])
await single_message_mode(message)
else:
# Інтерактивний режим
await interactive_mode()
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
print("\n👋 Програму зупинено")
except Exception as e:
print(f"❌ Критична помилка: {e}")
sys.exit(1)