Spaces:
Runtime error
Runtime error
| import io | |
| import os | |
| from langchain_core.tools import tool | |
| from googleapiclient.discovery import build | |
| from googleapiclient.http import MediaIoBaseDownload | |
| from googleapiclient.errors import HttpError | |
| from google_auth_helpers import ( | |
| AUTH_REQUIRED_PREFIX, | |
| auth_required_message, | |
| get_google_credentials, | |
| is_auth_failure, | |
| ) | |
| DOWNLOAD_DIR = os.getenv("DOWNLOAD_DIR", "/tmp/drive_downloads") | |
| def _drive_service(user_email: str): | |
| """ | |
| Returns (Drive service, auth_message). | |
| auth_message is set when the user must re-authenticate. | |
| """ | |
| creds, auth_msg = get_google_credentials(user_email) | |
| if auth_msg: | |
| return None, auth_msg | |
| if creds is None: | |
| return None, auth_required_message(user_email, "Google Drive") | |
| return build("drive", "v3", credentials=creds), None | |
| def _search_files(service, query: str, max_results: int = 5) -> list[dict]: | |
| """Full-text search across Drive files.""" | |
| results = service.files().list( | |
| q=f"fullText contains '{query}' and trashed=false", | |
| pageSize=max_results, | |
| fields="files(id, name, mimeType, webViewLink, size)", | |
| ).execute() | |
| return results.get("files", []) | |
| def _download_file(service, file_id: str, file_name: str, mime_type: str) -> str: | |
| """Downloads a file and returns local path.""" | |
| os.makedirs(DOWNLOAD_DIR, exist_ok=True) | |
| local_path = os.path.join(DOWNLOAD_DIR, file_name) | |
| export_map = { | |
| "application/vnd.google-apps.document": | |
| "application/vnd.openxmlformats-officedocument.wordprocessingml.document", | |
| "application/vnd.google-apps.spreadsheet": | |
| "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", | |
| "application/vnd.google-apps.presentation": | |
| "application/vnd.openxmlformats-officedocument.presentationml.presentation", | |
| } | |
| fh = io.BytesIO() | |
| if mime_type in export_map: | |
| export_mime = export_map[mime_type] | |
| request = service.files().export_media(fileId=file_id, mimeType=export_mime) | |
| ext_map = { | |
| "application/vnd.openxmlformats-officedocument.wordprocessingml.document": ".docx", | |
| "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": ".xlsx", | |
| "application/vnd.openxmlformats-officedocument.presentationml.presentation": ".pptx", | |
| } | |
| local_path += ext_map.get(export_mime, "") | |
| else: | |
| request = service.files().get_media(fileId=file_id) | |
| downloader = MediaIoBaseDownload(fh, request) | |
| done = False | |
| while not done: | |
| _, done = downloader.next_chunk() | |
| with open(local_path, "wb") as f: | |
| f.write(fh.getvalue()) | |
| return local_path | |
| def search_and_download_doc_tool(user_email: str, query: str) -> str: | |
| """ | |
| Searches Google Drive and downloads a document by name. | |
| """ | |
| service, auth_msg = _drive_service(user_email) | |
| if auth_msg: | |
| return auth_msg | |
| try: | |
| files = _search_files(service, query) | |
| except HttpError as e: | |
| if is_auth_failure(e): | |
| return auth_required_message(user_email, "Google Drive", revoke=True) | |
| return f"Drive search failed: {e}" | |
| if not files: | |
| return f"No files found on Google Drive matching '{query}'." | |
| best = files[0] | |
| file_id = best["id"] | |
| file_name = best["name"] | |
| mime_type = best["mimeType"] | |
| view_link = best.get("webViewLink", "N/A") | |
| other_matches = [f["name"] for f in files[1:]] | |
| other_str = ( | |
| f"\n\nOther matches: {', '.join(other_matches)}" if other_matches else "" | |
| ) | |
| try: | |
| local_path = _download_file(service, file_id, file_name, mime_type) | |
| return ( | |
| f"✅ Found and downloaded '{file_name}'.\n" | |
| f"Saved to: {local_path}\n" | |
| f"View online: {view_link}" | |
| f"{other_str}" | |
| ) | |
| except HttpError as e: | |
| if is_auth_failure(e): | |
| return auth_required_message(user_email, "Google Drive", revoke=True) | |
| return ( | |
| f"Found '{file_name}' on Drive but download failed: {e}\n" | |
| f"View online: {view_link}" | |
| ) | |