To automate daily content creation using a "NotebookLM-style" approach, there is an important technical detail you need to know first: **Google’s NotebookLM does not currently have a public API.** It is a standalone web application, which means you cannot directly hook it up to automation tools like Zapier or Make to run on autopilot.
However, **NotebookLM is powered by the Gemini 1.5 Pro model**, which *does* have an API.
To create an automated agent that acts exactly like NotebookLM (ingesting specific sources, synthesizing them, and drafting daily content), you can build a workflow using automation platforms and the Gemini API.
Here is the step-by-step blueprint to build your own automated "NotebookLM Content Agent."
---
### Step 1: Set up your "Notebook" (Data Sources)
NotebookLM is famous for its "grounding"—it only writes based on the documents you give it. You need a centralized place to dump your daily inspiration, news, or notes.
* **Options:** A specific Google Drive folder, a Notion database, an RSS feed reader (like Feedly), or a Pocket/Instapaper account.
* **The Goal:** Every day, as you browse, you save interesting articles, PDFs, or ideas to this specific location.
### Step 2: Choose your Automation Platform
You need a "glue" to connect your data sources to the AI and then to your publishing platform.
* **Make.com / Zapier:** Best if you want a no-code, drag-and-drop solution. Make.com is generally cheaper and better at handling complex AI workflows.
* **n8n:** A powerful workflow automation tool that has built-in AI agent capabilities (highly recommended for this use case).
* **Python (LangChain / CrewAI):** Best if you are a developer and want complete control over your AI agents.
### Step 3: Build the Automation Workflow
Let's assume you are using **Make.com** or **n8n**. Here is how you build the daily loop:
1. **The Trigger (Schedule):** Set the automation to run every day at a specific time (e.g., 6:00 AM).
2. **The Ingestion (Read the Notebook):** The automation looks into your Google Drive folder or RSS feed and extracts all the text from the files/links added in the last 24 hours.
3. **The Brain (Gemini 1.5 Pro API):** The automation passes all that text to the Gemini API. Gemini 1.5 Pro has a 2-million-token context window, meaning it can read dozens of long articles at once—exactly like NotebookLM.
4. **The Prompt:** You give Gemini a strict set of instructions (see Step 4 below).
5. **The Output (Drafting):** The automation takes Gemini's output and creates a draft in your CMS (WordPress, Webflow), your social media scheduler (Buffer, Typefully), or just a Google Doc for you to review.
### Step 4: The "NotebookLM" Prompt
To get the high-quality synthesis NotebookLM is known for, your API prompt needs to be highly engineered. Use a prompt like this:
> *"You are an expert content creator. I am providing you with several source documents from the past 24 hours. Your job is to synthesize this information and create [INSERT FORMAT: e.g., a 500-word newsletter / a 5-tweet Twitter thread / a LinkedIn post].*
>
> *RULES:*
> *1. Rely ONLY on the provided text. Do not hallucinate outside information.*
> *2. Extract the 3 most counter-intuitive or interesting insights.*
> *3. Write in a conversational, engaging, and professional tone.*
> *4. Cite the original sources where applicable."*
### Step 5: (Bonus) Replicate the NotebookLM "Audio Overview" Podcast
If you want to replicate NotebookLM's viral AI podcast feature (where two hosts discuss your content), you can add another step to your automation:
1. Have Gemini write a script formatted as a dialogue between "Host 1" and "Host 2".
2. Send the text of Host 1 to an audio AI like **ElevenLabs** API using Voice A.
3. Send the text of Host 2 to ElevenLabs using Voice B.
4. Have the automation stitch the audio files together and save the daily MP3 to your Google Drive.
### Summary: The Easiest Way to Start Today
If you have zero coding experience, do this:
1. Create a free **Make.com** account.
2. Connect an **RSS Feed** (e.g., your favorite industry blogs) as the Trigger.
3. Add the **Google Gemini API** module. Put in your system prompt.
4. Add the **Slack** or **Gmail** module to send the finished drafted content directly to you every morning so you can review, edit, and post it.
step 1 - google drive
step 2 - python
step 3 - local dev
step4 - email to prompt
step 5 - confirmation email
i want all code in local to be in docker
To move this Python agent into Docker, we need to make three important adjustments:
1. **Continuous Loop:** A Docker container stops when the script finishes. We need to add a scheduler so the script stays alive and checks your email every few minutes.
2. **Environment Variables:** We will use a `.env` file to securely pass your API keys and passwords into the container.
3. **The "Google Auth" Docker Trap:** Google's OAuth requires opening a web browser. Since a Docker container doesn't have a web browser, **you must generate the `token.json` file locally first**, and then pass it into the container.
Here is the complete setup to run your agent in Docker.
### Step 1: Project Structure
Create a new folder on your machine (e.g., `notebooklm-agent`) and set up these files:
```text
/notebooklm-agent
├── agent.py
├── requirements.txt
├── Dockerfile
├── docker-compose.yml
├── .env
├── credentials.json (Downloaded from Google Cloud)
└── token.json (We will generate this in Step 4)
```
### Step 2: The Updated Python Code (`agent.py`)
This is the same logic as before, but updated to run continuously and use environment variables.
```python
import os
import time
import smtplib
import imaplib
import email
from email.message import EmailMessage
import google.generativeai as genai
from googleapiclient.discovery import build
from google.oauth2.credentials import Credentials
# Load from Environment Variables (passed by Docker)
EMAIL_USER = os.environ.get("EMAIL_USER")
EMAIL_PASS = os.environ.get("EMAIL_PASS")
ALLOWED_SENDER = os.environ.get("ALLOWED_SENDER")
DRIVE_FOLDER_ID = os.environ.get("DRIVE_FOLDER_ID")
GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY")
genai.configure(api_key=GEMINI_API_KEY)
def get_drive_service():
"""Reads the token.json file mapped into the Docker container."""
SCOPES = ['https://www.googleapis.com/auth/drive.readonly']
creds = None
if os.path.exists('token.json'):
creds = Credentials.from_authorized_user_file('token.json', SCOPES)
if not creds or not creds.valid:
raise Exception("Google Drive token is invalid or missing. Generate token.json locally first!")
return build('drive', 'v3', credentials=creds)
def read_drive_documents(service):
context_text = ""
results = service.files().list(
q=f"'{DRIVE_FOLDER_ID}' in parents and mimeType='application/vnd.google-apps.document'",
fields="files(id, name)"
).execute()
items = results.get('files', [])
for item in items:
request = service.files().export_media(fileId=item['id'], mimeType='text/plain')
content = request.execute().decode('utf-8')
context_text += f"\n--- Document: {item['name']} ---\n{content}\n"
return context_text
def check_email_for_prompt():
try:
mail = imaplib.IMAP4_SSL("imap.gmail.com")
mail.login(EMAIL_USER, EMAIL_PASS)
mail.select("inbox")
status, messages = mail.search(None, f'(UNSEEN FROM "{ALLOWED_SENDER}")')
email_ids = messages[0].split()
if not email_ids:
return None
latest_email_id = email_ids[-1]
status, msg_data = mail.fetch(latest_email_id, '(RFC822)')
for response_part in msg_data:
if isinstance(response_part, tuple):
msg = email.message_from_bytes(response_part[1])
prompt_text = ""
if msg.is_multipart():
for part in msg.walk():
if part.get_content_type() == "text/plain":
prompt_text = part.get_payload(decode=True).decode()
else:
prompt_text = msg.get_payload(decode=True).decode()
return prompt_text.strip()
except Exception as e:
print(f"Error checking email: {e}")
return None
def send_confirmation_email(generated_content):
msg = EmailMessage()
msg.set_content(generated_content)
msg['Subject'] = "🤖 Your Daily Content Draft"
msg['From'] = EMAIL_USER
msg['To'] = ALLOWED_SENDER
with smtplib.SMTP_SSL('smtp.gmail.com', 465) as server:
server.login(EMAIL_USER, EMAIL_PASS)
server.send_message(msg)
def run_agent():
print("Checking for new prompt via email...")
user_prompt = check_email_for_prompt()
if not user_prompt:
return
print(f"Prompt received: {user_prompt[:50]}...")
try:
drive_service = get_drive_service()
context_data = read_drive_documents(drive_service)
model = genai.GenerativeModel('gemini-1.5-pro')
full_prompt = f"You are an expert content creator. Use ONLY the following source material to fulfill the user's prompt.\n\nUSER PROMPT: {user_prompt}\n\nSOURCE MATERIAL:\n{context_data}"
response = model.generate_content(full_prompt)
send_confirmation_email(response.text)
print("Content generated and emailed successfully!")
except Exception as e:
print(f"Error processing prompt: {e}")
send_confirmation_email(f"An error occurred: {str(e)}")
if __name__ == '__main__':
print("Starting NotebookLM Agent in Docker...")
# Loop continuously. Checks email every 60 seconds.
while True:
run_agent()
time.sleep(60)
```
### Step 3: Docker & Config Files
**`requirements.txt`**
```text
google-generativeai
google-api-python-client
google-auth-httplib2
google-auth-oauthlib
```
**`Dockerfile`**
```dockerfile
# Use a lightweight Python image
FROM python:3.10-slim
# Set the working directory inside the container
WORKDIR /app
# Copy requirements and install
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy the rest of the app
COPY . .
# Run the Python script
CMD ["python", "-u", "agent.py"]
# Note: -u forces unbuffered output so print() statements show in Docker logs immediately
```
**`docker-compose.yml`**
Using Docker Compose makes it much easier to pass environment variables and mount your Google credentials.
```yaml
version: '3.8'
services:
notebooklm-agent:
build: .
container_name: notebooklm-agent
env_file:
- .env
volumes:
- ./credentials.json:/app/credentials.json:ro
- ./token.json:/app/token.json:rw
restart: unless-stopped
```
**`.env`**
```env
EMAIL_USER=your_bot_email@gmail.com
EMAIL_PASS=your_16_character_app_password
ALLOWED_SENDER=your_personal_email@gmail.com
DRIVE_FOLDER_ID=your_google_drive_folder_id
GEMINI_API_KEY=your_gemini_api_key
```
### Step 4: Overcoming the Google Auth Trap (Important)
Because Docker has no UI, it cannot open the Google Login page to authorize your app. You must generate the `token.json` file on your host machine first.
1. Ensure `credentials.json` is in your project folder.
2. Open a terminal on your local machine and run this temporary one-liner to generate the token:
```bash
# Install the auth library temporarily on your host machine
pip install google-auth-oauthlib google-api-python-client
# Run this Python code in your terminal:
python -c "from google_auth_oauthlib.flow import InstalledAppFlow; InstalledAppFlow.from_client_secrets_file('credentials.json', ['https://www.googleapis.com/auth/drive.readonly']).run_local_server(port=0)"
```
3. Your browser will open. Log into Google and click "Allow".
4. You will now see a `token.json` file generated in your project folder. Docker can now use this file!
### Step 5: Build and Run
With your `.env`, `credentials.json`, and `token.json` in place, start the Docker container.
Open your terminal in the project directory and run:
```bash
docker-compose up -d --build
```
**Useful Docker Commands:**
* Check if it's running: `docker ps`
* Read the live logs: `docker logs -f notebooklm-agent`
* Stop the agent: `docker-compose down`
Your agent is now safely containerized. It will silently run in the background, pinging your email every 60 seconds waiting for your instructions!
To replace the "Email to Prompt" step with a clean, modern User Interface, we will use **Streamlit**. Streamlit is the industry standard for building fast, beautiful web UIs for Python AI apps.
By doing this, we change your Docker container from a "background loop" into a **local web server**. You will type your prompt into a web page on your browser, click "Generate", see the AI draft on the screen, and the app will *still* send you the confirmation email (Step 5).
Here is how to update your Docker setup to include the Streamlit UI.
### Step 1: Update your `requirements.txt`
Add `streamlit` to your list of dependencies.
```text
google-generativeai
google-api-python-client
google-auth-httplib2
google-auth-oauthlib
streamlit
```
### Step 2: The New Python Code (`app.py`)
Rename your `agent.py` to `app.py`. We are removing the IMAP (email checking) logic and replacing it with Streamlit UI components.
```python
import os
import smtplib
from email.message import EmailMessage
import streamlit as st
import google.generativeai as genai
from googleapiclient.discovery import build
from google.oauth2.credentials import Credentials
# --- CONFIGURATION ---
EMAIL_USER = os.environ.get("EMAIL_USER")
EMAIL_PASS = os.environ.get("EMAIL_PASS")
ALLOWED_SENDER = os.environ.get("ALLOWED_SENDER")
DRIVE_FOLDER_ID = os.environ.get("DRIVE_FOLDER_ID")
GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY")
genai.configure(api_key=GEMINI_API_KEY)
# --- HELPER FUNCTIONS ---
def get_drive_service():
SCOPES = ['https://www.googleapis.com/auth/drive.readonly']
creds = None
if os.path.exists('token.json'):
creds = Credentials.from_authorized_user_file('token.json', SCOPES)
if not creds or not creds.valid:
st.error("Google Drive token is invalid or missing. Check token.json.")
st.stop()
return build('drive', 'v3', credentials=creds)
def read_drive_documents(service):
context_text = ""
results = service.files().list(
q=f"'{DRIVE_FOLDER_ID}' in parents and mimeType='application/vnd.google-apps.document'",
fields="files(id, name)"
).execute()
items = results.get('files', [])
for item in items:
request = service.files().export_media(fileId=item['id'], mimeType='text/plain')
content = request.execute().decode('utf-8')
context_text += f"\n--- Document: {item['name']} ---\n{content}\n"
return context_text
def send_confirmation_email(generated_content):
msg = EmailMessage()
msg.set_content(generated_content)
msg['Subject'] = "🤖 Your Daily Content Draft"
msg['From'] = EMAIL_USER
msg['To'] = ALLOWED_SENDER
with smtplib.SMTP_SSL('smtp.gmail.com', 465) as server:
server.login(EMAIL_USER, EMAIL_PASS)
server.send_message(msg)
# --- STREAMLIT UI ---
st.set_page_config(page_title="NotebookLM Agent", page_icon="📓", layout="centered")
st.title("📓 Local NotebookLM Agent")
st.write("Generate content based *only* on the documents in your Google Drive folder.")
# UI: The Prompt Input
user_prompt = st.text_area("What should I create today?",
placeholder="e.g., Write a 3-part Twitter thread summarizing my notes...",
height=150)
# UI: The Generate Button
if st.button("Generate Content", type="primary"):
if not user_prompt.strip():
st.warning("Please enter a prompt first.")
else:
with st.spinner("Ingesting Google Drive and generating content..."):
try:
# 1. Get Google Drive Data
drive_service = get_drive_service()
context_data = read_drive_documents(drive_service)
# 2. Call Gemini
model = genai.GenerativeModel('gemini-1.5-pro')
full_prompt = f"""
You are an expert content creator. Use ONLY the following source material to fulfill the user's prompt.
USER PROMPT: {user_prompt}
SOURCE MATERIAL:
{context_data}
"""
response = model.generate_content(full_prompt)
draft_text = response.text
# 3. Send Confirmation Email
send_confirmation_email(draft_text)
# 4. Display Results in UI
st.success("Success! Draft generated and confirmation email sent.")
st.subheader("Your Draft:")
st.markdown(draft_text)
except Exception as e:
st.error(f"An error occurred: {e}")
```
### Step 3: Update `Dockerfile`
Streamlit requires specific commands to run inside Docker. We need to expose port `8501` and change the CMD.
```dockerfile
FROM python:3.10-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
# Expose Streamlit's default port
EXPOSE 8501
# Run Streamlit
CMD ["streamlit", "run", "app.py", "--server.port=8501", "--server.address=0.0.0.0"]
```
### Step 4: Update `docker-compose.yml`
We must map port 8501 from the container to your local machine so you can open the UI in your browser.
```yaml
version: '3.8'
services:
notebooklm-agent:
build: .
container_name: notebooklm-agent
ports:
- "8501:8501"
env_file:
- .env
volumes:
- ./credentials.json:/app/credentials.json:ro
- ./token.json:/app/token.json:rw
restart: unless-stopped
```
### Step 5: Run the Web App
Make sure your `.env`, `credentials.json`, and the `token.json` (that you generated previously) are all still in the folder.
1. Open your terminal and rebuild the Docker container:
```bash
docker-compose up -d --build
```
2. Open your web browser and go to:
**http://localhost:8501**
You will now see a clean, modern web app. You can type your prompt into the box, click generate, watch the spinner as it ingests your Google Docs and pings Gemini, read the final output directly on the screen, and automatically receive a copy in your email inbox!
0 comments :
Post a Comment