vachaspathi commited on
Commit
b390399
·
verified ·
1 Parent(s): 27926a7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +101 -51
app.py CHANGED
@@ -1,58 +1,108 @@
1
- import gradio as gr
 
 
2
  import os
3
- import google.generativeai as genai
4
- from zoho_client_mcp import mcp # Import the MCP instance from our tools file
5
-
6
- # --- 1. Gemini Client Initialization ---
7
- # We configure the Gemini client directly in the app before launching the MCP.
8
- # This assumes os.environ['GOOGLE_API_KEY'] is set in config.py.
9
- def configure_gemini():
10
- """Initializes the Gemini client using the API key from environment variables."""
11
- try:
12
- genai.configure(api_key=os.environ.get('GOOGLE_API_KEY'))
13
- print("Gemini API configured successfully for conversational use.")
14
- except Exception as e:
15
- print(f"Error configuring Gemini API: {e}")
16
-
17
- # --- 2. Gradio Chat Interface Definition ---
18
- # This defines the web UI required for conversation and file uploads [3, 13, 16, 17].
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  def chat_interface():
20
- # Gradio's gr.ChatInterface is used to build a standard chat UI.
21
- # The submission logic is handled automatically by FastMCP when mcp_server=True is used.
22
-
23
- # The file input is added directly to allow attachments (images/PDFs) [13, 18].
24
- # Files uploaded here will be available to the 'process_document' tool [18].
25
- file_component = gr.File(label="Upload Image or PDF Document", type="filepath")
26
-
27
- # The gr.ChatInterface sets up the UI structure for the conversation.
28
- iface = gr.ChatInterface(
29
- # The function passed here is typically the conversational engine.
30
- # When mcp_server=True, the MCP framework handles the routing.
31
- fn=lambda msg, history: f"Thinking...",
32
- chatbot=gr.Chatbot(height=400),
33
- textbox=gr.Textbox(placeholder="Ask me to create a contact, search records, or upload a document...", scale=7),
34
- title="Zoho CRM Agent (Gemini + FastMCP)",
35
- submit_btn="Send Command",
36
- # We attach the file component to the interface so users can upload [3, 16].
37
- additional_inputs=[file_component]
38
  )
39
- return iface
40
-
41
- # --- 3. Server Launch ---
42
 
43
  if __name__ == "__main__":
44
- # Ensure Gemini is ready [11, 19].
45
- configure_gemini()
46
-
47
- # Get the defined Gradio UI
48
  demo = chat_interface()
49
-
50
- # Launch the Gradio UI, instructing it to also start the FastMCP server [4].
51
- # Gradio automatically connects the UI to the running 'mcp' instance when mcp_server=True [3].
52
- print("Starting Gradio Web UI and FastMCP Server...")
53
  demo.launch(
54
- server_name="0.0.0.0",
55
- server_port=7860,
56
- mcp_server=True, # Crucial: Starts the FastMCP server instance 'mcp' [4].
57
- mcp=mcp
58
- )
 
1
+ from mcp.server.fastmcp import FastMCP
2
+ from typing import Optional
3
+ import requests
4
  import os
5
+ import gradio as gr
6
+
7
+ from config import CLIENT_ID, CLIENT_SECRET, REFRESH_TOKEN, API_BASE
8
+
9
+ # --- Initialize the FastMCP Server ---
10
+ mcp = FastMCP("ZohoCRMAgent")
11
+
12
+ # --- Token Refresh Utility ---
13
+ def _get_valid_token_headers() -> dict:
14
+ """Internal function to ensure a valid Zoho access token is available.
15
+ This uses the refresh token flow to retrieve a fresh access token."""
16
+ token_url = "https://accounts.zoho.in/oauth/v2/token"
17
+ params = {
18
+ "refresh_token": REFRESH_TOKEN,
19
+ "client_id": CLIENT_ID,
20
+ "client_secret": CLIENT_SECRET,
21
+ "grant_type": "refresh_token"
22
+ }
23
+ response = requests.post(token_url, params=params)
24
+ if response.status_code == 200:
25
+ access_token = response.json().get("access_token")
26
+ return {"Authorization": f"Zoho-oauthtoken {access_token}"}
27
+ else:
28
+ raise Exception(f"Failed to refresh token: {response.text}")
29
+
30
+ # --- MCP Tools for Zoho CRM and Zoho Books Operations ---
31
+
32
+ @mcp.tool()
33
+ def authenticate_zoho() -> str:
34
+ """Refreshes and confirms Zoho CRM access token availability."""
35
+ _ = _get_valid_token_headers()
36
+ return "Zoho CRM access token successfully refreshed."
37
+
38
+ @mcp.tool()
39
+ def create_record(module_name: str, record_data: dict) -> str:
40
+ """Creates a new record in the specified Zoho CRM module."""
41
+ headers = _get_valid_token_headers()
42
+ response = requests.post(f"{API_BASE}/{module_name}", headers=headers, json={"data": [record_data]})
43
+ if response.status_code in [200, 201]:
44
+ return f"Record created successfully in {module_name}."
45
+ return f"Error creating record: {response.text}"
46
+
47
+ @mcp.tool()
48
+ def get_records(module_name: str, page: int = 1, per_page: int = 200) -> list:
49
+ """Fetches records from a specified Zoho CRM module."""
50
+ headers = _get_valid_token_headers()
51
+ params = {"page": page, "per_page": per_page}
52
+ response = requests.get(f"{API_BASE}/{module_name}", headers=headers, params=params)
53
+ if response.status_code == 200:
54
+ return response.json().get("data", [])
55
+ return [f"Error retrieving records: {response.text}"]
56
+
57
+ @mcp.tool()
58
+ def update_record(module_name: str, record_id: str, data: dict) -> str:
59
+ """Updates a record in a Zoho CRM module."""
60
+ headers = _get_valid_token_headers()
61
+ response = requests.put(f"{API_BASE}/{module_name}/{record_id}", headers=headers, json={"data": [data]})
62
+ if response.status_code == 200:
63
+ return f"Record {record_id} in {module_name} updated successfully."
64
+ return f"Error updating record: {response.text}"
65
+
66
+ @mcp.tool()
67
+ def delete_record(module_name: str, record_id: str) -> str:
68
+ """Deletes a record from the specified Zoho CRM module."""
69
+ headers = _get_valid_token_headers()
70
+ response = requests.delete(f"{API_BASE}/{module_name}/{record_id}", headers=headers)
71
+ if response.status_code == 200:
72
+ return f"Record {record_id} in {module_name} deleted."
73
+ return f"Error deleting record: {response.text}"
74
+
75
+ @mcp.tool()
76
+ def create_invoice(data: dict) -> str:
77
+ """Creates an invoice in Zoho Books."""
78
+ headers = _get_valid_token_headers()
79
+ response = requests.post(f"{API_BASE}/invoices", headers=headers, json={"data": [data]})
80
+ if response.status_code in [200, 201]:
81
+ return "Invoice created successfully."
82
+ return f"Error creating invoice: {response.text}"
83
+
84
+ @mcp.tool()
85
+ def process_document(file_path: str, target_module: Optional[str] = "Contacts") -> dict:
86
+ """Extracts data from uploaded file (PDF/image) and returns structured info."""
87
+ # Placeholder for OCR + Gemini parsing logic
88
+ # raw_text = perform_ocr(file_path)
89
+ # structured_data = gemini_parse_json(raw_text)
90
+ return {
91
+ "status": "success",
92
+ "file": os.path.basename(file_path),
93
+ "extracted_data": f"Simulated structured data from {target_module} document."
94
+ }
95
+
96
+ # --- Launch UI and MCP Server ---
97
  def chat_interface():
98
+ return gr.ChatInterface(
99
+ lambda msg: f"Received: {msg}",
100
+ textbox=gr.Textbox(placeholder="Ask me to create contacts, deals, or upload documents."),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  )
 
 
 
102
 
103
  if __name__ == "__main__":
 
 
 
 
104
  demo = chat_interface()
 
 
 
 
105
  demo.launch(
106
+ server_name="0.0.0.0",
107
+ server_port=7860
108
+ )