diff --git "a/RAG-1.ipynb" "b/RAG-1.ipynb"
new file mode 100644--- /dev/null
+++ "b/RAG-1.ipynb"
@@ -0,0 +1,2454 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "e549bafd-78b1-4a83-80b4-2cb597efff79",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "import json\n",
+ "from google.oauth2 import service_account\n",
+ "from googleapiclient.discovery import build\n",
+ "from googleapiclient.http import MediaIoBaseDownload\n",
+ "import openai\n",
+ "from dotenv import load_dotenv, dotenv_values\n",
+ "import io"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "04361235-7896-4439-9d04-1400e043528b",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "load_dotenv()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "9ae411c5-c84b-4bfd-b089-69b5c5ba70ae",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "OPENAI_API_KEY\n",
+ "ANTHROPIC_API_KEY\n",
+ "GOOGLE_SERVICE_ACCOUNT_FILE\n"
+ ]
+ }
+ ],
+ "source": [
+ "config = dotenv_values(\".env\")\n",
+ "for key in config.keys():\n",
+ " print(key)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "7622a0e4-64a6-4848-b588-bd65d56c55e0",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from openai import OpenAI\n",
+ "openai.api_key = os.getenv('OPENAI_API_KEY')\n",
+ "openai = OpenAI(api_key = openai.api_key)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "2ead7c59-1f11-478a-bb69-2928ddc38901",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Hello! How can I assist you today?\n"
+ ]
+ }
+ ],
+ "source": [
+ "response = openai.chat.completions.create(\n",
+ " model = \"gpt-4o-mini\",\n",
+ " messages = [\n",
+ " {\"role\":\"system\", \"content\":\"you are a helpful assistant\"},\n",
+ " {\"role\":\"user\", \"content\":\"hi\"}\n",
+ " ])\n",
+ "\n",
+ "reply = response.choices[0].message.content\n",
+ "print(reply)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "b3bcbada-6a72-4cc8-a166-d2e596cd1fc4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "service_account_file_path = os.getenv(\"GOOGLE_SERVICE_ACCOUNT_FILE\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "81c59a6d-0831-4bff-b3fc-fbe3d4cc1e31",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "openai activated\n",
+ "service_account_file_path activated\n"
+ ]
+ }
+ ],
+ "source": [
+ "#troubleshoot\n",
+ "if openai is None:\n",
+ " print(\"openai not activated\")\n",
+ "else: \n",
+ " print (\"openai activated\")\n",
+ "\n",
+ "if service_account_file_path is None:\n",
+ " print(\"service_account_file_path not activated\")\n",
+ "else: \n",
+ " print (\"service_account_file_path activated\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "a70f32aa-9e43-4175-8cca-d6af723aef91",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "0efe325d-badd-4533-affe-47d572ef128e",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "class GPTDriveIntegration:\n",
+ " def __init__(self):\n",
+ " # Initialize Google Drive API\n",
+ " self.credentials = service_account.Credentials.from_service_account_file(\n",
+ " os.getenv('GOOGLE_SERVICE_ACCOUNT_FILE'),\n",
+ " scopes=['https://www.googleapis.com/auth/drive.readonly']\n",
+ " )\n",
+ " self.drive_service = build('drive', 'v3', credentials=self.credentials)\n",
+ " \n",
+ " # Initialize OpenAI\n",
+ " openai.api_key = os.getenv('OPENAI_API_KEY')\n",
+ " \n",
+ " def search_files(self, query, file_types=None):\n",
+ " \"\"\"Search for files in Google Drive\"\"\"\n",
+ " search_query = f\"name contains '{query}'\"\n",
+ " \n",
+ " if file_types:\n",
+ " type_queries = []\n",
+ " for file_type in file_types:\n",
+ " if file_type.lower() == 'pdf':\n",
+ " type_queries.append(\"mimeType='application/pdf'\")\n",
+ " elif file_type.lower() in ['doc', 'docx']:\n",
+ " type_queries.append(\"mimeType contains 'document'\")\n",
+ " elif file_type.lower() in ['xls', 'xlsx']:\n",
+ " type_queries.append(\"mimeType contains 'spreadsheet'\")\n",
+ " \n",
+ " if type_queries:\n",
+ " search_query += f\" and ({' or '.join(type_queries)})\"\n",
+ " \n",
+ " results = self.drive_service.files().list(\n",
+ " q=search_query,\n",
+ " fields=\"files(id, name, mimeType, size)\"\n",
+ " ).execute()\n",
+ " \n",
+ " return results.get('files', [])\n",
+ " \n",
+ " def get_file_content(self, file_id, mime_type):\n",
+ " \"\"\"Download and extract text content from file\"\"\"\n",
+ " try:\n",
+ " if 'text' in mime_type or 'document' in mime_type:\n",
+ " # For Google Docs, export as plain text\n",
+ " if 'document' in mime_type:\n",
+ " request = self.drive_service.files().export_media(\n",
+ " fileId=file_id, mimeType='text/plain'\n",
+ " )\n",
+ " else:\n",
+ " request = self.drive_service.files().get_media(fileId=file_id)\n",
+ " \n",
+ " file_content = io.BytesIO()\n",
+ " downloader = MediaIoBaseDownload(file_content, request)\n",
+ " done = False\n",
+ " while done is False:\n",
+ " status, done = downloader.next_chunk()\n",
+ " \n",
+ " return file_content.getvalue().decode('utf-8')\n",
+ " \n",
+ " elif 'spreadsheet' in mime_type:\n",
+ " # For Google Sheets, export as CSV\n",
+ " request = self.drive_service.files().export_media(\n",
+ " fileId=file_id, mimeType='text/csv'\n",
+ " )\n",
+ " file_content = io.BytesIO()\n",
+ " downloader = MediaIoBaseDownload(file_content, request)\n",
+ " done = False\n",
+ " while done is False:\n",
+ " status, done = downloader.next_chunk()\n",
+ " \n",
+ " return file_content.getvalue().decode('utf-8')\n",
+ " \n",
+ " elif mime_type == 'application/pdf':\n",
+ " # For PDF files, download binary content and extract text\n",
+ " request = self.drive_service.files().get_media(fileId=file_id)\n",
+ " file_content = io.BytesIO()\n",
+ " downloader = MediaIoBaseDownload(file_content, request)\n",
+ " done = False\n",
+ " while done is False:\n",
+ " status, done = downloader.next_chunk()\n",
+ " \n",
+ " # Extract text from PDF using PyPDF2 or pdfplumber\n",
+ " file_content.seek(0) # Reset buffer position\n",
+ " \n",
+ " # Option 1: Using PyPDF2\n",
+ " try:\n",
+ " import PyPDF2\n",
+ " pdf_reader = PyPDF2.PdfReader(file_content)\n",
+ " text = \"\"\n",
+ " for page in pdf_reader.pages:\n",
+ " text += page.extract_text() + \"\\n\"\n",
+ " return text\n",
+ " except ImportError:\n",
+ " pass\n",
+ " \n",
+ " # Option 2: Using pdfplumber (better for complex PDFs)\n",
+ " try:\n",
+ " import pdfplumber\n",
+ " text = \"\"\n",
+ " with pdfplumber.open(file_content) as pdf:\n",
+ " for page in pdf.pages:\n",
+ " page_text = page.extract_text()\n",
+ " if page_text:\n",
+ " text += page_text + \"\\n\"\n",
+ " return text\n",
+ " except ImportError:\n",
+ " pass\n",
+ " \n",
+ " # Option 3: Using pymupdf (fitz) - fastest option\n",
+ " try:\n",
+ " import fitz # pymupdf\n",
+ " pdf_document = fitz.open(stream=file_content.read(), filetype=\"pdf\")\n",
+ " text = \"\"\n",
+ " for page_num in range(pdf_document.page_count):\n",
+ " page = pdf_document[page_num]\n",
+ " text += page.get_text() + \"\\n\"\n",
+ " pdf_document.close()\n",
+ " return text\n",
+ " except ImportError:\n",
+ " pass\n",
+ " \n",
+ " return \"PDF text extraction requires PyPDF2, pdfplumber, or pymupdf library\"\n",
+ " \n",
+ " else:\n",
+ " return \"File type not supported for text extraction\"\n",
+ " \n",
+ " except Exception as e:\n",
+ " return f\"Error reading file: {str(e)}\"\n",
+ " \n",
+ " def query_gpt_with_context(self, user_query, file_contents):\n",
+ " \"\"\"Send query to GPT with file context\"\"\"\n",
+ " context = \"\\n\\n\".join([\n",
+ " f\"File: {content['name']}\\nContent: {content['text'][:2000]}...\"\n",
+ " for content in file_contents\n",
+ " ])\n",
+ " \n",
+ " messages = [\n",
+ " {\n",
+ " \"role\": \"system\", \n",
+ " \"content\": \"\"\"\n",
+ " You are an AI assistant that can analyze documents from Google Drive. \n",
+ " Use the provided file contents to answer user questions.\"\"\"\n",
+ " },\n",
+ " {\n",
+ " \"role\": \"user\", \n",
+ " \"content\": f\"Context from Google Drive files:\\n{context}\\n\\nUser Question: {user_query}\"\n",
+ " }\n",
+ " ]\n",
+ " \n",
+ " response = openai.chat.completions.create(\n",
+ " model=\"gpt-4o-mini\",\n",
+ " messages=messages,\n",
+ " max_tokens=1000\n",
+ " )\n",
+ " \n",
+ " return response.choices[0].message.content\n",
+ " \n",
+ " def process_query(self, user_query, search_terms=None):\n",
+ " \"\"\"Main function to process user queries\"\"\"\n",
+ " # Extract search terms from query if not provided\n",
+ " if not search_terms:\n",
+ " search_terms = user_query.split()[:3] # Simple extraction\n",
+ " \n",
+ " # Search for relevant files\n",
+ " files = []\n",
+ " for term in search_terms:\n",
+ " files.extend(self.search_files(term))\n",
+ " \n",
+ " # Remove duplicates\n",
+ " unique_files = {f['id']: f for f in files}.values()\n",
+ " \n",
+ " # Get content from top 3 most relevant files\n",
+ " file_contents = []\n",
+ " for file in list(unique_files)[:3]:\n",
+ " content = self.get_file_content(file['id'], file['mimeType'])\n",
+ " file_contents.append({\n",
+ " 'name': file['name'],\n",
+ " 'text': content\n",
+ " })\n",
+ " \n",
+ " # Query GPT with context\n",
+ " if file_contents:\n",
+ " response = self.query_gpt_with_context(user_query, file_contents)\n",
+ " return {\n",
+ " 'answer': response,\n",
+ " 'sources': [f['name'] for f in file_contents]\n",
+ " }\n",
+ " else:\n",
+ " return {\n",
+ " 'answer': \"No relevant files found in your Google Drive.\",\n",
+ " 'sources': []\n",
+ " }"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "id": "3c2c1ccf-9ade-482d-a170-978e97bc1c08",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Answer: The transmission of nerves is called \"nerve conduction.\" This process involves the propagation of electrical impulses along the nerve fibers, allowing for communication between different parts of the body.\n",
+ "Sources: ['Neuro Note Dr Clement.docx']\n"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " integration = GPTDriveIntegration()\n",
+ " \n",
+ " # Test query\n",
+ " result = integration.process_query(\n",
+ " \"The transmission of nerves is called?\",\n",
+ " search_terms=[\"nerves\", \"Dr Clement\"]\n",
+ " )\n",
+ " \n",
+ " print(\"Answer:\", result['answer'])\n",
+ " print(\"Sources:\", result['sources'])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "120e7c93-b38a-4c89-8e76-5b0170d22548",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "61e976a6-1fe4-45de-a63d-3cf849eedbe1",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "id": "c514b8af-1af4-4497-9044-139a71aedd36",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "* Running on local URL: http://127.0.0.1:7860\n",
+ "* Running on public URL: https://5320171f6af3e2eef9.gradio.live\n",
+ "\n",
+ "This share link expires in 1 week. For free permanent hosting and GPU upgrades, run `gradio deploy` from the terminal in the working directory to deploy to Hugging Face Spaces (https://huggingface.co/spaces)\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Keyboard interruption in main thread... closing server.\n",
+ "Killing tunnel 127.0.0.1:7860 <> https://5320171f6af3e2eef9.gradio.live\n"
+ ]
+ }
+ ],
+ "source": [
+ "gpt_drive = GPTDriveIntegration()\n",
+ "\n",
+ "def process_user_query(query, search_terms_input):\n",
+ " \"\"\"Process user query and return formatted response\"\"\"\n",
+ " if not query.strip():\n",
+ " return \"Please enter a question.\", \"\"\n",
+ " \n",
+ " # Parse search terms if provided\n",
+ " search_terms = None\n",
+ " # if search_terms_input.strip():\n",
+ " # search_terms = [term.strip() for term in search_terms_input.split(',')]\n",
+ " \n",
+ " # Process the query\n",
+ " result = gpt_drive.process_query(query, search_terms)\n",
+ " \n",
+ " # Format the response\n",
+ " answer = result['answer']\n",
+ " sources = result['sources']\n",
+ " \n",
+ " sources_text = \"\"\n",
+ " if sources:\n",
+ " sources_text = \"**Sources used:**\\n\" + \"\\n\".join([f\"• {source}\" for source in sources])\n",
+ " \n",
+ " return answer, sources_text\n",
+ "\n",
+ "def check_setup():\n",
+ " \"\"\"Check if the APIs are properly configured\"\"\"\n",
+ " status_messages = []\n",
+ " \n",
+ " # Check Google Drive API\n",
+ " if gpt_drive.drive_initialized:\n",
+ " status_messages.append(\"✅ Google Drive API: Connected\")\n",
+ " else:\n",
+ " status_messages.append(f\"❌ Google Drive API: {getattr(gpt_drive, 'drive_error', 'Not configured')}\")\n",
+ " \n",
+ " # Check OpenAI API\n",
+ " if gpt_drive.openai_initialized:\n",
+ " status_messages.append(\"✅ OpenAI API: Connected\")\n",
+ " else:\n",
+ " status_messages.append(f\"❌ OpenAI API: {getattr(gpt_drive, 'openai_error', 'Not configured')}\")\n",
+ " \n",
+ " return \"\\n\".join(status_messages)\n",
+ "\n",
+ "# Create Gradio interface\n",
+ "with gr.Blocks(title=\"Augusta's Anatomy Reading Assistant\", theme=gr.themes.Soft()) as app:\n",
+ " gr.Markdown(\"# 🤖 Augusta's Anatomy bot\")\n",
+ " gr.Markdown(\"Ask questions about your anatomy books using AI!\")\n",
+ " \n",
+ " with gr.Row():\n",
+ " with gr.Column(scale=2):\n",
+ " # Main query interface\n",
+ " with gr.Group():\n",
+ " gr.Markdown(\"### Ask a Question\")\n",
+ " query_input = gr.Textbox(\n",
+ " label=\"Your Question\",\n",
+ " placeholder=\"Ask me any question about your anatomy books?\",\n",
+ " lines=3\n",
+ " )\n",
+ " \n",
+ " search_terms_input = gr.Textbox(\n",
+ " label=\"Search Terms (optional)\",\n",
+ " placeholder=\"Enter comma-separated terms to search for specific files\",\n",
+ " lines=1\n",
+ " )\n",
+ " \n",
+ " submit_btn = gr.Button(\"Search & Ask\", variant=\"primary\", size=\"lg\")\n",
+ " \n",
+ " # Results section\n",
+ " with gr.Group():\n",
+ " gr.Markdown(\"### Answer\")\n",
+ " answer_output = gr.Textbox(\n",
+ " label=\"AI Response\",\n",
+ " lines=10,\n",
+ " interactive=False\n",
+ " )\n",
+ " \n",
+ " sources_output = gr.Textbox(\n",
+ " label=\"Sources\",\n",
+ " lines=3,\n",
+ " interactive=False\n",
+ " )\n",
+ " \n",
+ " with gr.Column(scale=1):\n",
+ " # Status and setup info\n",
+ " with gr.Group():\n",
+ " gr.Markdown(\"### System Status\")\n",
+ " status_btn = gr.Button(\"Check Status\", size=\"sm\")\n",
+ " status_output = gr.Textbox(\n",
+ " label=\"API Status\",\n",
+ " lines=4,\n",
+ " interactive=False\n",
+ " )\n",
+ " \n",
+ " with gr.Group():\n",
+ " gr.Markdown(\"### Setup Instructions\")\n",
+ " gr.Markdown(\"\"\"\n",
+ " **Important Notes:**\n",
+ " 1.Only documents shared with it, it can answer\n",
+ " \n",
+ " **File Types Supported:**\n",
+ " - Google Docs\n",
+ " - Google Sheets \n",
+ " - PDF files\n",
+ " - Text files\n",
+ " \n",
+ " **Tips:**\n",
+ " - Use specific search terms for better results\n",
+ " - The system searches the top 3 most relevant files\n",
+ " - Ask clear, specific questions for better answers\n",
+ " \"\"\")\n",
+ " \n",
+ " # Event handlers\n",
+ " submit_btn.click(\n",
+ " fn=process_user_query,\n",
+ " inputs=[query_input, search_terms_input],\n",
+ " outputs=[answer_output, sources_output]\n",
+ " )\n",
+ " \n",
+ " status_btn.click(\n",
+ " fn=check_setup,\n",
+ " outputs=status_output\n",
+ " )\n",
+ " \n",
+ " # Example queries\n",
+ " with gr.Row():\n",
+ " gr.Examples(\n",
+ " examples=[\n",
+ " [\"What is morbid Anatomy?\", \"morbid, Anatomy\"],\n",
+ " [\"The transmission of nerves from one neuron to another is as a result of what?\", \"neuron, nerves, Dr Clement\"],\n",
+ " ],\n",
+ " inputs=[query_input, search_terms_input],\n",
+ " )\n",
+ "\n",
+ "# Launch the app\n",
+ "if __name__ == \"__main__\":\n",
+ " app.launch(\n",
+ " share=True,debug =True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 42,
+ "id": "593c4f63-cdda-46e8-aad6-9f9d7db66615",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "#Gradio\n",
+ "# !pip install gradio"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "859060a9-56f9-49e9-bb41-04ccf7b10d3f",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "d893999c-4f3f-4306-8b0b-072e3fbb8236",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "id": "01b70311-ff22-4c88-bf22-64dc441afaab",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "C:\\Users\\Uche Buzz\\anaconda3\\envs\\RAG\\Lib\\site-packages\\tqdm\\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
+ " from .autonotebook import tqdm as notebook_tqdm\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "* Running on local URL: http://127.0.0.1:7860\n",
+ "* Running on public URL: https://8fac475cac6193423b.gradio.live\n",
+ "\n",
+ "This share link expires in 1 week. For free permanent hosting and GPU upgrades, run `gradio deploy` from the terminal in the working directory to deploy to Hugging Face Spaces (https://huggingface.co/spaces)\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Keyboard interruption in main thread... closing server.\n",
+ "Killing tunnel 127.0.0.1:7860 <> https://8fac475cac6193423b.gradio.live\n"
+ ]
+ }
+ ],
+ "source": [
+ "import gradio as gr\n",
+ "import os\n",
+ "import io\n",
+ "import openai\n",
+ "from google.oauth2 import service_account\n",
+ "from googleapiclient.discovery import build\n",
+ "from googleapiclient.http import MediaIoBaseDownload\n",
+ "\n",
+ "class GPTDriveIntegration:\n",
+ " def __init__(self):\n",
+ " # Initialize Google Drive API\n",
+ " try:\n",
+ " self.credentials = service_account.Credentials.from_service_account_file(\n",
+ " os.getenv('GOOGLE_SERVICE_ACCOUNT_FILE'),\n",
+ " scopes=['https://www.googleapis.com/auth/drive.readonly']\n",
+ " )\n",
+ " self.drive_service = build('drive', 'v3', credentials=self.credentials)\n",
+ " self.drive_initialized = True\n",
+ " except Exception as e:\n",
+ " self.drive_initialized = False\n",
+ " self.drive_error = str(e)\n",
+ " \n",
+ " # Initialize OpenAI\n",
+ " try:\n",
+ " openai.api_key = os.getenv('OPENAI_API_KEY')\n",
+ " self.openai_initialized = True\n",
+ " except Exception as e:\n",
+ " self.openai_initialized = False\n",
+ " self.openai_error = str(e)\n",
+ " \n",
+ " def search_files(self, query, file_types=None):\n",
+ " \"\"\"Search for files in Google Drive\"\"\"\n",
+ " if not self.drive_initialized:\n",
+ " return []\n",
+ " \n",
+ " search_query = f\"name contains '{query}'\"\n",
+ " \n",
+ " if file_types:\n",
+ " type_queries = []\n",
+ " for file_type in file_types:\n",
+ " if file_type.lower() == 'pdf':\n",
+ " type_queries.append(\"mimeType='application/pdf'\")\n",
+ " elif file_type.lower() in ['doc', 'docx']:\n",
+ " type_queries.append(\"mimeType contains 'document'\")\n",
+ " elif file_type.lower() in ['xls', 'xlsx']:\n",
+ " type_queries.append(\"mimeType contains 'spreadsheet'\")\n",
+ " \n",
+ " if type_queries:\n",
+ " search_query += f\" and ({' or '.join(type_queries)})\"\n",
+ " \n",
+ " try:\n",
+ " results = self.drive_service.files().list(\n",
+ " q=search_query,\n",
+ " fields=\"files(id, name, mimeType, size)\"\n",
+ " ).execute()\n",
+ " \n",
+ " return results.get('files', [])\n",
+ " except Exception as e:\n",
+ " return []\n",
+ " \n",
+ " def get_file_content(self, file_id, mime_type):\n",
+ " \"\"\"Download and extract text content from file\"\"\"\n",
+ " try:\n",
+ " if 'text' in mime_type or 'document' in mime_type:\n",
+ " # For Google Docs, export as plain text\n",
+ " if 'document' in mime_type:\n",
+ " request = self.drive_service.files().export_media(\n",
+ " fileId=file_id, mimeType='text/plain'\n",
+ " )\n",
+ " else:\n",
+ " request = self.drive_service.files().get_media(fileId=file_id)\n",
+ " \n",
+ " file_content = io.BytesIO()\n",
+ " downloader = MediaIoBaseDownload(file_content, request)\n",
+ " done = False\n",
+ " while done is False:\n",
+ " status, done = downloader.next_chunk()\n",
+ " \n",
+ " return file_content.getvalue().decode('utf-8')\n",
+ " \n",
+ " elif 'spreadsheet' in mime_type:\n",
+ " # For Google Sheets, export as CSV\n",
+ " request = self.drive_service.files().export_media(\n",
+ " fileId=file_id, mimeType='text/csv'\n",
+ " )\n",
+ " file_content = io.BytesIO()\n",
+ " downloader = MediaIoBaseDownload(file_content, request)\n",
+ " done = False\n",
+ " while done is False:\n",
+ " status, done = downloader.next_chunk()\n",
+ " \n",
+ " return file_content.getvalue().decode('utf-8')\n",
+ " \n",
+ " else:\n",
+ " return \"File type not supported for text extraction\"\n",
+ " \n",
+ " except Exception as e:\n",
+ " return f\"Error reading file: {str(e)}\"\n",
+ " \n",
+ " def query_gpt_with_context(self, user_query, file_contents):\n",
+ " \"\"\"Send query to GPT with file context\"\"\"\n",
+ " context = \"\\n\\n\".join([\n",
+ " f\"File: {content['name']}\\nContent: {content['text'][:2000]}...\"\n",
+ " for content in file_contents\n",
+ " ])\n",
+ " \n",
+ " messages = [\n",
+ " {\n",
+ " \"role\": \"system\", \n",
+ " \"content\": \"\"\"\n",
+ " You are an AI assistant that can analyze anatomy documents from Google Drive. \n",
+ " Use the provided file contents to answer user questions. Always answer straightforwardly. Don't Hallucinate.\n",
+ " Always end with 'Do you have any other question?'\n",
+ " \n",
+ " \"\"\"\n",
+ " },\n",
+ " {\n",
+ " \"role\": \"user\", \n",
+ " \"content\": f\"Context from Google Drive files:\\n{context}\\n\\nUser Question: {user_query}\"\n",
+ " }\n",
+ " ]\n",
+ " \n",
+ " try:\n",
+ " response = openai.chat.completions.create(\n",
+ " model=\"gpt-4o-mini\",\n",
+ " messages=messages,\n",
+ " max_tokens=1000\n",
+ " )\n",
+ " \n",
+ " return response.choices[0].message.content\n",
+ " except Exception as e:\n",
+ " return f\"Error querying OpenAI: {str(e)}\"\n",
+ " \n",
+ " def process_query(self, user_query, search_terms=None):\n",
+ " \"\"\"Main function to process user queries\"\"\"\n",
+ " # Check if services are initialized\n",
+ " if not self.drive_initialized:\n",
+ " return {\n",
+ " 'answer': f\"Google Drive API not initialized: {getattr(self, 'drive_error', 'Unknown error')}\",\n",
+ " 'sources': []\n",
+ " }\n",
+ " \n",
+ " if not self.openai_initialized:\n",
+ " return {\n",
+ " 'answer': f\"OpenAI API not initialized: {getattr(self, 'openai_error', 'Unknown error')}\",\n",
+ " 'sources': []\n",
+ " }\n",
+ " \n",
+ " # Extract search terms from query if not provided\n",
+ " if not search_terms:\n",
+ " search_terms = user_query.split()[:3] # Simple extraction\n",
+ " \n",
+ " # Search for relevant files\n",
+ " files = []\n",
+ " for term in search_terms:\n",
+ " files.extend(self.search_files(term))\n",
+ " \n",
+ " # Remove duplicates\n",
+ " unique_files = {f['id']: f for f in files}.values()\n",
+ " \n",
+ " # Get content from top 3 most relevant files\n",
+ " file_contents = []\n",
+ " for file in list(unique_files)[:3]:\n",
+ " content = self.get_file_content(file['id'], file['mimeType'])\n",
+ " file_contents.append({\n",
+ " 'name': file['name'],\n",
+ " 'text': content\n",
+ " })\n",
+ " \n",
+ " # Query GPT with context\n",
+ " if file_contents:\n",
+ " response = self.query_gpt_with_context(user_query, file_contents)\n",
+ " return {\n",
+ " 'answer': response,\n",
+ " 'sources': [f['name'] for f in file_contents]\n",
+ " }\n",
+ " else:\n",
+ " return {\n",
+ " 'answer': \"No relevant files found in your Google Drive.\",\n",
+ " 'sources': []\n",
+ " }\n",
+ "\n",
+ "# Initialize the GPT Drive Integration\n",
+ "gpt_drive = GPTDriveIntegration()\n",
+ "\n",
+ "def process_user_query(query, search_terms_input):\n",
+ " \"\"\"Process user query and return formatted response\"\"\"\n",
+ " if not query.strip():\n",
+ " return \"Please enter a question.\", \"\"\n",
+ " \n",
+ " # Parse search terms if provided\n",
+ " search_terms = None\n",
+ " if search_terms_input.strip():\n",
+ " search_terms = [term.strip() for term in search_terms_input.split(',')]\n",
+ " \n",
+ " # Process the query\n",
+ " result = gpt_drive.process_query(query, search_terms)\n",
+ " \n",
+ " # Format the response\n",
+ " answer = result['answer']\n",
+ " sources = result['sources']\n",
+ " \n",
+ " sources_text = \"\"\n",
+ " if sources:\n",
+ " sources_text = \"**Sources used:**\\n\" + \"\\n\".join([f\"• {source}\" for source in sources])\n",
+ " \n",
+ " return answer, sources_text\n",
+ "\n",
+ "def check_setup():\n",
+ " \"\"\"Check if the APIs are properly configured\"\"\"\n",
+ " status_messages = []\n",
+ " \n",
+ " # Check Google Drive API\n",
+ " if gpt_drive.drive_initialized:\n",
+ " status_messages.append(\"✅ Google Drive API: Connected\")\n",
+ " else:\n",
+ " status_messages.append(f\"❌ Google Drive API: {getattr(gpt_drive, 'drive_error', 'Not configured')}\")\n",
+ " \n",
+ " # Check OpenAI API\n",
+ " if gpt_drive.openai_initialized:\n",
+ " status_messages.append(\"✅ OpenAI API: Connected\")\n",
+ " else:\n",
+ " status_messages.append(f\"❌ OpenAI API: {getattr(gpt_drive, 'openai_error', 'Not configured')}\")\n",
+ " \n",
+ " return \"\\n\".join(status_messages)\n",
+ "\n",
+ "# Create Gradio interface\n",
+ "with gr.Blocks(title=\"Augusta's Anatomy Reading Assistant\", theme=gr.themes.Soft()) as app:\n",
+ " gr.Markdown(\"# 🤖 Augusta's Anatomy bot\")\n",
+ " gr.Markdown(\"Ask questions about your anatomy books using AI!\")\n",
+ " \n",
+ " with gr.Row():\n",
+ " with gr.Column(scale=2):\n",
+ " # Main query interface\n",
+ " with gr.Group():\n",
+ " gr.Markdown(\"### Ask a Question\")\n",
+ " query_input = gr.Textbox(\n",
+ " label=\"Your Question\",\n",
+ " placeholder=\"Ask me any question about your anatomy books?\",\n",
+ " lines=3\n",
+ " )\n",
+ " \n",
+ " search_terms_input = gr.Textbox(\n",
+ " label=\"Search Terms (optional)\",\n",
+ " placeholder=\"Enter comma-separated terms to search for specific files\",\n",
+ " lines=1\n",
+ " )\n",
+ " \n",
+ " submit_btn = gr.Button(\"Search & Ask\", variant=\"primary\", size=\"lg\")\n",
+ " \n",
+ " # Results section\n",
+ " with gr.Group():\n",
+ " gr.Markdown(\"### Answer\")\n",
+ " answer_output = gr.Textbox(\n",
+ " label=\"AI Response\",\n",
+ " lines=10,\n",
+ " interactive=False\n",
+ " )\n",
+ " \n",
+ " sources_output = gr.Textbox(\n",
+ " label=\"Sources\",\n",
+ " lines=3,\n",
+ " interactive=False\n",
+ " )\n",
+ " \n",
+ " with gr.Column(scale=1):\n",
+ " # Status and setup info\n",
+ " with gr.Group():\n",
+ " gr.Markdown(\"### System Status\")\n",
+ " status_btn = gr.Button(\"Check Status\", size=\"sm\")\n",
+ " status_output = gr.Textbox(\n",
+ " label=\"API Status\",\n",
+ " lines=4,\n",
+ " interactive=False\n",
+ " )\n",
+ " \n",
+ " with gr.Group():\n",
+ " gr.Markdown(\"### Setup Instructions\")\n",
+ " gr.Markdown(\"\"\"\n",
+ " **Important Notes:**\n",
+ " 1.Only documents shared with it, it can answer\n",
+ " \n",
+ " **File Types Supported:**\n",
+ " - Google Docs\n",
+ " - Google Sheets \n",
+ " - PDF files\n",
+ " - Text files\n",
+ " \n",
+ " **Tips:**\n",
+ " - Use specific search terms for better results\n",
+ " - The system searches the top 3 most relevant files\n",
+ " - Ask clear, specific questions for better answers\n",
+ " \"\"\")\n",
+ " \n",
+ " # Event handlers\n",
+ " submit_btn.click(\n",
+ " fn=process_user_query,\n",
+ " inputs=[query_input, search_terms_input],\n",
+ " outputs=[answer_output, sources_output]\n",
+ " )\n",
+ " \n",
+ " status_btn.click(\n",
+ " fn=check_setup,\n",
+ " outputs=status_output\n",
+ " )\n",
+ " \n",
+ " # Example queries\n",
+ " with gr.Row():\n",
+ " gr.Examples(\n",
+ " examples=[\n",
+ " [\"What is morbid Anatomy?\", \"morbid, Anatomy\"],\n",
+ " [\"The transmission of nerves from one neuron to another is as a result of what?\", \"neuron, nerves, Dr Clement\"],\n",
+ " ],\n",
+ " inputs=[query_input, search_terms_input],\n",
+ " )\n",
+ "\n",
+ "# Launch the app\n",
+ "if __name__ == \"__main__\":\n",
+ " app.launch(\n",
+ " share=True,\n",
+ " debug=True\n",
+ " )"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "a6fd9c8c-e8e9-4b1c-8d21-d7ea2c42303a",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "95c85a4f-470f-4858-8172-78d7f9d04d1a",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f237c114-7924-4074-9c11-c7ba13833293",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "a2f9c7ae-35bb-4261-adc4-f24c6ab5c8a1",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "aaa446b0-a14e-4c98-b466-f503a521f052",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "5770d683-7bfc-49e9-a3c4-a67060e27620",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "2ef7744c-1346-4692-ac28-013ae0e8c4ac",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "08643ace-f94f-4a4a-bbc1-3289b7fc29a1",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "70849fd3-6f4e-4c57-b780-bda53db83e14",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c18d5d20-439a-45a7-a847-25f659fd4a10",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "id": "634b9787-d493-46e5-8114-0851c6172ed6",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "🔍 Starting Google Drive API Diagnostic...\n",
+ "==================================================\n",
+ "\n",
+ "1️⃣ Checking service account file...\n",
+ "✅ Service account file is valid\n",
+ " 📧 Service account email: rag-base@rag-system-463320.iam.gserviceaccount.com\n",
+ " 🏗️ Project ID: rag-system-463320\n",
+ "\n",
+ "2️⃣ Checking credentials...\n",
+ "✅ Credentials created successfully\n",
+ "\n",
+ "3️⃣ Testing API connection...\n",
+ "✅ Successfully connected to Google Drive API\n",
+ " 👤 Connected as: rag-base@rag-system-463320.iam.gserviceaccount.com\n",
+ "\n",
+ "4️⃣ Checking basic permissions...\n",
+ "✅ Can access Drive API - found 0 files in test query\n",
+ "⚠️ No files found - this might mean:\n",
+ " • Service account has no shared files\n",
+ " • No files are shared with the service account\n",
+ "\n",
+ "5️⃣ Testing access to 'Blue berry' folder...\n",
+ "❌ Folder 'Blue berry' not found or not accessible\n",
+ "💡 Possible solutions:\n",
+ " • Make sure the folder exists in Google Drive\n",
+ " • Share the folder with your service account email\n",
+ " • Check folder name spelling (case sensitive)\n",
+ "\n",
+ "✅ All basic checks passed!\n"
+ ]
+ }
+ ],
+ "source": [
+ "import json\n",
+ "from google.auth.exceptions import RefreshError\n",
+ "from googleapiclient.errors import HttpError\n",
+ "\n",
+ "class GPTDriveTroubleshooter:\n",
+ " def __init__(self, service_account_file_path):\n",
+ " self.service_account_file = service_account_file_path\n",
+ " self.credentials = None\n",
+ " self.drive_service = None\n",
+ " \n",
+ " def run_full_diagnostic(self):\n",
+ " \"\"\"Run complete diagnostic check\"\"\"\n",
+ " print(\"🔍 Starting Google Drive API Diagnostic...\")\n",
+ " print(\"=\" * 50)\n",
+ " \n",
+ " # Step 1: Check service account file\n",
+ " if not self.check_service_account_file():\n",
+ " return False\n",
+ " \n",
+ " # Step 2: Check credentials\n",
+ " if not self.check_credentials():\n",
+ " return False\n",
+ " \n",
+ " # Step 3: Test API connection\n",
+ " if not self.test_api_connection():\n",
+ " return False\n",
+ " \n",
+ " # Step 4: Check permissions\n",
+ " if not self.check_basic_permissions():\n",
+ " return False\n",
+ " \n",
+ " # Step 5: Test folder access\n",
+ " self.test_folder_access()\n",
+ " \n",
+ " print(\"\\n✅ All basic checks passed!\")\n",
+ " return True\n",
+ " \n",
+ " def check_service_account_file(self):\n",
+ " \"\"\"Check if service account file exists and is valid\"\"\"\n",
+ " print(\"\\n1️⃣ Checking service account file...\")\n",
+ " \n",
+ " if not os.path.exists(self.service_account_file):\n",
+ " print(f\"❌ Service account file not found: {self.service_account_file}\")\n",
+ " print(\"💡 Make sure you've downloaded the JSON key file from Google Cloud Console\")\n",
+ " return False\n",
+ " \n",
+ " try:\n",
+ " with open(self.service_account_file, 'r') as f:\n",
+ " service_account_info = json.load(f)\n",
+ " \n",
+ " required_fields = ['type', 'project_id', 'private_key_id', 'private_key', 'client_email']\n",
+ " missing_fields = [field for field in required_fields if field not in service_account_info]\n",
+ " \n",
+ " if missing_fields:\n",
+ " print(f\"❌ Service account file missing required fields: {missing_fields}\")\n",
+ " return False\n",
+ " \n",
+ " print(f\"✅ Service account file is valid\")\n",
+ " print(f\" 📧 Service account email: {service_account_info['client_email']}\")\n",
+ " print(f\" 🏗️ Project ID: {service_account_info['project_id']}\")\n",
+ " \n",
+ " return True\n",
+ " \n",
+ " except json.JSONDecodeError:\n",
+ " print(\"❌ Service account file is not valid JSON\")\n",
+ " return False\n",
+ " except Exception as e:\n",
+ " print(f\"❌ Error reading service account file: {e}\")\n",
+ " return False\n",
+ " \n",
+ " def check_credentials(self):\n",
+ " \"\"\"Check if credentials can be created\"\"\"\n",
+ " print(\"\\n2️⃣ Checking credentials...\")\n",
+ " \n",
+ " try:\n",
+ " self.credentials = service_account.Credentials.from_service_account_file(\n",
+ " self.service_account_file,\n",
+ " scopes=['https://www.googleapis.com/auth/drive.readonly']\n",
+ " )\n",
+ " print(\"✅ Credentials created successfully\")\n",
+ " return True\n",
+ " \n",
+ " except Exception as e:\n",
+ " print(f\"❌ Failed to create credentials: {e}\")\n",
+ " print(\"💡 Check if your service account key file is corrupted\")\n",
+ " return False\n",
+ " \n",
+ " def test_api_connection(self):\n",
+ " \"\"\"Test basic API connection\"\"\"\n",
+ " print(\"\\n3️⃣ Testing API connection...\")\n",
+ " \n",
+ " try:\n",
+ " self.drive_service = build('drive', 'v3', credentials=self.credentials)\n",
+ " \n",
+ " # Try a simple API call\n",
+ " about = self.drive_service.about().get(fields=\"user, storageQuota\").execute()\n",
+ " print(\"✅ Successfully connected to Google Drive API\")\n",
+ " print(f\" 👤 Connected as: {about.get('user', {}).get('emailAddress', 'Unknown')}\")\n",
+ " \n",
+ " return True\n",
+ " \n",
+ " except HttpError as e:\n",
+ " print(f\"❌ HTTP Error connecting to API: {e}\")\n",
+ " if e.resp.status == 403:\n",
+ " print(\"💡 This is likely a permissions issue - check if Drive API is enabled\")\n",
+ " return False\n",
+ " except Exception as e:\n",
+ " print(f\"❌ Failed to connect to API: {e}\")\n",
+ " return False\n",
+ " \n",
+ " def check_basic_permissions(self):\n",
+ " \"\"\"Check basic file listing permissions\"\"\"\n",
+ " print(\"\\n4️⃣ Checking basic permissions...\")\n",
+ " \n",
+ " try:\n",
+ " # Try to list files (this should work with readonly access)\n",
+ " results = self.drive_service.files().list(\n",
+ " pageSize=1,\n",
+ " fields=\"files(id, name)\"\n",
+ " ).execute()\n",
+ " \n",
+ " files = results.get('files', [])\n",
+ " print(f\"✅ Can access Drive API - found {len(files)} files in test query\")\n",
+ " \n",
+ " if len(files) == 0:\n",
+ " print(\"⚠️ No files found - this might mean:\")\n",
+ " print(\" • Service account has no shared files\")\n",
+ " print(\" • No files are shared with the service account\")\n",
+ " \n",
+ " return True\n",
+ " \n",
+ " except HttpError as e:\n",
+ " print(f\"❌ Permission error: {e}\")\n",
+ " if e.resp.status == 403:\n",
+ " print(\"💡 Common causes:\")\n",
+ " print(\" • Google Drive API not enabled in Google Cloud Console\")\n",
+ " print(\" • Service account doesn't have proper permissions\")\n",
+ " return False\n",
+ " except Exception as e:\n",
+ " print(f\"❌ Error checking permissions: {e}\")\n",
+ " return False\n",
+ " \n",
+ " def test_folder_access(self, folder_name=\"Blue berry\"):\n",
+ " \"\"\"Test access to specific folder\"\"\"\n",
+ " print(f\"\\n5️⃣ Testing access to '{folder_name}' folder...\")\n",
+ " \n",
+ " try:\n",
+ " # Search for the folder\n",
+ " query = f\"name='{folder_name}' and mimeType='application/vnd.google-apps.folder' and trashed=false\"\n",
+ " results = self.drive_service.files().list(\n",
+ " q=query,\n",
+ " fields=\"files(id, name, owners, permissions)\"\n",
+ " ).execute()\n",
+ " \n",
+ " folders = results.get('files', [])\n",
+ " \n",
+ " if not folders:\n",
+ " print(f\"❌ Folder '{folder_name}' not found or not accessible\")\n",
+ " print(\"💡 Possible solutions:\")\n",
+ " print(\" • Make sure the folder exists in Google Drive\")\n",
+ " print(\" • Share the folder with your service account email\")\n",
+ " print(\" • Check folder name spelling (case sensitive)\")\n",
+ " return False\n",
+ " \n",
+ " folder = folders[0]\n",
+ " print(f\"✅ Found folder '{folder_name}'\")\n",
+ " print(f\" 📁 Folder ID: {folder['id']}\")\n",
+ " \n",
+ " # Test listing files in the folder\n",
+ " files_in_folder = self.drive_service.files().list(\n",
+ " q=f\"'{folder['id']}' in parents and trashed=false\",\n",
+ " fields=\"files(id, name, mimeType)\"\n",
+ " ).execute()\n",
+ " \n",
+ " files = files_in_folder.get('files', [])\n",
+ " print(f\" 📄 Contains {len(files)} files\")\n",
+ " \n",
+ " if files:\n",
+ " print(\" 📝 Sample files:\")\n",
+ " for file in files[:3]: # Show first 3 files\n",
+ " print(f\" • {file['name']} ({file['mimeType']})\")\n",
+ " \n",
+ " return True\n",
+ " \n",
+ " except HttpError as e:\n",
+ " print(f\"❌ HTTP Error accessing folder: {e}\")\n",
+ " return False\n",
+ " except Exception as e:\n",
+ " print(f\"❌ Error accessing folder: {e}\")\n",
+ " return False\n",
+ " \n",
+ " def check_file_permissions(self, file_id):\n",
+ " \"\"\"Check permissions for a specific file\"\"\"\n",
+ " print(f\"\\n🔍 Checking permissions for file ID: {file_id}\")\n",
+ " \n",
+ " try:\n",
+ " file_info = self.drive_service.files().get(\n",
+ " fileId=file_id,\n",
+ " fields=\"id, name, mimeType, owners, permissions, capabilities\"\n",
+ " ).execute()\n",
+ " \n",
+ " print(f\"✅ File: {file_info['name']}\")\n",
+ " print(f\" 🔗 Type: {file_info['mimeType']}\")\n",
+ " print(f\" 👤 Owner: {file_info.get('owners', [{}])[0].get('emailAddress', 'Unknown')}\")\n",
+ " \n",
+ " capabilities = file_info.get('capabilities', {})\n",
+ " print(f\" 📖 Can read: {capabilities.get('canDownload', False)}\")\n",
+ " print(f\" 📤 Can export: {capabilities.get('canExport', False)}\")\n",
+ " \n",
+ " except HttpError as e:\n",
+ " print(f\"❌ Cannot access file: {e}\")\n",
+ " except Exception as e:\n",
+ " print(f\"❌ Error: {e}\")\n",
+ " \n",
+ " def get_sharing_instructions(self):\n",
+ " \"\"\"Provide step-by-step sharing instructions\"\"\"\n",
+ " print(\"\\n📋 HOW TO SHARE FOLDER WITH SERVICE ACCOUNT:\")\n",
+ " print(\"=\" * 50)\n",
+ " \n",
+ " if self.credentials:\n",
+ " service_email = self.credentials.service_account_email\n",
+ " print(f\"1. Copy this service account email: {service_email}\")\n",
+ " else:\n",
+ " print(\"1. Find your service account email in the JSON key file (client_email field)\")\n",
+ " \n",
+ " print(\"2. Open Google Drive in your browser\")\n",
+ " print(\"3. Right-click on your 'Blue berry' folder\")\n",
+ " print(\"4. Select 'Share'\")\n",
+ " print(\"5. Paste the service account email\")\n",
+ " print(\"6. Set permission to 'Viewer' or 'Editor'\")\n",
+ " print(\"7. Click 'Send' (you can uncheck 'Notify people')\")\n",
+ " print(\"8. Wait a few minutes for permissions to propagate\")\n",
+ " \n",
+ " def run_connection_test(self):\n",
+ " \"\"\"Quick connection test\"\"\"\n",
+ " print(\"🚀 Quick Connection Test\")\n",
+ " print(\"-\" * 30)\n",
+ " \n",
+ " try:\n",
+ " self.credentials = service_account.Credentials.from_service_account_file(\n",
+ " self.service_account_file,\n",
+ " scopes=['https://www.googleapis.com/auth/drive.readonly']\n",
+ " )\n",
+ " \n",
+ " service = build('drive', 'v3', credentials=self.credentials)\n",
+ " \n",
+ " # Test basic query\n",
+ " results = service.files().list(pageSize=5).execute()\n",
+ " files = results.get('files', [])\n",
+ " \n",
+ " print(f\"✅ Connected! Found {len(files)} accessible files\")\n",
+ " print(f\"📧 Service account: {self.credentials.service_account_email}\")\n",
+ " \n",
+ " return True\n",
+ " \n",
+ " except Exception as e:\n",
+ " print(f\"❌ Connection failed: {e}\")\n",
+ " return False\n",
+ "\n",
+ "# Usage Examples\n",
+ "def troubleshoot_drive_access():\n",
+ " \"\"\"Main troubleshooting function\"\"\"\n",
+ " service_account_file = os.getenv('GOOGLE_SERVICE_ACCOUNT_FILE')\n",
+ " \n",
+ " if not service_account_file:\n",
+ " print(\"❌ GOOGLE_SERVICE_ACCOUNT_FILE environment variable not set\")\n",
+ " print(\"💡 Add this to your .env file:\")\n",
+ " print(\"GOOGLE_SERVICE_ACCOUNT_FILE=path/to/your/service-account-key.json\")\n",
+ " return\n",
+ " \n",
+ " troubleshooter = GPTDriveTroubleshooter(service_account_file)\n",
+ " \n",
+ " # Run full diagnostic\n",
+ " success = troubleshooter.run_full_diagnostic()\n",
+ " \n",
+ " if not success:\n",
+ " print(\"\\n\" + \"=\"*50)\n",
+ " troubleshooter.get_sharing_instructions()\n",
+ " \n",
+ " return success\n",
+ "\n",
+ "# Quick test function\n",
+ "def quick_test():\n",
+ " \"\"\"Quick test to verify everything works\"\"\"\n",
+ " service_account_file = os.getenv('GOOGLE_SERVICE_ACCOUNT_FILE')\n",
+ " troubleshooter = GPTDriveTroubleshooter(service_account_file)\n",
+ " return troubleshooter.run_connection_test()\n",
+ "\n",
+ "if __name__ == \"__main__\":\n",
+ " # Uncomment the test you want to run:\n",
+ " \n",
+ " # Full diagnostic (recommended for first-time setup)\n",
+ " troubleshoot_drive_access()\n",
+ " \n",
+ " # Quick test (for regular checks)\n",
+ " # quick_test()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6b336789-d402-455d-a631-26e987d79ed6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "troubleshooter = GPTDriveTroubleshooter(GOOGLE_SERVICE_ACCOUNT_FILE)\n",
+ "troubleshooter.test_folder_access(\"Blue berry\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e2786c67-215e-46b0-b3ca-2c3176bd8971",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Add this test function to verify access\n",
+ "def test_folder_access():\n",
+ " integration = GPTDriveIntegration()\n",
+ " folder_id = integration.find_folder_by_name(\"Blue berry\")\n",
+ " if folder_id:\n",
+ " print(\"✅ Successfully found 'Blue berry' folder!\")\n",
+ " \n",
+ " # List files in the folder\n",
+ " results = integration.drive_service.files().list(\n",
+ " q=f\"'{folder_id}' in parents and trashed=false\",\n",
+ " fields=\"files(id, name, mimeType)\"\n",
+ " ).execute()\n",
+ " \n",
+ " files = results.get('files', [])\n",
+ " print(f\"Found {len(files)} files in the folder:\")\n",
+ " for file in files[:5]: # Show first 5 files\n",
+ " print(f\" - {file['name']} ({file['mimeType']})\")\n",
+ " else:\n",
+ " print(\"❌ Could not access 'Blue berry' folder\")\n",
+ " print(\"Make sure you've shared the folder with your service account\")\n",
+ "\n",
+ "# Run this test first\n",
+ "test_folder_access()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c3dede9f-5e01-436d-a7b7-905e1646baf9",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b933c8b6-add6-40fc-827f-e5e07447ac00",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "#Troubleshooting"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 32,
+ "id": "b63a1f4b-1315-44fe-ba84-93fb1c2655cc",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "🔍 Searching for 'Blue Berry' folder...\n",
+ "Total folders found: 2\n",
+ "\n",
+ "✅ Found 1 'Blue Berry' folder(s):\n",
+ "📁 Anatomy Books \n",
+ " Full Path: Anatomy Books \n",
+ " Folder ID: 125NdiCL7moQsNYWRuHojVM7If88Bxh0q\n",
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "import os\n",
+ "from google.oauth2 import service_account\n",
+ "from googleapiclient.discovery import build\n",
+ "\n",
+ "class DrivefolderLister:\n",
+ " def __init__(self):\n",
+ " # Initialize Google Drive API\n",
+ " self.credentials = service_account.Credentials.from_service_account_file(\n",
+ " os.getenv('GOOGLE_SERVICE_ACCOUNT_FILE'),\n",
+ " scopes=['https://www.googleapis.com/auth/drive.readonly']\n",
+ " )\n",
+ " self.drive_service = build('drive', 'v3', credentials=self.credentials)\n",
+ " \n",
+ " def get_all_folders(self):\n",
+ " \"\"\"Get ALL folders in the Google Drive\"\"\"\n",
+ " try:\n",
+ " # Query to get all folders (not trashed)\n",
+ " query = \"mimeType='application/vnd.google-apps.folder' and trashed=false\"\n",
+ " \n",
+ " all_folders = []\n",
+ " page_token = None\n",
+ " \n",
+ " while True:\n",
+ " results = self.drive_service.files().list(\n",
+ " q=query,\n",
+ " fields=\"nextPageToken, files(id, name, parents)\",\n",
+ " pageSize=1000, # Maximum allowed\n",
+ " pageToken=page_token\n",
+ " ).execute()\n",
+ " \n",
+ " folders = results.get('files', [])\n",
+ " all_folders.extend(folders)\n",
+ " \n",
+ " page_token = results.get('nextPageToken')\n",
+ " if not page_token:\n",
+ " break\n",
+ " \n",
+ " print(f\"Total folders found: {len(all_folders)}\")\n",
+ " return all_folders\n",
+ " \n",
+ " except Exception as e:\n",
+ " print(f\"Error retrieving folders: {e}\")\n",
+ " return []\n",
+ " \n",
+ " def build_folder_tree(self, folders):\n",
+ " \"\"\"Build a tree structure from the flat list of folders\"\"\"\n",
+ " # Create a dictionary for quick lookup\n",
+ " folder_dict = {folder['id']: folder for folder in folders}\n",
+ " \n",
+ " # Add root folder\n",
+ " folder_dict['root'] = {'id': 'root', 'name': 'My Drive', 'parents': []}\n",
+ " \n",
+ " # Build the tree structure\n",
+ " tree = {}\n",
+ " \n",
+ " def build_path(folder_id, visited=None):\n",
+ " if visited is None:\n",
+ " visited = set()\n",
+ " \n",
+ " if folder_id in visited: # Prevent infinite loops\n",
+ " return \"CIRCULAR_REFERENCE\"\n",
+ " \n",
+ " visited.add(folder_id)\n",
+ " \n",
+ " if folder_id not in folder_dict:\n",
+ " return \"UNKNOWN\"\n",
+ " \n",
+ " folder = folder_dict[folder_id]\n",
+ " \n",
+ " if folder_id == 'root':\n",
+ " return \"My Drive\"\n",
+ " \n",
+ " parents = folder.get('parents', [])\n",
+ " if not parents:\n",
+ " return folder['name']\n",
+ " \n",
+ " parent_path = build_path(parents[0], visited.copy())\n",
+ " return f\"{parent_path}/{folder['name']}\"\n",
+ " \n",
+ " # Build paths for all folders\n",
+ " folder_paths = []\n",
+ " for folder in folders:\n",
+ " path = build_path(folder['id'])\n",
+ " folder_paths.append({\n",
+ " 'name': folder['name'],\n",
+ " 'id': folder['id'],\n",
+ " 'path': path\n",
+ " })\n",
+ " \n",
+ " return folder_paths\n",
+ " \n",
+ " def search_folder_by_name(self, folder_name, folders_with_paths):\n",
+ " \"\"\"Search for folders by name (case-insensitive)\"\"\"\n",
+ " matches = []\n",
+ " search_name = folder_name.lower()\n",
+ " \n",
+ " for folder in folders_with_paths:\n",
+ " if search_name in folder['name'].lower():\n",
+ " matches.append(folder)\n",
+ " \n",
+ " return matches\n",
+ " \n",
+ " def display_all_folders(self, folders_with_paths, search_term=None):\n",
+ " \"\"\"Display all folders in a readable format\"\"\"\n",
+ " if search_term:\n",
+ " print(f\"\\n=== Searching for folders containing '{search_term}' ===\")\n",
+ " matches = self.search_folder_by_name(search_term, folders_with_paths)\n",
+ " if matches:\n",
+ " print(f\"Found {len(matches)} matching folders:\")\n",
+ " for folder in matches:\n",
+ " print(f\"📁 {folder['name']}\")\n",
+ " print(f\" Path: {folder['path']}\")\n",
+ " print(f\" ID: {folder['id']}\")\n",
+ " print()\n",
+ " else:\n",
+ " print(f\"No folders found containing '{search_term}'\")\n",
+ " else:\n",
+ " print(f\"\\n=== All {len(folders_with_paths)} folders in your Google Drive ===\")\n",
+ " \n",
+ " # Sort by path for better readability\n",
+ " sorted_folders = sorted(folders_with_paths, key=lambda x: x['path'])\n",
+ " \n",
+ " for folder in sorted_folders:\n",
+ " print(f\"📁 {folder['path']}\")\n",
+ " # print(f\" ID: {folder['id']}\") # Uncomment if you need IDs\n",
+ " \n",
+ " def find_blue_berry_folder(self):\n",
+ " \"\"\"Specifically look for the Anatomy Books folder\"\"\"\n",
+ " print(\"🔍 Searching for 'Blue Berry' folder...\")\n",
+ " \n",
+ " folders = self.get_all_folders()\n",
+ " if not folders:\n",
+ " print(\"No folders found or error occurred.\")\n",
+ " return\n",
+ " \n",
+ " folders_with_paths = self.build_folder_tree(folders)\n",
+ " \n",
+ " # Search for Anatomy Books specifically\n",
+ " blue_berry_matches = self.search_folder_by_name(\"Anatomy Books\", folders_with_paths)\n",
+ " \n",
+ " if blue_berry_matches:\n",
+ " print(f\"\\n✅ Found {len(blue_berry_matches)} 'Blue Berry' folder(s):\")\n",
+ " for folder in blue_berry_matches:\n",
+ " print(f\"📁 {folder['name']}\")\n",
+ " print(f\" Full Path: {folder['path']}\")\n",
+ " print(f\" Folder ID: {folder['id']}\")\n",
+ " print()\n",
+ " else:\n",
+ " print(\"\\n❌ No 'Blue Berry' folder found.\")\n",
+ " print(\"Let me show you all folders to help you locate it:\")\n",
+ " \n",
+ " # Show all folders if Blue Berry not found\n",
+ " self.display_all_folders(folders_with_paths)\n",
+ " \n",
+ " def interactive_folder_search(self):\n",
+ " \"\"\"Interactive search for any folder\"\"\"\n",
+ " print(\"📂 Google Drive Folder Explorer\")\n",
+ " print(\"=\" * 40)\n",
+ " \n",
+ " folders = self.get_all_folders()\n",
+ " if not folders:\n",
+ " print(\"No folders found or error occurred.\")\n",
+ " return\n",
+ " \n",
+ " folders_with_paths = self.build_folder_tree(folders)\n",
+ " \n",
+ " while True:\n",
+ " print(\"\\nOptions:\")\n",
+ " print(\"1. Search for a specific folder\")\n",
+ " print(\"2. Show all folders\")\n",
+ " print(\"3. Find 'Blue Berry' folder\")\n",
+ " print(\"4. Exit\")\n",
+ " \n",
+ " choice = input(\"\\nEnter your choice (1-4): \").strip()\n",
+ " \n",
+ " if choice == '1':\n",
+ " search_term = input(\"Enter folder name to search: \").strip()\n",
+ " if search_term:\n",
+ " self.display_all_folders(folders_with_paths, search_term)\n",
+ " \n",
+ " elif choice == '2':\n",
+ " self.display_all_folders(folders_with_paths)\n",
+ " \n",
+ " elif choice == '3':\n",
+ " blue_berry_matches = self.search_folder_by_name(\"blue berry\", folders_with_paths)\n",
+ " if blue_berry_matches:\n",
+ " print(f\"\\n✅ Found 'Blue Berry' folder(s):\")\n",
+ " for folder in blue_berry_matches:\n",
+ " print(f\"📁 {folder['name']} -> {folder['path']}\")\n",
+ " else:\n",
+ " print(\"\\n❌ 'Blue Berry' folder not found in your Drive.\")\n",
+ " \n",
+ " elif choice == '4':\n",
+ " print(\"Goodbye!\")\n",
+ " break\n",
+ " \n",
+ " else:\n",
+ " print(\"Invalid choice. Please try again.\")\n",
+ "\n",
+ "def main():\n",
+ " \"\"\"Main function to run the folder lister\"\"\"\n",
+ " try:\n",
+ " lister = DrivefolderLister()\n",
+ " \n",
+ " # Quick search for Blue Berry folder\n",
+ " lister.find_blue_berry_folder()\n",
+ " \n",
+ " # Uncomment the line below for interactive mode\n",
+ " # lister.interactive_folder_search()\n",
+ " \n",
+ " except Exception as e:\n",
+ " print(f\"Error initializing Drive connection: {e}\")\n",
+ " print(\"Make sure your GOOGLE_SERVICE_ACCOUNT_FILE environment variable is set correctly.\")\n",
+ "\n",
+ "if __name__ == \"__main__\":\n",
+ " main()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "29a61039-9043-44d5-94b1-4847350b2200",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 31,
+ "id": "7350d687-f76e-46f4-a30b-0518e5b8236e",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "🚀 Google Drive API Diagnostic Tool\n",
+ "==================================================\n",
+ "🔧 Testing Environment Variables...\n",
+ "----------------------------------------\n",
+ "✅ GOOGLE_SERVICE_ACCOUNT_FILE: C:/Users/Uche Buzz/myprojects/RAG/rag-system-463320-f292991d0516.json\n",
+ "✅ Service account file exists\n",
+ "✅ Service account file is valid JSON\n",
+ "✅ All required fields present in service account file\n",
+ "📧 Service account email: rag-base@rag-system-463320.iam.gserviceaccount.com\n",
+ "✅ OPENAI_API_KEY: ************************************************************************************************************************************************************K1OkRRkA\n",
+ "\n",
+ "🔑 Testing Credentials Loading...\n",
+ "----------------------------------------\n",
+ "\n",
+ "Testing scope set 1: ['https://www.googleapis.com/auth/drive.readonly']\n",
+ "✅ Credentials loaded successfully with scopes: ['https://www.googleapis.com/auth/drive.readonly']\n",
+ "\n",
+ "🔧 Testing Drive Service Creation...\n",
+ "----------------------------------------\n",
+ "✅ Google Drive service created successfully\n",
+ "\n",
+ "📡 Testing Basic API Call...\n",
+ "----------------------------------------\n",
+ "✅ API call successful!\n",
+ "📧 Connected as: rag-base@rag-system-463320.iam.gserviceaccount.com\n",
+ "👤 Display name: rag-base@rag-system-463320.iam.gserviceaccount.com\n",
+ "\n",
+ "🏠 Testing Root Folder Access...\n",
+ "----------------------------------------\n",
+ "✅ Root folder accessible\n",
+ "📁 Root folder name: My Drive\n",
+ "📄 Items in root folder: 0\n",
+ "\n",
+ "📁 Testing File Listing...\n",
+ "----------------------------------------\n",
+ "Test 1: Listing all files (including documents)...\n",
+ "✅ Found 7 files total\n",
+ "📄 First few files:\n",
+ " - Neuro Note Dr Clement.docx (application/vnd.openxmlformats-officedocument.wordprocessingml.document)\n",
+ " - Morbid Anatomy - ANA 3107.pdf (application/pdf)\n",
+ " - ANT & POST TRIANGLES OF THE NECK.pdf (application/pdf)\n",
+ " - Anatomy Books (application/vnd.google-apps.folder)\n",
+ " - Blue Berry (application/vnd.google-apps.folder)\n",
+ "\n",
+ "Test 2: Listing folders only...\n",
+ "✅ Found 2 folders\n",
+ "📁 Folders found:\n",
+ " - Anatomy Books (ID: 125NdiCL7moQsNYWRuHojVM7If88Bxh0q)\n",
+ " - Blue Berry (ID: 1AYaS0yt_srFlgdE4mSNlqA6FLm10rdt4)\n",
+ "\n",
+ "✅ All diagnostic tests passed!\n",
+ "🎉 Your Google Drive API connection is working correctly!\n"
+ ]
+ }
+ ],
+ "source": [
+ "import os\n",
+ "from google.oauth2 import service_account\n",
+ "from googleapiclient.discovery import build\n",
+ "from googleapiclient.errors import HttpError\n",
+ "import json\n",
+ "\n",
+ "class DriveConnectionDiagnostic:\n",
+ " def __init__(self):\n",
+ " self.credentials = None\n",
+ " self.drive_service = None\n",
+ " self.setup_success = False\n",
+ " \n",
+ " def test_environment_variables(self):\n",
+ " \"\"\"Test if environment variables are set correctly\"\"\"\n",
+ " print(\"🔧 Testing Environment Variables...\")\n",
+ " print(\"-\" * 40)\n",
+ " \n",
+ " service_account_file = os.getenv('GOOGLE_SERVICE_ACCOUNT_FILE')\n",
+ " openai_key = os.getenv('OPENAI_API_KEY')\n",
+ " \n",
+ " if service_account_file:\n",
+ " print(f\"✅ GOOGLE_SERVICE_ACCOUNT_FILE: {service_account_file}\")\n",
+ " \n",
+ " # Check if file exists\n",
+ " if os.path.exists(service_account_file):\n",
+ " print(f\"✅ Service account file exists\")\n",
+ " \n",
+ " # Check if file is readable\n",
+ " try:\n",
+ " with open(service_account_file, 'r') as f:\n",
+ " service_data = json.load(f)\n",
+ " print(f\"✅ Service account file is valid JSON\")\n",
+ " \n",
+ " # Check required fields\n",
+ " required_fields = ['type', 'project_id', 'private_key_id', 'private_key', 'client_email']\n",
+ " missing_fields = [field for field in required_fields if field not in service_data]\n",
+ " \n",
+ " if missing_fields:\n",
+ " print(f\"❌ Missing required fields in service account file: {missing_fields}\")\n",
+ " return False\n",
+ " else:\n",
+ " print(f\"✅ All required fields present in service account file\")\n",
+ " print(f\"📧 Service account email: {service_data.get('client_email')}\")\n",
+ " \n",
+ " except json.JSONDecodeError:\n",
+ " print(f\"❌ Service account file is not valid JSON\")\n",
+ " return False\n",
+ " except Exception as e:\n",
+ " print(f\"❌ Error reading service account file: {e}\")\n",
+ " return False\n",
+ " \n",
+ " else:\n",
+ " print(f\"❌ Service account file does not exist at: {service_account_file}\")\n",
+ " return False\n",
+ " else:\n",
+ " print(f\"❌ GOOGLE_SERVICE_ACCOUNT_FILE environment variable not set\")\n",
+ " return False\n",
+ " \n",
+ " if openai_key:\n",
+ " print(f\"✅ OPENAI_API_KEY: {'*' * (len(openai_key) - 8) + openai_key[-8:]}\")\n",
+ " else:\n",
+ " print(f\"⚠️ OPENAI_API_KEY not set (not required for folder listing)\")\n",
+ " \n",
+ " return True\n",
+ " \n",
+ " def test_credentials_loading(self):\n",
+ " \"\"\"Test if credentials can be loaded\"\"\"\n",
+ " print(\"\\n🔑 Testing Credentials Loading...\")\n",
+ " print(\"-\" * 40)\n",
+ " \n",
+ " try:\n",
+ " service_account_file = os.getenv('GOOGLE_SERVICE_ACCOUNT_FILE')\n",
+ " \n",
+ " # Try different scope combinations\n",
+ " scopes_to_test = [\n",
+ " ['https://www.googleapis.com/auth/drive.readonly'],\n",
+ " ['https://www.googleapis.com/auth/drive'],\n",
+ " ['https://www.googleapis.com/auth/drive.metadata.readonly'],\n",
+ " ['https://www.googleapis.com/auth/drive.file']\n",
+ " ]\n",
+ " \n",
+ " for i, scopes in enumerate(scopes_to_test):\n",
+ " try:\n",
+ " print(f\"\\nTesting scope set {i+1}: {scopes}\")\n",
+ " self.credentials = service_account.Credentials.from_service_account_file(\n",
+ " service_account_file,\n",
+ " scopes=scopes\n",
+ " )\n",
+ " print(f\"✅ Credentials loaded successfully with scopes: {scopes}\")\n",
+ " return True\n",
+ " except Exception as e:\n",
+ " print(f\"❌ Failed to load credentials with scopes {scopes}: {e}\")\n",
+ " \n",
+ " return False\n",
+ " \n",
+ " except Exception as e:\n",
+ " print(f\"❌ Error loading credentials: {e}\")\n",
+ " return False\n",
+ " \n",
+ " def test_drive_service_creation(self):\n",
+ " \"\"\"Test if Drive service can be created\"\"\"\n",
+ " print(\"\\n🔧 Testing Drive Service Creation...\")\n",
+ " print(\"-\" * 40)\n",
+ " \n",
+ " try:\n",
+ " if not self.credentials:\n",
+ " print(\"❌ No credentials available\")\n",
+ " return False\n",
+ " \n",
+ " self.drive_service = build('drive', 'v3', credentials=self.credentials)\n",
+ " print(\"✅ Google Drive service created successfully\")\n",
+ " return True\n",
+ " \n",
+ " except Exception as e:\n",
+ " print(f\"❌ Error creating Drive service: {e}\")\n",
+ " return False\n",
+ " \n",
+ " def test_basic_api_call(self):\n",
+ " \"\"\"Test basic API functionality\"\"\"\n",
+ " print(\"\\n📡 Testing Basic API Call...\")\n",
+ " print(\"-\" * 40)\n",
+ " \n",
+ " try:\n",
+ " if not self.drive_service:\n",
+ " print(\"❌ No Drive service available\")\n",
+ " return False\n",
+ " \n",
+ " # Test getting user info\n",
+ " about = self.drive_service.about().get(fields=\"user\").execute()\n",
+ " user_info = about.get('user', {})\n",
+ " print(f\"✅ API call successful!\")\n",
+ " print(f\"📧 Connected as: {user_info.get('emailAddress', 'Unknown')}\")\n",
+ " print(f\"👤 Display name: {user_info.get('displayName', 'Unknown')}\")\n",
+ " \n",
+ " return True\n",
+ " \n",
+ " except HttpError as e:\n",
+ " print(f\"❌ HTTP Error: {e}\")\n",
+ " if e.resp.status == 403:\n",
+ " print(\" This might be a permissions issue. Check:\")\n",
+ " print(\" 1. Is the service account enabled?\")\n",
+ " print(\" 2. Does it have the right permissions?\")\n",
+ " print(\" 3. Is the Google Drive API enabled in your project?\")\n",
+ " return False\n",
+ " except Exception as e:\n",
+ " print(f\"❌ Error making API call: {e}\")\n",
+ " return False\n",
+ " \n",
+ " def test_file_listing(self):\n",
+ " \"\"\"Test different file listing approaches\"\"\"\n",
+ " print(\"\\n📁 Testing File Listing...\")\n",
+ " print(\"-\" * 40)\n",
+ " \n",
+ " if not self.drive_service:\n",
+ " print(\"❌ No Drive service available\")\n",
+ " return False\n",
+ " \n",
+ " # Test 1: List any files (not just folders)\n",
+ " try:\n",
+ " print(\"Test 1: Listing all files (including documents)...\")\n",
+ " results = self.drive_service.files().list(\n",
+ " q=\"trashed=false\",\n",
+ " fields=\"files(id, name, mimeType)\",\n",
+ " pageSize=10\n",
+ " ).execute()\n",
+ " \n",
+ " files = results.get('files', [])\n",
+ " print(f\"✅ Found {len(files)} files total\")\n",
+ " \n",
+ " if files:\n",
+ " print(\"📄 First few files:\")\n",
+ " for file in files[:5]:\n",
+ " print(f\" - {file['name']} ({file['mimeType']})\")\n",
+ " \n",
+ " except Exception as e:\n",
+ " print(f\"❌ Error listing files: {e}\")\n",
+ " return False\n",
+ " \n",
+ " # Test 2: List only folders\n",
+ " try:\n",
+ " print(f\"\\nTest 2: Listing folders only...\")\n",
+ " results = self.drive_service.files().list(\n",
+ " q=\"mimeType='application/vnd.google-apps.folder' and trashed=false\",\n",
+ " fields=\"files(id, name, parents)\",\n",
+ " pageSize=10\n",
+ " ).execute()\n",
+ " \n",
+ " folders = results.get('files', [])\n",
+ " print(f\"✅ Found {len(folders)} folders\")\n",
+ " \n",
+ " if folders:\n",
+ " print(\"📁 Folders found:\")\n",
+ " for folder in folders:\n",
+ " print(f\" - {folder['name']} (ID: {folder['id']})\")\n",
+ " else:\n",
+ " print(\"⚠️ No folders found - this might indicate:\")\n",
+ " print(\" 1. Your Google Drive is empty\")\n",
+ " print(\" 2. The service account doesn't have access to your personal Drive\")\n",
+ " print(\" 3. You need to share folders with the service account\")\n",
+ " \n",
+ " return len(folders) > 0\n",
+ " \n",
+ " except Exception as e:\n",
+ " print(f\"❌ Error listing folders: {e}\")\n",
+ " return False\n",
+ " \n",
+ " def test_root_access(self):\n",
+ " \"\"\"Test access to root folder\"\"\"\n",
+ " print(\"\\n🏠 Testing Root Folder Access...\")\n",
+ " print(\"-\" * 40)\n",
+ " \n",
+ " try:\n",
+ " if not self.drive_service:\n",
+ " print(\"❌ No Drive service available\")\n",
+ " return False\n",
+ " \n",
+ " # Try to get root folder info\n",
+ " root_info = self.drive_service.files().get(\n",
+ " fileId='root',\n",
+ " fields=\"id, name, mimeType\"\n",
+ " ).execute()\n",
+ " \n",
+ " print(f\"✅ Root folder accessible\")\n",
+ " print(f\"📁 Root folder name: {root_info.get('name', 'My Drive')}\")\n",
+ " \n",
+ " # Try to list contents of root\n",
+ " results = self.drive_service.files().list(\n",
+ " q=\"'root' in parents and trashed=false\",\n",
+ " fields=\"files(id, name, mimeType)\",\n",
+ " pageSize=10\n",
+ " ).execute()\n",
+ " \n",
+ " root_contents = results.get('files', [])\n",
+ " print(f\"📄 Items in root folder: {len(root_contents)}\")\n",
+ " \n",
+ " if root_contents:\n",
+ " print(\"🔍 Root folder contents:\")\n",
+ " for item in root_contents[:5]:\n",
+ " item_type = \"📁\" if \"folder\" in item['mimeType'] else \"📄\"\n",
+ " print(f\" {item_type} {item['name']}\")\n",
+ " \n",
+ " return True\n",
+ " \n",
+ " except Exception as e:\n",
+ " print(f\"❌ Error accessing root folder: {e}\")\n",
+ " return False\n",
+ " \n",
+ " def run_full_diagnostic(self):\n",
+ " \"\"\"Run complete diagnostic\"\"\"\n",
+ " print(\"🚀 Google Drive API Diagnostic Tool\")\n",
+ " print(\"=\" * 50)\n",
+ " \n",
+ " # Step 1: Environment variables\n",
+ " if not self.test_environment_variables():\n",
+ " print(\"\\n❌ Environment setup failed. Please check your service account file.\")\n",
+ " return False\n",
+ " \n",
+ " # Step 2: Credentials\n",
+ " if not self.test_credentials_loading():\n",
+ " print(\"\\n❌ Credentials loading failed.\")\n",
+ " return False\n",
+ " \n",
+ " # Step 3: Service creation\n",
+ " if not self.test_drive_service_creation():\n",
+ " print(\"\\n❌ Drive service creation failed.\")\n",
+ " return False\n",
+ " \n",
+ " # Step 4: Basic API call\n",
+ " if not self.test_basic_api_call():\n",
+ " print(\"\\n❌ Basic API call failed.\")\n",
+ " return False\n",
+ " \n",
+ " # Step 5: Root access\n",
+ " if not self.test_root_access():\n",
+ " print(\"\\n❌ Root folder access failed.\")\n",
+ " return False\n",
+ " \n",
+ " # Step 6: File listing\n",
+ " if not self.test_file_listing():\n",
+ " print(\"\\n❌ File listing failed or no folders found.\")\n",
+ " print(\"\\n🔧 SOLUTION SUGGESTIONS:\")\n",
+ " print(\"1. If you're using a service account, you need to SHARE folders with it\")\n",
+ " print(\"2. Share your 'Blue Berry' folder with the service account email\")\n",
+ " print(\"3. Or consider using OAuth2 instead of service account for personal Drive access\")\n",
+ " return False\n",
+ " \n",
+ " print(\"\\n✅ All diagnostic tests passed!\")\n",
+ " print(\"🎉 Your Google Drive API connection is working correctly!\")\n",
+ " return True\n",
+ " \n",
+ " def show_service_account_sharing_instructions(self):\n",
+ " \"\"\"Show instructions for sharing with service account\"\"\"\n",
+ " print(\"\\n📋 SERVICE ACCOUNT SHARING INSTRUCTIONS:\")\n",
+ " print(\"=\" * 50)\n",
+ " print(\"If you're using a service account, you need to share folders with it:\")\n",
+ " print()\n",
+ " print(\"1. Open Google Drive in your browser\")\n",
+ " print(\"2. Find the folder you want to access (e.g., 'Blue Berry')\")\n",
+ " print(\"3. Right-click the folder → 'Share'\")\n",
+ " print(\"4. Add the service account email address\")\n",
+ " print(\"5. Give it 'Viewer' or 'Editor' permissions\")\n",
+ " print(\"6. Click 'Send'\")\n",
+ " print()\n",
+ " \n",
+ " if self.credentials:\n",
+ " try:\n",
+ " service_account_file = os.getenv('GOOGLE_SERVICE_ACCOUNT_FILE')\n",
+ " with open(service_account_file, 'r') as f:\n",
+ " service_data = json.load(f)\n",
+ " email = service_data.get('client_email')\n",
+ " print(f\"📧 Your service account email: {email}\")\n",
+ " print(\" ^ Share your folders with this email address\")\n",
+ " except:\n",
+ " print(\"❌ Could not read service account email\")\n",
+ "\n",
+ "def main():\n",
+ " diagnostic = DriveConnectionDiagnostic()\n",
+ " success = diagnostic.run_full_diagnostic()\n",
+ " \n",
+ " if not success:\n",
+ " diagnostic.show_service_account_sharing_instructions()\n",
+ "\n",
+ "if __name__ == \"__main__\":\n",
+ " main()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e3374b17-d2fa-4c80-a70b-76b8bf94c702",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "#flask"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 30,
+ "id": "c8ac4c93-8b36-49d2-b8e1-efb7d1c4b104",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " * Serving Flask app '__main__'\n",
+ " * Debug mode: on\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.\n",
+ " * Running on http://127.0.0.1:5000\n",
+ "Press CTRL+C to quit\n",
+ " * Restarting with stat\n"
+ ]
+ },
+ {
+ "ename": "SystemExit",
+ "evalue": "1",
+ "output_type": "error",
+ "traceback": [
+ "An exception has occurred, use %tb to see the full traceback.\n",
+ "\u001b[31mSystemExit\u001b[39m\u001b[31m:\u001b[39m 1\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "C:\\Users\\Uche Buzz\\anaconda3\\envs\\RAG\\Lib\\site-packages\\IPython\\core\\interactiveshell.py:3680: UserWarning: To exit: use 'exit', 'quit', or Ctrl-D.\n",
+ " warn(\"To exit: use 'exit', 'quit', or Ctrl-D.\", stacklevel=1)\n"
+ ]
+ }
+ ],
+ "source": [
+ "from flask import Flask, request, jsonify, render_template_string\n",
+ "\n",
+ "app = Flask(__name__)\n",
+ "integration = GPTDriveIntegration()\n",
+ "\n",
+ "HTML_TEMPLATE = \"\"\"\n",
+ "\n",
+ "\n",
+ "\n",
+ " GPT-Drive Integration\n",
+ " \n",
+ "\n",
+ "\n",
+ " GPT-Google Drive Integration
\n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ "\n",
+ "\n",
+ "\"\"\"\n",
+ "\n",
+ "@app.route('/')\n",
+ "def home():\n",
+ " return render_template_string(HTML_TEMPLATE)\n",
+ "\n",
+ "@app.route('/query', methods=['POST'])\n",
+ "def query():\n",
+ " data = request.json\n",
+ " result = integration.process_query(data['query'])\n",
+ " return jsonify(result)\n",
+ "\n",
+ "if __name__ == '__main__':\n",
+ " app.run(debug=True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "caef8af5-73f9-4627-9203-0e9c8d098db0",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ff7582bd-f80c-46c4-a51b-b20fd7493b0e",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "96ea63b3-3cf3-41c1-b160-72d677ab0949",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "a8a64f0d-c9b5-4ce7-a887-e1b60de4dac3",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "id": "abbc0f6c-5350-4fd9-8711-de68d4aa739d",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "02ae258f-bef0-469b-a696-1edf6a7b5921",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "id": "09a0b418-eb0e-486e-bf05-bc7b43645784",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "* Running on local URL: http://127.0.0.1:7860\n",
+ "* Running on public URL: https://a9ef60dd3438b2ef0e.gradio.live\n",
+ "\n",
+ "This share link expires in 1 week. For free permanent hosting and GPU upgrades, run `gradio deploy` from the terminal in the working directory to deploy to Hugging Face Spaces (https://huggingface.co/spaces)\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Keyboard interruption in main thread... closing server.\n",
+ "Killing tunnel 127.0.0.1:7860 <> https://a9ef60dd3438b2ef0e.gradio.live\n"
+ ]
+ }
+ ],
+ "source": [
+ "gpt_drive = GPTDriveIntegration()\n",
+ "\n",
+ "def process_user_query(query, search_terms_input):\n",
+ " \"\"\"Process user query and return formatted response\"\"\"\n",
+ " if not query.strip():\n",
+ " return \"Please enter a question.\", \"\"\n",
+ " \n",
+ " # Parse search terms if provided\n",
+ " search_terms = None\n",
+ " # if search_terms_input.strip():\n",
+ " # search_terms = [term.strip() for term in search_terms_input.split(',')]\n",
+ " \n",
+ " # Process the query\n",
+ " result = gpt_drive.process_query(query, search_terms)\n",
+ " \n",
+ " # Format the response\n",
+ " answer = result['answer']\n",
+ " sources = result['sources']\n",
+ " \n",
+ " sources_text = \"\"\n",
+ " if sources:\n",
+ " sources_text = \"**Sources used:**\\n\" + \"\\n\".join([f\"• {source}\" for source in sources])\n",
+ " \n",
+ " return answer, sources_text\n",
+ "\n",
+ "def check_setup():\n",
+ " \"\"\"Check if the APIs are properly configured\"\"\"\n",
+ " status_messages = []\n",
+ " \n",
+ " # Check Google Drive API\n",
+ " if gpt_drive.drive_initialized:\n",
+ " status_messages.append(\"✅ Google Drive API: Connected\")\n",
+ " else:\n",
+ " status_messages.append(f\"❌ Google Drive API: {getattr(gpt_drive, 'drive_error', 'Not configured')}\")\n",
+ " \n",
+ " # Check OpenAI API\n",
+ " if gpt_drive.openai_initialized:\n",
+ " status_messages.append(\"✅ OpenAI API: Connected\")\n",
+ " else:\n",
+ " status_messages.append(f\"❌ OpenAI API: {getattr(gpt_drive, 'openai_error', 'Not configured')}\")\n",
+ " \n",
+ " return \"\\n\".join(status_messages)\n",
+ "\n",
+ "# Create Gradio interface\n",
+ "with gr.Blocks(title=\"Augusta's Anatomy Reading Assistant\", theme=gr.themes.Soft()) as app:\n",
+ " gr.Markdown(\"# 🤖 Augusta's Anatomy bot\")\n",
+ " gr.Markdown(\"Ask questions about your anatomy books using AI!\")\n",
+ " \n",
+ " with gr.Row():\n",
+ " with gr.Column(scale=2):\n",
+ " # Main query interface\n",
+ " with gr.Group():\n",
+ " gr.Markdown(\"### Ask a Question\")\n",
+ " query_input = gr.Textbox(\n",
+ " label=\"Your Question\",\n",
+ " placeholder=\"Ask me any question about your anatomy books?\",\n",
+ " lines=3\n",
+ " )\n",
+ " \n",
+ " search_terms_input = gr.Textbox(\n",
+ " label=\"Search Terms (optional)\",\n",
+ " placeholder=\"Enter comma-separated terms to search for specific files\",\n",
+ " lines=1\n",
+ " )\n",
+ " \n",
+ " submit_btn = gr.Button(\"Search & Ask\", variant=\"primary\", size=\"lg\")\n",
+ " \n",
+ " # Results section\n",
+ " with gr.Group():\n",
+ " gr.Markdown(\"### Answer\")\n",
+ " answer_output = gr.Textbox(\n",
+ " label=\"AI Response\",\n",
+ " lines=10,\n",
+ " interactive=False\n",
+ " )\n",
+ " \n",
+ " sources_output = gr.Textbox(\n",
+ " label=\"Sources\",\n",
+ " lines=3,\n",
+ " interactive=False\n",
+ " )\n",
+ " \n",
+ " with gr.Column(scale=1):\n",
+ " # Status and setup info\n",
+ " with gr.Group():\n",
+ " gr.Markdown(\"### System Status\")\n",
+ " status_btn = gr.Button(\"Check Status\", size=\"sm\")\n",
+ " status_output = gr.Textbox(\n",
+ " label=\"API Status\",\n",
+ " lines=4,\n",
+ " interactive=False\n",
+ " )\n",
+ " \n",
+ " with gr.Group():\n",
+ " gr.Markdown(\"### Setup Instructions\")\n",
+ " gr.Markdown(\"\"\"\n",
+ " **Important Notes:**\n",
+ " 1.Only documents shared with it, it can answer\n",
+ " \n",
+ " **File Types Supported:**\n",
+ " - Google Docs\n",
+ " - Google Sheets \n",
+ " - PDF files\n",
+ " - Text files\n",
+ " \n",
+ " **Tips:**\n",
+ " - Use specific search terms for better results\n",
+ " - The system searches the top 3 most relevant files\n",
+ " - Ask clear, specific questions for better answers\n",
+ " \"\"\")\n",
+ " \n",
+ " # Event handlers\n",
+ " submit_btn.click(\n",
+ " fn=process_user_query,\n",
+ " inputs=[query_input, search_terms_input],\n",
+ " outputs=[answer_output, sources_output]\n",
+ " )\n",
+ " \n",
+ " status_btn.click(\n",
+ " fn=check_setup,\n",
+ " outputs=status_output\n",
+ " )\n",
+ " \n",
+ " # Example queries\n",
+ " with gr.Row():\n",
+ " gr.Examples(\n",
+ " examples=[\n",
+ " [\"What is morbid Anatomy?\", \"morbid, Anatomy\"],\n",
+ " [\"The transmission of nerves from one neuron to another is as a result of what?\", \"neuron, nerves, Dr Clement\"],\n",
+ " ],\n",
+ " inputs=[query_input, search_terms_input],\n",
+ " )\n",
+ "\n",
+ "# Launch the app\n",
+ "if __name__ == \"__main__\":\n",
+ " app.launch(\n",
+ " share=True,debug =True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "35d0a347-2cc6-4f4e-bb70-cc47067eaf53",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.13.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}