File size: 6,194 Bytes
f3edde7
 
5d0bd9d
f3edde7
8545511
8af2bcc
 
 
08e7b43
8af2bcc
 
 
 
08e7b43
8af2bcc
 
 
5d0bd9d
f3edde7
 
5d0bd9d
f3edde7
 
8af2bcc
 
 
 
 
 
 
5d0bd9d
f3edde7
08e7b43
 
8af2bcc
5d0bd9d
f3edde7
 
 
 
 
 
 
 
8af2bcc
 
 
 
 
 
 
 
 
 
 
8545511
8af2bcc
8545511
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f3edde7
8af2bcc
 
 
 
 
 
 
 
 
 
 
 
 
8545511
 
 
 
 
 
8af2bcc
 
8545511
 
 
 
 
 
 
 
d5e1565
 
 
 
 
 
 
8545511
 
f3edde7
8545511
 
 
 
 
5d0bd9d
8545511
 
 
 
 
 
974d0bb
f3edde7
d5e1565
 
 
 
 
 
 
 
f3edde7
8af2bcc
 
 
f3edde7
 
9f70d46
f3edde7
 
8af2bcc
 
 
 
 
 
f3edde7
 
8af2bcc
f3edde7
 
8545511
8af2bcc
 
 
f3edde7
8af2bcc
f3edde7
8545511
8af2bcc
 
f3edde7
5d0bd9d
f3edde7
 
 
 
 
 
5d0bd9d
8af2bcc
 
 
8545511
 
 
 
 
 
 
8af2bcc
8545511
8af2bcc
 
 
 
 
 
 
 
 
 
 
 
 
8545511
5d0bd9d
 
 
8af2bcc
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
import os
import warnings

from dotenv import load_dotenv
from huggingface_hub import get_token
from mcp import StdioServerParameters
from smolagents import (
    CodeAgent,
    #    DuckDuckGoSearchTool,
    FinalAnswerTool,
    InferenceClientModel,
    MCPClient,
    Tool,
    #    VisitWebpageTool,
)

from my_ui import CustomGradioUI

# Load environment variables from .env file
load_dotenv()

# Configuration
HF_MODEL_ID = os.getenv("HF_MODEL_ID", "Qwen/Qwen2.5-Coder-32B-Instruct")
# GROQ_API_KEY = os.getenv("GROQ_API_KEY", "")
TAVILY_API_KEY = os.getenv("TAVILY_API_KEY", "")

# Suppress OAuth warning when running locally (OAuth only works on HF Spaces)
warnings.filterwarnings(
    "ignore", message=".*Gradio does not support OAuth features outside of a Space environment.*"
)

# smolagents Toolbox
# web_search = DuckDuckGoSearchTool(max_results=5, rate_limit=2.0)
# visit_webpage = VisitWebpageTool()
final_answer = FinalAnswerTool()

# Import tool from Hub
image_generation_tool = Tool.from_space(
    space_id="black-forest-labs/FLUX.1-schnell",
    name="image_generator",
    description="Generates an image following your prompt. Returns a PIL Image.",
    api_name="/infer",
)

# image_analysis_tool = Tool.from_space(
#     space_id="fffiloni/Sa2VA-simple-demo",
#     name="image_analyzer",
#     description=(
#         "Perform image-based visual question answering and segmentation. "
#         "This function takes an image and a text prompt (instruction) as input, "
#         "processes the image with a multimodal model, and returns a textual answer."
#     ),
#     api_name="/image_vision",
# )


# MCP Servers
def get_upload_files_to_gradio_server():
    """Get the upload files to Gradio MCP server configuration."""
    return StdioServerParameters(
        command="uvx",  # Using uvx ensures dependencies are available
        args=[
            "--from",
            "gradio[mcp]",
            "gradio",
            "upload-mcp",
            "https://fffiloni-sa2va-simple-demo.hf.space/",
            "./data",
        ],
        env={"UV_PYTHON": "3.12", **os.environ},
    )


# groq_compount_beta = StdioServerParameters(
#     command="uvx",  # Using uvx ensures dependencies are available
#     args=[
#         "--from",
#         "git+https://github.com/groq/groq-mcp-server",
#         "groq-mcp"
#     ],
#     env={"GROQ_API_KEY": GROQ_API_KEY,
#          "BASE_OUTPUT_PATH": "./data"  # Optional: Where to save generated files
#     },
# )


def get_image_analysis_mcp():
    """Get the image analysis MCP configuration."""
    return {
        "url": "https://fffiloni-sa2va-simple-demo.hf.space/gradio_api/mcp/",
        "transport": "streamable-http",
    }


def get_tavily_search_mcp(api_key):
    """Get the Tavily search MCP configuration with the provided API key."""
    return {
        "url": f"https://mcp.tavily.com/mcp/?tavilyApiKey={api_key}",
        "transport": "streamable-http",
    }


def create_agent(tavily_api_key=None, oauth_token=None):
    """Create an agent with the specified Tavily API key and OAuth token.

    Args:
        tavily_api_key: Optional Tavily API key for web search
        oauth_token: OAuth token from Gradio (gr.OAuthToken | None)
    """
    # Use provided API key or fall back to environment variable
    api_key = tavily_api_key or TAVILY_API_KEY

    # Build list of MCP servers - only include Tavily if API key is provided
    mcp_servers = [
        get_upload_files_to_gradio_server(),
        get_image_analysis_mcp(),
    ]

    # Only add Tavily search if we have an API key
    if api_key:
        mcp_servers.append(get_tavily_search_mcp(api_key))

    # Create MCP client with the appropriate servers
    mcp_client = MCPClient(mcp_servers, structured_output=False)

    # Create model with user-specified parameters
    # Priority: OAuth token from Gradio > HF_TOKEN env var > get_token() from CLI login
    if oauth_token is not None:
        # On HF Spaces, use the OAuth token provided by Gradio
        hf_token = oauth_token.token if hasattr(oauth_token, 'token') else oauth_token
    else:
        # Fallback to environment variable or CLI login
        hf_token = os.getenv("HF_TOKEN") or get_token()

    model = InferenceClientModel(
        max_tokens=2096,
        temperature=0.5,
        top_p=0.95,
        model_id=HF_MODEL_ID,
        custom_role_conversions=None,
        token=hf_token,
    )

    # Load instructions from file.  This text will be appended to the system prompt.
    with open("instructions.txt") as f:
        instructions = f.read()

    # Initialize the agent with the configured model and tools
    # Use the global mcp_client's tools instead of creating a new context
    agent = CodeAgent(
        model=model,
        additional_authorized_imports=["*"],
        tools=[
            image_generation_tool,
            *mcp_client.get_tools(),  # Use tools from the MCP client
            # web_search,
            # visit_webpage,
            final_answer,
        ],
        instructions=instructions,
        add_base_tools=False,
        max_steps=10,
        verbosity_level=1,
        planning_interval=3,
    )

    # Print the names and descriptions of the added tools
    print("--- Active Tools ---")
    for tool_name, tool in agent.tools.items():
        print(f"Tool Name: {tool_name}")
        print(f"Description: {tool.description}")
        print("-" * 20)

    return agent


# Example prompts for users
EXAMPLES = [
    "Search the web for the latest developments in quantum computing and summarize the key findings",
    "Generate an image of a futuristic city with flying cars and neon lights",
    "What are the current trends in artificial intelligence research?",
]

gradio_ui = CustomGradioUI(
    create_agent,  # Pass the factory function, not the agent instance
    file_upload_folder="./data",
    reset_agent_memory=True,
    allowed_file_types=[
        ".pdf",
        ".docx",
        ".txt",
        ".md",
        ".json",
        ".csv",
        ".png",
        ".jpeg",
        ".jpg",
    ],  # Customize this list!
    examples=EXAMPLES,
)

if __name__ == "__main__":
    gradio_ui.launch(share=False)