File size: 6,531 Bytes
d4ea4e5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
import modal
import os

# Create Modal app
app = modal.App("alita-chat-app")

# Define the image with all required dependencies
image = (
    modal.Image.debian_slim(python_version="3.11")
    .pip_install([
        "gradio>=4.0.0",
        "llama-index-core",
        "llama-index-llms-anthropic",
        "python-dotenv",
        "openai",
        "llama-index",
        "anthropic",
        "requests",
        "dataclasses",
        "beautifulsoup4",
        "duckduckgo-search",
        "llama-index-tools-duckduckgo"
    ])
    # Main script
    .add_local_file("manager_agent2.py", "/app/manager_agent2.py")
    
    # Models
    .add_local_file("models/__init__.py", "/app/models/__init__.py")
    .add_local_file("models/mcp_tool_spec.py", "/app/models/mcp_tool_spec.py")
    .add_local_file("models/mcp_execution_result.py", "/app/models/mcp_execution_result.py")
    .add_local_file("models/task_prompt.py", "/app/models/task_prompt.py")
    
    # Components
    .add_local_file("components/__init__.py", "/app/components/__init__.py")
    .add_local_file("components/mcp_brainstormer.py", "/app/components/mcp_brainstormer.py")
    .add_local_file("components/web_agent.py", "/app/components/web_agent.py")
    .add_local_file("components/script_generator.py", "/app/components/script_generator.py")
    .add_local_file("components/code_runner.py", "/app/components/code_runner.py")
    .add_local_file("components/mcp_registry.py", "/app/components/mcp_registry.py")
)

# Global variables to store initialized components
llm = None
manager_agent = None

@app.function(

    image=image,

    secrets=[modal.Secret.from_name("anthropic")],

    max_containers=10,

    timeout=300,

    min_containers=1,

    cpu=2,

    memory=2048

)
def initialize_components():
    """Initialize LLM and Manager Agent"""
    global llm, manager_agent
    
    import sys
    sys.path.append("/app")
    
    try:
        # Import required modules
        from llama_index.core import Settings
        from llama_index.llms.anthropic import Anthropic
        from models import TaskPrompt
        from manager_agent import ManagerAgent
        
        # Get API key from environment
        api_key = os.environ.get("ANTHROPIC_API_KEY")
        if not api_key:
            raise ValueError("ANTHROPIC_API_KEY not found in environment variables")
        
        # Initialize LLM
        llm = Anthropic(model="claude-3-5-sonnet-20241022", api_key=api_key)
        Settings.llm = llm
        print("Successfully initialized LlamaIndex with Anthropic model")
        
        # Initialize the ManagerAgent
        manager_agent = ManagerAgent(llm)
        print("βœ… ManagerAgent initialized successfully")
        
        return True
        
    except Exception as e:
        print(f"Error initializing components: {e}")
        import traceback
        traceback.print_exc()
        return False

@app.function(

    image=image,

    secrets=[modal.Secret.from_name("anthropic-api-key")],

    max_containers=10,

    timeout=60,

    min_containers=1,

    cpu=2,

    memory=2048

)
def process_message(message: str):
    """Process a single message through the ManagerAgent"""
    import sys
    sys.path.append("/app")
    
    try:
        from models import TaskPrompt
        from manager_agent import ManagerAgent
        from llama_index.core import Settings
        from llama_index.llms.anthropic import Anthropic
        
        # Initialize components if needed
        api_key = os.environ.get("ANTHROPIC_API_KEY")
        if not api_key:
            return "❌ ANTHROPIC_API_KEY not found in environment variables"
        
        llm = Anthropic(model="claude-3-5-sonnet-20241022", api_key=api_key)
        Settings.llm = llm
        manager_agent = ManagerAgent(llm)
        
        # Process the message
        task_prompt = TaskPrompt(text=message)
        
        response = manager_agent.run_task(task_prompt)
        
        return response
        
    except Exception as e:
        import traceback
        error_msg = f"❌ Error processing message: {str(e)}\n{traceback.format_exc()}"
        print(error_msg)
        return error_msg

# FIXED: Simple web server approach
@app.function(

    image=image,

    secrets=[modal.Secret.from_name("anthropic-api-key")],

    max_containers=10,

    timeout=300,

    min_containers=1,

    cpu=2,

    memory=2048

)
@modal.web_server(port=7860, startup_timeout=180)
def gradio_app():
    """Simple Gradio app without complex initialization"""
    import gradio as gr
    import asyncio
    
    async def chat_function(message, history):
        """Simple chat function that calls the Modal function"""
        try:
            # Call the Modal function to process the message
            response = process_message.remote(message)
            
            # Stream the response word by word for better UX
            words = response.split()
            partial_response = ""
            
            for i, word in enumerate(words):
                partial_response += word + " "
                if i % 3 == 0 or i == len(words) - 1:
                    yield partial_response.strip()
                    await asyncio.sleep(0.01)
                    
        except Exception as e:
            yield f"❌ Error: {str(e)}"
    
    # Create simple Gradio interface
    interface = gr.ChatInterface(
        fn=chat_function,
        type="messages",
        title="ALITA",
        description="ALITA: the self learning AI",
        examples=[
            "πŸ” search for information about AI",
            "πŸ› οΈ Analyse this csv file", 
            "⚑ Generate a script to automate a repetitive task",
            "🌐 Find open source resources for machine learning",
        ],
        theme="soft"
    )
    
    # Launch the interface with Modal-compatible settings
    interface.launch(
        server_name="0.0.0.0",  # Must bind to all interfaces for Modal
        server_port=7840,       # Must match the port in @modal.web_server
        share=False,            # Don't create public links
        quiet=True,             # Reduce logging noise
        show_error=True,
        prevent_thread_lock=True  # Important: prevents blocking Modal's event loop
    )

# For local development and testing
if __name__ == "__main__":
    app.deploy("alita-chat-app")