Futuresony commited on
Commit
141953b
·
verified ·
1 Parent(s): 061bddc

Upload app (16).py

Browse files
Files changed (1) hide show
  1. app (16).py +203 -0
app (16).py ADDED
@@ -0,0 +1,203 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from fastapi import FastAPI, Request, HTTPException, Form
3
+ import uvicorn
4
+ from gradio_client import Client
5
+ from fastapi.responses import Response
6
+ import json
7
+ import re # Import re for potential future use (e.g., parsing messages)
8
+ import asyncio # Import asyncio for async operations
9
+
10
+ # Connect to your hosted Gradio Space (Futuresony/Mr.Events)
11
+ # This client is used by BOTH the /chat and /webhook endpoints to interact with the core chatbot
12
+ try:
13
+ client = Client("Futuresony/Mr.Events")
14
+ print("Gradio Client for 'Futuresony/Mr.Events' initialized.")
15
+ except Exception as e:
16
+ print(f"Error initializing Gradio Client for 'Futuresony/Mr.Events': {e}")
17
+ print("Ensure the Space name is correct and it is accessible.")
18
+ client = None # Set client to None if initialization fails
19
+
20
+
21
+ # Get your secure API key for THIS FastAPI application and the hosted Space from environment
22
+ # Assuming the same API key (APP_API_KEY) is used for both.
23
+ VALID_API_KEY = os.getenv("APP_API_KEY")
24
+ # Add a print statement to confirm if the API key is loaded
25
+ print(f"APP_API_KEY loaded: {'Yes' if VALID_API_KEY else 'No'}")
26
+ if not VALID_API_KEY:
27
+ print("Warning: APP_API_KEY secret not set. API key validation and calls to hosted space may fail.")
28
+
29
+
30
+ app = FastAPI()
31
+
32
+ # --- Chat Endpoint (Existing Functionality) ---
33
+ @app.post("/chat")
34
+ async def chat(request: Request):
35
+ """
36
+ Handles chat requests via a JSON payload, validates API key,
37
+ and calls the hosted Gradio chatbot with history.
38
+ """
39
+ print("\n--- Received POST request at /chat ---")
40
+ data = await request.json()
41
+
42
+ # API Key Check for THIS FastAPI application
43
+ api_key = request.headers.get("X-API-Key") # Get API key from headers
44
+ print(f"API Key from header: {api_key[:4]}...") if api_key else "No API Key in header"
45
+ if not VALID_API_KEY or api_key != VALID_API_KEY:
46
+ print("API Key validation failed.")
47
+ raise HTTPException(status_code=403, detail="Invalid API Key")
48
+ print("API Key validation successful.")
49
+
50
+ # Get user message
51
+ user_message = data.get("message")
52
+ if not user_message:
53
+ print("Error: 'message' is required in the request body.")
54
+ raise HTTPException(status_code=400, detail="Message is required")
55
+ print(f"User message: {user_message}")
56
+
57
+
58
+ # Get chat history (assuming it's sent in the request body for stateless API)
59
+ # The chat_history is expected to be a list of lists: [[user_msg, bot_msg], ...]
60
+ # If not provided, initialize as empty list.
61
+ chat_history = data.get("chat_history", [])
62
+ # print(f"Received chat history: {chat_history}") # Be cautious logging history
63
+
64
+
65
+ # --- Call the hosted Gradio chatbot ---
66
+ if client is None:
67
+ print("Error: Gradio Client not initialized. Cannot call chatbot.")
68
+ raise HTTPException(status_code=500, detail="Chatbot service not available.")
69
+
70
+ try:
71
+ print(f"Calling hosted Gradio Space 'Futuresony/Mr.Events' /chat endpoint from /chat...")
72
+ # Note: The Gradio ChatInterface API typically expects query (current message)
73
+ # and chat_history (history *before* the current turn).
74
+ # Use the same VALID_API_KEY for the hosted space call
75
+ result = await client.predict( # Use await because client.predict can be async
76
+ query=user_message,
77
+ chat_history=chat_history, # Pass the history directly
78
+ api_key=VALID_API_KEY, # Pass the APP_API_KEY to the hosted space
79
+ api_name="/chat" # Ensure this matches the API endpoint exposed by the hosted Gradio app
80
+ )
81
+ print(f"Received raw result from hosted Space: {result}")
82
+
83
+ # The result from client.predict on a ChatInterface is typically the assistant's response string
84
+ assistant_response = result
85
+ if not isinstance(assistant_response, str):
86
+ print(f"Warning: Hosted Space returned unexpected result type: {type(assistant_response)}. Raw result: {result}")
87
+ # Attempt to convert to string or handle appropriately
88
+ assistant_response = str(assistant_response)
89
+ print(f"Formatted assistant response: {assistant_response}")
90
+
91
+
92
+ except Exception as e:
93
+ print(f"Error calling hosted Gradio Space from /chat: {e}")
94
+ raise HTTPException(status_code=500, detail=f"Error communicating with chatbot model: {e}")
95
+
96
+
97
+ return {"response": assistant_response}
98
+
99
+
100
+ # --- Twilio Webhook Endpoint ---
101
+ # In-memory dictionary to store history per sender (NOT for production!)
102
+ # Replace this with a persistent storage solution (database, file storage) for production.
103
+ conversation_histories = {}
104
+ # For production-level history management, you would initialize and interact with
105
+ # a database or other persistent storage here.
106
+
107
+ @app.post("/webhook")
108
+ async def webhook(
109
+ # Explicitly receive form data parameters expected from Twilio
110
+ From: str = Form(...), # Sender's phone number
111
+ Body: str = Form(...), # Message content
112
+ # Twilio sends other parameters like MessageSid, To, AccountSid, etc.
113
+ # You can receive them here if needed:
114
+ # MessageSid: str = Form(None),
115
+ # To: str = Form(None),
116
+ request: Request = None # Keep request for raw access if needed
117
+ ):
118
+ """
119
+ Handles incoming Twilio webhook requests for new messages,
120
+ processes them with the chatbot, and returns TwiML.
121
+ Note: This implementation uses in-memory history (NOT for production).
122
+ """
123
+ print("\n--- Received POST request at /webhook from Twilio ---")
124
+
125
+ # Access the incoming message and sender number directly from Form parameters
126
+ incoming_message = Body
127
+ sender_number = From
128
+
129
+ print(f"Parsed Incoming Message: '{incoming_message}' from {sender_number}")
130
+
131
+ # --- Conversation History Management (In-Memory - NOT Persistent!) ---
132
+ # In a real application, you would load/save history from a database/file.
133
+ chat_history = conversation_histories.get(sender_number, [])
134
+ print(f"Retrieved in-memory history for {sender_number}: {chat_history}")
135
+
136
+
137
+ # --- Call Chatbot Logic ---
138
+ if client is None:
139
+ print("Error: Gradio Client not initialized. Cannot call chatbot from webhook.")
140
+ bot_response = "Error: Chatbot service is not available."
141
+ else:
142
+ try:
143
+ # Use the same VALID_API_KEY for the hosted space call from webhook
144
+ print(f"Calling hosted Gradio Space 'Futuresony/Mr.Events' /chat endpoint from /webhook...")
145
+ print(f" Query: {incoming_message}")
146
+ # print(f" History: {chat_history}") # Be cautious logging history
147
+
148
+ # Call the hosted chatbot with the retrieved history
149
+ # Gradio client expects query (current message) and chat_history (history *before* current turn)
150
+ result = await client.predict( # Use await
151
+ query=incoming_message,
152
+ chat_history=chat_history, # Pass the retrieved history
153
+ api_key=VALID_API_KEY, # Pass the APP_API_KEY to the hosted space
154
+ api_name="/chat" # Ensure this matches the API endpoint exposed by the hosted Gradio app
155
+ )
156
+ print(f"Received raw result from hosted Space for webhook: {result}")
157
+
158
+ bot_response = result
159
+ if not isinstance(bot_response, str):
160
+ print(f"Warning: Hosted Space returned unexpected result type for webhook: {type(bot_response)}. Raw result: {result}")
161
+ bot_response = str(bot_response)
162
+ print(f"Formatted chatbot response for webhook: {bot_response}")
163
+
164
+ except Exception as e:
165
+ print(f"Error calling hosted Gradio Space from /webhook: {e}")
166
+ bot_response = f"An error occurred while processing your request: {e}" # Provide a user-friendly error message
167
+
168
+
169
+ # --- Update and Store History (In-Memory - NOT Persistent!) ---
170
+ # Append the current turn (user message + bot response)
171
+ chat_history.append([incoming_message, bot_response])
172
+ conversation_histories[sender_number] = chat_history
173
+ print(f"Updated in-memory history for {sender_number}: {conversation_histories[sender_number]}")
174
+
175
+
176
+ # --- Generate TwiML Response ---
177
+ # Twilio expects TwiML XML to know what to do with the message
178
+ # Use f-string with triple single quotes for multi-line string to avoid conflicts with HTML-like tags
179
+ twiml_response = f'''<Response><Message>{bot_response}</Message></Response>'''
180
+ print(f"Generated TwiML response: {twiml_response}")
181
+
182
+ # Return TwiML with the correct media type
183
+ return Response(content=twiml_response, media_type="application/xml")
184
+
185
+
186
+ if __name__ == "__main__":
187
+ # When running this app.py directly (e.g., with `uvicorn app:app --reload`),
188
+ # this block is executed. On Hugging Face Spaces, the environment typically
189
+ # runs the FastAPI application directly without executing this block.
190
+ # If you need specific initializations (like loading RAG data, initializing cache)
191
+ # when running on Spaces via FastAPI directly, you might need to move them
192
+ # outside this __main__ block or ensure they are called on app startup.
193
+
194
+ # Example (commented out, adjust based on your needs):
195
+ # from app_components import authenticate_google_sheets, load_business_info, initialize_cache
196
+ # authenticate_google_sheets()
197
+ # load_business_info()
198
+ # initialize_cache()
199
+ # cleanup_expired_cache_entries() # Optional
200
+
201
+
202
+ print("Starting FastAPI application with Uvicorn...")
203
+ uvicorn.run(app, host="0.0.0.0", port=7860) # HF default port