File size: 5,322 Bytes
d0c87f7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import gradio as gr
import modal
import json

# --- Configuration ---
MODAL_APP_NAME = "sitegeist-ai-app"

def analyze_web_content(urls_json: str, deep_analysis: bool = False, analysis_prompt: str = "Summarize the content and identify key themes."):
    """
    MCP Tool: Analyzes web content from one or more URLs.
    Performs deep analysis with marketing metrics if a single URL is provided and deep_analysis is True.
    Otherwise, performs a swarm analysis for multiple URLs or a single URL without deep_analysis.

    Args:
        urls_json (str): A JSON string representing a list of URLs. e.g., '["http://example.com", "http://another.com"]'
        deep_analysis (bool): If True and only one URL is provided, performs an in-depth analysis.
        analysis_prompt (str): The specific analysis to perform on the content.
    """
    print(f"Received request: deep_analysis={deep_analysis}, prompt='{analysis_prompt}', urls_json='{urls_json}'")
    try:
        urls = json.loads(urls_json)
        if not isinstance(urls, list) or not all(isinstance(url, str) for url in urls):
            raise ValueError("Input must be a JSON string of a list of URLs.")
        if not urls:
            return json.dumps({"status": "error", "message": "URL list cannot be empty."})
    except json.JSONDecodeError:
        return json.dumps({"status": "error", "message": "Invalid JSON format for URLs."})
    except ValueError as ve:
        return json.dumps({"status": "error", "message": str(ve)})

    result = None
    try:
        if len(urls) == 1 and deep_analysis:
            print(f"Calling Modal: deep_analyze_url for {urls[0]}")
            # Lookup the Modal function
            modal_deep_analyze = modal.Function.lookup(MODAL_APP_NAME, "deep_analyze_url")
            if modal_deep_analyze is None:
                 return json.dumps({"status": "error", "message": f"Could not find Modal function 'deep_analyze_url' in app '{MODAL_APP_NAME}'."})
            # Call the Modal function remotely
            result = modal_deep_analyze.remote(url=urls[0])
        else:
            print(f"Calling Modal: swarm_analyze_urls for {len(urls)} URLs")
            # Lookup the Modal function
            modal_swarm_analyze = modal.Function.lookup(MODAL_APP_NAME, "swarm_analyze_urls")
            if modal_swarm_analyze is None:
                return json.dumps({"status": "error", "message": f"Could not find Modal function 'swarm_analyze_urls' in app '{MODAL_APP_NAME}'."})
            # Call the Modal function remotely
            result = modal_swarm_analyze.remote(urls=urls, analysis_prompt=analysis_prompt)
        
        return json.dumps(result, indent=2) # Return the result from Modal as a JSON string

    except modal.exception.NotFoundError as e:
         print(f"Modal function not found: {e}")
         return json.dumps({"status": "error", "message": f"Modal function lookup failed. Ensure '{MODAL_APP_NAME}' is deployed and functions are correctly named. Details: {e}"})
    except Exception as e:
        print(f"An unexpected error occurred: {e}")
        return json.dumps({"status": "error", "message": f"An unexpected error occurred: {str(e)}"})

# --- Gradio Interface for Testing (if not using MCP directly) ---
# This allows you to test the analyze_web_content function via a web UI.
# You would typically expose `analyze_web_content` directly as an MCP tool.
with gr.Blocks() as demo:
    gr.Markdown("# Sitegeist AI: Marketing & Content Intelligence Engine")
    gr.Markdown(
        "Enter URLs as a JSON list (e.g., `[\"http://url1.com\", \"http://url2.com\"]`). "
        "The Modal backend calls are mocked and will return predefined data."
    )
    with gr.Row():
        urls_input = gr.Textbox(label="URLs (JSON list)", placeholder='["https://example.com"]')
        deep_analysis_checkbox = gr.Checkbox(label="Perform Deep Analysis (for single URL)", value=False)
    analysis_prompt_input = gr.Textbox(label="Analysis Prompt", value="Summarize the content.")
    submit_button = gr.Button("Analyze Content")
    output_json = gr.JSON(label="Analysis Result")

    submit_button.click(
        analyze_web_content,
        inputs=[urls_input, deep_analysis_checkbox, analysis_prompt_input],
        outputs=output_json
    )

if __name__ == "__main__":
    # To run this Gradio app: python app.py
    # Ensure your Modal token is configured (`modal token set`)
    # And the Modal app (`modal_app.py`) is deployed (`modal deploy modal_app.py`)
    # or runnable locally if you are testing `modal run modal_app.py` in another terminal.
    
    # For the Gradio app to successfully call `modal.Function.lookup()`,
    # it generally expects the Modal app to be deployed, or you need to be
    # running within a `modal.stub.run()` context if calling local stubs
    # from another Modal process, which is more advanced.
    # The simplest way for this sketch is to deploy `modal_app.py` first.
    print("Attempting to launch Gradio demo...")
    print("REMINDER: For Gradio to connect to Modal functions,")
    print(f"1. Deploy 'modal_app.py' using 'modal deploy modal_app.py'.")
    print(f"2. Ensure your Modal token is set up.")
    print(f"3. The MODAL_APP_NAME ('{MODAL_APP_NAME}') in app.py must match the app name in modal_app.py.")

    demo.launch(mcp_server=True)