File size: 3,735 Bytes
c216959
0491e54
 
c216959
0491e54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7cf341b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0491e54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ac59ee6
 
02679c3
 
 
ac59ee6
 
02679c3
ac59ee6
02679c3
ac59ee6
02679c3
 
 
 
 
ac59ee6
 
 
02679c3
 
 
 
 
 
ac59ee6
0491e54
 
c216959
 
0491e54
 
 
02679c3
 
 
361a507
02679c3
 
361a507
02679c3
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
"""
FocusFlow: AI Accountability Agent with Gradio 5 Interface.
Configurable via environment variables for HuggingFace Spaces or local use.
"""
import gradio as gr
import os
from dotenv import load_dotenv
from storage import TaskManager
from monitor import FileMonitor
from metrics import MetricsTracker
from voice import voice_generator
from linear_client import LinearClient
from core.pomodoro import PomodoroTimer
from core.focus_check import FocusMonitor
from ui.handlers import UIHandlers
from ui.layout import create_app

# Load environment variables
load_dotenv()

# Debug: Print Configuration
print("-" * 40)
print("πŸ”§ FOCUSFLOW CONFIGURATION")
print(f"   LAUNCH_MODE:      {os.getenv('LAUNCH_MODE', 'demo')}")
print(f"   AI_PROVIDER:      {os.getenv('AI_PROVIDER', 'openai')}")
print(f"   MONITOR_INTERVAL: {os.getenv('MONITOR_INTERVAL', '30')}")
print(f"   ENABLE_MCP:       {os.getenv('ENABLE_MCP', 'true')}")
print(f"   HF_SPACE:         {'Yes' if os.getenv('SPACE_ID') or os.getenv('huggingface_space_id') else 'No'}")

# Masked Keys for safety
for key in ["OPENAI_API_KEY", "ANTHROPIC_API_KEY", "GEMINI_API_KEY", "LINEAR_API_KEY", 
            "DEMO_OPENAI_API_KEY", "DEMO_ANTHROPIC_API_KEY", "DEMO_GEMINI_API_KEY"]:
    val = os.getenv(key)
    status = f"Set ({val[:4]}...)" if val else "Not Set"
    print(f"   {key:<22}: {status}")
print("-" * 40)

# Import MCP tools to register them with Gradio
try:
    import mcp_tools
    MCP_AVAILABLE = True
except Exception as e:
    print(f"⚠️ MCP tools not available: {e}")
    MCP_AVAILABLE = False

# Configuration from environment
LAUNCH_MODE = os.getenv("LAUNCH_MODE", "demo").lower()  # 'demo' or 'local'
AI_PROVIDER = os.getenv("AI_PROVIDER", "openai").lower()  # 'openai', 'anthropic', or 'vllm'
MONITOR_INTERVAL = int(os.getenv("MONITOR_INTERVAL", "30"))  # seconds

# Initialize Core Components
task_manager = TaskManager()
file_monitor = FileMonitor()
metrics_tracker = MetricsTracker()
linear_client = LinearClient()

# Initialize Logic Modules
focus_monitor = FocusMonitor(task_manager, file_monitor, metrics_tracker, voice_generator)
focus_monitor.set_launch_mode(LAUNCH_MODE)

pomodoro_timer = PomodoroTimer()

# Initialize UI Handlers
ui_handlers = UIHandlers(task_manager, file_monitor, metrics_tracker, focus_monitor, linear_client)

# Register cleanup handler
import atexit
import signal
import sys

def cleanup():
    """Cleanup resources on shutdown."""
    print("🧹 Cleaning up resources...")
    if file_monitor.is_running():
        print("   Stopping file monitor...")
        file_monitor.stop()
    try:
        print("   Closing Gradio app...")
        app.close()
    except Exception as e:
        print(f"   Error closing app: {e}")

atexit.register(cleanup)

def handle_sigterm(*args):
    """Handle SIGTERM signal from K8s/Docker."""
    print("πŸ›‘ Received SIGTERM, initiating shutdown...")
    sys.exit(0)

signal.signal(signal.SIGTERM, handle_sigterm)

# Create App
app = create_app(ui_handlers, pomodoro_timer, LAUNCH_MODE, AI_PROVIDER, MONITOR_INTERVAL)

if __name__ == "__main__":
    # Enable MCP server if available
    mcp_enabled = os.getenv("ENABLE_MCP", "true").lower() == "true"

    try:
        if MCP_AVAILABLE and mcp_enabled:
            print("πŸ”— MCP Server enabled! Connect via Claude Desktop or other MCP clients.")
            app.launch(server_name="0.0.0.0", server_port=7860, share=False, mcp_server=True)
        else:
            print("πŸ“± Running without MCP integration")
            app.launch(server_name="0.0.0.0", server_port=7860, share=False)
    except KeyboardInterrupt:
        print("πŸ‘‹ FocusFlow stopped by user")
    except Exception as e:
        print(f"❌ Unexpected error: {e}")