TarSh8654 commited on
Commit
9d07e1c
·
verified ·
1 Parent(s): ac824ad

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +38 -78
app.py CHANGED
@@ -22,51 +22,9 @@ app = Flask(__name__)
22
  # For persistent history, a database (like Firestore) is required.
23
  conversation_histories = {}
24
 
25
- async def call_google_search_tool(query):
26
- """
27
- Calls the internal google_search tool provided by the environment.
28
- """
29
- print(f"Calling google_search tool for query: {query}")
30
- search_payload = {
31
- "queries": [query]
32
- }
33
- # This endpoint is specific to the Canvas/Hugging Face environment where tools are exposed
34
- # If running locally, you would need to replace this with an actual Google Search API call
35
- # (e.g., Google Custom Search API) and handle its API key.
36
- try:
37
- search_response = requests.post(
38
- 'http://localhost:8000/api/google_search', # This URL is for the Canvas environment's tool access
39
- headers={'Content-Type': 'application/json'},
40
- data=json.dumps(search_payload)
41
- )
42
- search_response.raise_for_status()
43
- search_result = search_response.json()
44
- print("Google Search results received.")
45
-
46
- context = ""
47
- if search_result.get('results'):
48
- for query_result in search_result['results']:
49
- if query_result.get('results'):
50
- for item_index, item in enumerate(query_result['results']):
51
- if item.get('snippet'):
52
- context += f"[Source {item_index + 1}] {item['snippet']}\n"
53
- if len(context) > 2000: # Limit context length to avoid excessively long prompts
54
- context += "...\n"
55
- break
56
- if len(context) > 2000:
57
- break
58
- return context
59
- except requests.exceptions.RequestException as e:
60
- print(f"Error calling google_search tool: {e}")
61
- return f"Error retrieving information from search: {e}"
62
- except Exception as e:
63
- print(f"Unexpected error in google_search tool call: {e}")
64
- return f"An unexpected error occurred during search: {e}"
65
-
66
-
67
  async def generate_solution_python(chat_history):
68
  """
69
- Generates a solution using Google Search for context and Gemini LLM,
70
  based on the provided chat history which can include text, images, and extracted PDF text.
71
 
72
  Args:
@@ -84,47 +42,38 @@ async def generate_solution_python(chat_history):
84
  response_text = ""
85
 
86
  try:
87
- # Extract the latest user query from chat history for Google Search
88
- latest_user_query = ""
 
 
 
 
 
89
  for message in reversed(chat_history):
90
  if message["role"] == "user" and message["parts"]:
91
  for part in message["parts"]:
92
  if part.get("text"):
93
- latest_user_query = part["text"]
94
- break # Found the latest text query
95
- if latest_user_query:
 
 
 
 
 
 
 
96
  break
97
 
98
- # --- Google Search Integration Point ---
99
- search_context = ""
100
- if latest_user_query:
101
- search_context = await call_google_search_tool(latest_user_query)
102
- if search_context and not search_context.startswith("Error"):
103
- search_context = "\n\nRelevant Information from Web Search:\n" + search_context
104
- else:
105
- search_context = f"\n\nCould not retrieve web search results: {search_context}"
106
-
107
-
108
- # Construct the final `contents` list for the LLM call.
109
- # We'll prepend the search context to the latest user message.
110
- augmented_chat_contents = []
111
- for i, message in enumerate(chat_history):
112
- if i == len(chat_history) - 1 and message["role"] == "user": # Last user message
113
- augmented_parts = []
114
- if search_context:
115
- augmented_parts.append({"text": search_context})
116
- for part in message["parts"]:
117
- augmented_parts.append(part)
118
- augmented_chat_contents.append({"role": "user", "parts": augmented_parts})
119
- else:
120
- augmented_chat_contents.append(message)
121
-
122
- # Step 2: Call Gemini API with the augmented chat history
123
- print("Calling Gemini API with augmented chat history...")
124
  llm_payload = {
125
- "contents": augmented_chat_contents # Pass the augmented history
126
  }
127
 
 
128
  gemini_api_key = os.environ.get("GEMINI_API_KEY")
129
  if not gemini_api_key:
130
  raise ValueError("GEMINI_API_KEY environment variable not set.")
@@ -137,7 +86,7 @@ async def generate_solution_python(chat_history):
137
  data=json.dumps(llm_payload)
138
  )
139
 
140
- gemini_response.raise_for_status()
141
  llm_result = gemini_response.json()
142
  print("Gemini API response received.")
143
 
@@ -173,7 +122,7 @@ def index():
173
  @app.route('/generate', methods=['POST'])
174
  async def generate():
175
  """Handles the AI generation request, managing conversation history and multi-modal input."""
176
- session_id = None
177
  try:
178
  data = request.get_json()
179
  if not data:
@@ -184,6 +133,7 @@ async def generate():
184
  document_text = data.get('document_text') # Text extracted from .txt on frontend
185
  pdf_data = data.get('pdf_data') # Base64 PDF data
186
 
 
187
  session_id = data.get('session_id')
188
  if not session_id:
189
  session_id = str(uuid.uuid4())
@@ -194,6 +144,7 @@ async def generate():
194
 
195
  current_chat_history = conversation_histories.get(session_id, [])
196
 
 
197
  user_message_parts = []
198
  if user_query:
199
  user_message_parts.append({"text": user_query})
@@ -211,6 +162,7 @@ async def generate():
211
  return jsonify({"error": "PDF parsing library (PyPDF2) not installed on backend."}), 500
212
 
213
  try:
 
214
  pdf_bytes = base64.b64decode(pdf_data['data'])
215
  pdf_file = io.BytesIO(pdf_bytes)
216
  reader = PdfReader(pdf_file)
@@ -218,7 +170,7 @@ async def generate():
218
  pdf_extracted_text = ""
219
  for page_num in range(len(reader.pages)):
220
  page = reader.pages[page_num]
221
- pdf_extracted_text += page.extract_text() or ""
222
 
223
  if pdf_extracted_text.strip():
224
  user_message_parts.append({"text": f"PDF Document Content:\n{pdf_extracted_text}"})
@@ -230,6 +182,9 @@ async def generate():
230
  except Exception as pdf_error:
231
  print(f"Error processing PDF: {pdf_error}")
232
  user_message_parts.append({"text": f"PDF Document: (Error processing PDF: {pdf_error})"})
 
 
 
233
 
234
  # If only a file was provided without a query, add a default instruction
235
  if not user_query and (image_data or document_text or pdf_data):
@@ -238,18 +193,23 @@ async def generate():
238
  elif document_text or pdf_data:
239
  user_message_parts.insert(0, {"text": "Please analyze the following document content and provide a summary or answer questions:"})
240
 
 
241
  current_chat_history.append({"role": "user", "parts": user_message_parts})
242
 
 
243
  solution_text = await generate_solution_python(current_chat_history)
244
 
 
245
  current_chat_history.append({"role": "model", "parts": [{"text": solution_text}]})
246
 
 
247
  conversation_histories[session_id] = current_chat_history
248
 
249
  return jsonify({"solution": solution_text, "session_id": session_id})
250
 
251
  except Exception as e:
252
  print(f"Error in /generate endpoint: {e}")
 
253
  if session_id:
254
  return jsonify({"error": f"Internal server error for session {session_id}: {e}"}), 500
255
  else:
 
22
  # For persistent history, a database (like Firestore) is required.
23
  conversation_histories = {}
24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  async def generate_solution_python(chat_history):
26
  """
27
+ Generates a solution using a dummy context and Gemini LLM,
28
  based on the provided chat history which can include text, images, and extracted PDF text.
29
 
30
  Args:
 
42
  response_text = ""
43
 
44
  try:
45
+ # --- IMPORTANT: Placeholder for Search API Integration ---
46
+ # The 'google_search' tool is specific to the Canvas environment.
47
+ # On Hugging Face, you would integrate a real public search API here.
48
+ # For this example, we'll use a dummy context based on the latest user query.
49
+
50
+ # Find the latest user input (text or image/document indication) for dummy context
51
+ latest_user_input = ""
52
  for message in reversed(chat_history):
53
  if message["role"] == "user" and message["parts"]:
54
  for part in message["parts"]:
55
  if part.get("text"):
56
+ latest_user_input = part["text"]
57
+ break
58
+ if part.get("inlineData") and "image" in part["inlineData"].get("mimeType", ""):
59
+ latest_user_input = "an image"
60
+ break
61
+ # If a document was processed and its text added, use that
62
+ if part.get("text") and part["text"].startswith("PDF Document Content:") or part["text"].startswith("Document content:"):
63
+ latest_user_input = "a document"
64
+ break
65
+ if latest_user_input:
66
  break
67
 
68
+ dummy_context = f"Information related to '{latest_user_input}' from various online sources indicates that..."
69
+
70
+ # Step 2: Call Gemini API with the full chat history
71
+ print("Calling Gemini API with full chat history...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  llm_payload = {
73
+ "contents": chat_history # Pass the entire history, including text and image parts
74
  }
75
 
76
+ # Get API key from environment variables (Hugging Face Space Secrets)
77
  gemini_api_key = os.environ.get("GEMINI_API_KEY")
78
  if not gemini_api_key:
79
  raise ValueError("GEMINI_API_KEY environment variable not set.")
 
86
  data=json.dumps(llm_payload)
87
  )
88
 
89
+ gemini_response.raise_for_status() # Raise an exception for HTTP errors
90
  llm_result = gemini_response.json()
91
  print("Gemini API response received.")
92
 
 
122
  @app.route('/generate', methods=['POST'])
123
  async def generate():
124
  """Handles the AI generation request, managing conversation history and multi-modal input."""
125
+ session_id = None # Initialize session_id to None
126
  try:
127
  data = request.get_json()
128
  if not data:
 
133
  document_text = data.get('document_text') # Text extracted from .txt on frontend
134
  pdf_data = data.get('pdf_data') # Base64 PDF data
135
 
136
+ # Ensure session_id is assigned before use
137
  session_id = data.get('session_id')
138
  if not session_id:
139
  session_id = str(uuid.uuid4())
 
144
 
145
  current_chat_history = conversation_histories.get(session_id, [])
146
 
147
+ # Construct the parts for the user message
148
  user_message_parts = []
149
  if user_query:
150
  user_message_parts.append({"text": user_query})
 
162
  return jsonify({"error": "PDF parsing library (PyPDF2) not installed on backend."}), 500
163
 
164
  try:
165
+ # Decode base64 PDF data
166
  pdf_bytes = base64.b64decode(pdf_data['data'])
167
  pdf_file = io.BytesIO(pdf_bytes)
168
  reader = PdfReader(pdf_file)
 
170
  pdf_extracted_text = ""
171
  for page_num in range(len(reader.pages)):
172
  page = reader.pages[page_num]
173
+ pdf_extracted_text += page.extract_text() or "" # extract_text can return None
174
 
175
  if pdf_extracted_text.strip():
176
  user_message_parts.append({"text": f"PDF Document Content:\n{pdf_extracted_text}"})
 
182
  except Exception as pdf_error:
183
  print(f"Error processing PDF: {pdf_error}")
184
  user_message_parts.append({"text": f"PDF Document: (Error processing PDF: {pdf_error})"})
185
+ # Do not return error to frontend immediately for PDF processing issues
186
+ # Let the LLM try to respond even if PDF extraction failed
187
+ # return jsonify({"error": f"Failed to process PDF: {pdf_error}"}), 400
188
 
189
  # If only a file was provided without a query, add a default instruction
190
  if not user_query and (image_data or document_text or pdf_data):
 
193
  elif document_text or pdf_data:
194
  user_message_parts.insert(0, {"text": "Please analyze the following document content and provide a summary or answer questions:"})
195
 
196
+ # Append the new user message (which can be multi-part) to the history
197
  current_chat_history.append({"role": "user", "parts": user_message_parts})
198
 
199
+ # Generate the solution using the full chat history
200
  solution_text = await generate_solution_python(current_chat_history)
201
 
202
+ # Append the model's response to the history
203
  current_chat_history.append({"role": "model", "parts": [{"text": solution_text}]})
204
 
205
+ # Store the updated history
206
  conversation_histories[session_id] = current_chat_history
207
 
208
  return jsonify({"solution": solution_text, "session_id": session_id})
209
 
210
  except Exception as e:
211
  print(f"Error in /generate endpoint: {e}")
212
+ # Ensure session_id is handled even in the outer exception for logging/debugging
213
  if session_id:
214
  return jsonify({"error": f"Internal server error for session {session_id}: {e}"}), 500
215
  else: