File size: 7,298 Bytes
918bdb4
3b9a6b5
 
918bdb4
3b9a6b5
918bdb4
 
 
3b9a6b5
 
 
 
 
 
 
b9b1ca9
 
 
 
 
 
 
3b9a6b5
2004c79
3b9a6b5
 
 
 
 
 
 
 
 
 
 
 
 
 
918bdb4
 
 
 
 
 
 
 
 
 
 
 
3b9a6b5
 
 
0965204
 
 
 
 
 
 
 
3b9a6b5
 
 
918bdb4
3b9a6b5
918bdb4
 
3b9a6b5
918bdb4
3b9a6b5
 
918bdb4
b9b1ca9
3b9a6b5
b9b1ca9
 
 
 
 
3b9a6b5
b9b1ca9
 
 
 
 
 
3b9a6b5
b9b1ca9
918bdb4
b9b1ca9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
918bdb4
 
b9b1ca9
 
 
918bdb4
b9b1ca9
918bdb4
b9b1ca9
 
 
3b9a6b5
b9b1ca9
918bdb4
b9b1ca9
 
 
 
 
3b9a6b5
b9b1ca9
 
 
3b9a6b5
b9b1ca9
3b9a6b5
b9b1ca9
 
 
 
 
 
918bdb4
b9b1ca9
 
918bdb4
3b9a6b5
b9b1ca9
 
 
 
 
3b9a6b5
b9b1ca9
 
 
918bdb4
b9b1ca9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3b9a6b5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
import os, argparse
import gradio as gr

from utils.logging_config import setup_logging, get_logger

# Initialize logging early - will be reconfigured based on debug mode
setup_logging()
logger = get_logger(__name__)

from utils.load_secrets import load_secrets

if not os.getenv("NEBIUS_API_KEY") or not os.getenv("NEBIUS_MODEL"):
    load_secrets("tests/secrets/creds.py")


# from handlers.web_backend import (
#     load_data,
#     show_solved,
#     start_timer,
#     auto_poll,
#     show_mock_project_content,
# )

from handlers.mcp_backend import process_message_and_attached_file

from services import MockProjectService

# Store last chat message and file in global variables (for demo purposes)
last_message_body = None
last_attached_file = None


# =========================
#           APP
# =========================


def app(debug: bool = False):
    """Main application function with optional debug mode"""

    # Configure logging based on debug mode
    if debug:
        os.environ["YUGA_DEBUG"] = "true"
        setup_logging("DEBUG")
        logger.info("Application started in DEBUG mode")
    else:
        os.environ["YUGA_DEBUG"] = "false"
        setup_logging("INFO")
        logger.info("Application started in normal mode")

    with gr.Blocks() as demo:
        gr.Markdown(
            """
            # 🐍 Yuga Planner

            **Yuga Planner** is a neuro-symbolic system that combines AI agents with constraint optimization
            for intelligent scheduling.

            ## πŸ”Œ **Using as MCP Tool**

            You can use Yuga Planner as an MCP server to integrate scheduling into your AI workflows.
            """
        )

        _draw_info_page(debug)

        # Register the MCP tool as an API endpoint
        gr.api(process_message_and_attached_file)

    return demo


def _draw_info_page(debug: bool = False):
    with gr.Tab("πŸ“‹ Information"):

        def get_server_url():
            try:
                return gr.get_state().server_url + "/gradio_api/mcp/sse"
            except:
                return "http://localhost:7860/gradio_api/mcp/sse"

        gr.Textbox(
            value=get_server_url(),
            label="🌐 MCP Server Endpoint",
            interactive=False,
            max_lines=1,
        )

        with gr.Accordion("πŸ“ MCP Setup Instructions", open=True):
            gr.Markdown(
                """
                ### 1. **Cursor Setup Instructions (should work from any MCP client!)**

                **For Cursor AI Editor:**
                1. Create or edit your MCP configuration file: `~/.cursor/mcp.json`
                2. Add the yuga-planner server configuration:
                ```json
                {
                  "mcpServers": {
                    "yuga-planner": {
                      "url": -> "Insert the above endpoint URL here"
                    }
                  }
                }
                ```
                3. If you already have other MCP servers, add `yuga-planner` to the existing `mcpServers` object
                4. Restart Cursor to load the new configuration
                5. The tool will be available in your chat

                ### 2. **Usage Example**
                """
            )

            gr.Textbox(
                value="""use yuga-planner mcp tool
Task Description: Create a new EC2 instance on AWS

[Attach your calendar.ics file to provide existing commitments]

Tool Response: Optimized schedule created - EC2 setup task assigned to
available time slots around your existing meetings
[Returns JSON response with schedule data]

User: show all fields as a table, ordered by start date

[Displays formatted schedule table with all tasks and calendar events]""",
                label="πŸ’¬ Cursor Chat Usage Example",
                interactive=False,
                lines=10,
            )

            gr.Markdown(
                """
                ### 3. **What it does**

                **Personal Task Scheduling with Calendar Integration:**

                1. πŸ“… **Parses your calendar** (.ics file) for existing commitments
                2. πŸ€– **AI breaks down your task** into actionable subtasks using LLamaIndex + Nebius AI
                3. ⚑ **Constraint-based optimization** finds optimal time slots around your existing schedule
                4. πŸ“‹ **Returns complete solved schedule** integrated with your personal calendar events
                5. πŸ•˜ **Respects business hours** (9:00-18:00) and excludes weekends automatically
                6. πŸ“Š **JSON response format** - Ask to "show all fields as a table, ordered by start date" for readable formatting

                **Designed for**: Personal productivity and task planning around existing appointments in Cursor.
                """
            )

        if debug:
            with gr.Tab("πŸ› Debug Info"):
                gr.Markdown(
                    """
                    # πŸ› Debug Information

                    **Debug Mode Enabled** - Additional system information and controls available.
                    """
                )

                with gr.Accordion("πŸ”§ **Environment Details**", open=True):
                    import os

                    env_info = f"""
                    **🐍 Python Environment**
                    - Debug Mode: {debug}
                    - YUGA_DEBUG: {os.getenv('YUGA_DEBUG', 'Not Set')}
                    - Nebius API Key: {'βœ… Set' if os.getenv('NEBIUS_API_KEY') else '❌ Not Set'}
                    - Nebius Model: {os.getenv('NEBIUS_MODEL', 'Not Set')}

                    **🌐 Server Information**
                    - MCP Endpoint: {get_server_url()}
                    - Current Working Directory: {os.getcwd()}
                    """
                    gr.Markdown(env_info)

                with gr.Accordion("πŸ“Š **System Status**", open=False):
                    gr.Markdown(
                        """
                        **πŸ”„ Service Status**
                        - DataService: βœ… Active
                        - ScheduleService: βœ… Active
                        - StateService: βœ… Active
                        - LoggingService: βœ… Active
                        - MockProjectService: βœ… Active

                        **πŸ”Œ Integration Status**
                        - MCP Server: βœ… Enabled
                        - Gradio API: βœ… Active
                        - Real-time Logs: βœ… Streaming
                        """
                    )


if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="Yuga Planner - Team Scheduling Application"
    )
    parser.add_argument(
        "--debug",
        action="store_true",
        help="Enable debug mode with additional UI controls and logging",
    )
    parser.add_argument(
        "--server-name",
        default="0.0.0.0",
        help="Server name/IP to bind to (default: 0.0.0.0)",
    )
    parser.add_argument(
        "--server-port",
        type=int,
        default=7860,
        help="Server port to bind to (default: 7860)",
    )

    args = parser.parse_args()

    app(debug=args.debug).launch(
        server_name=args.server_name, server_port=args.server_port, mcp_server=True
    )