A terminal assistant that manages Google Slides and PowerPoint (.pptx)
files on Google Drive through a Turkish- or English-speaking chat. It is
built on the Agno framework, powered by OpenAI gpt-4o-mini, and talks to
Google's official Slides/Drive APIs. It can read and edit both native
Google Slides presentations and .pptx files — on Drive and on the local
disk.
- Google Drive integration: file search, listing, opening.
- Reads and edits native Google Slides files directly through the Slides
API (
GoogleSlidesTools). - Edits PowerPoint (
.pptx) files while preserving the format..pptxfiles on Drive are never converted to Google Slides; they are downloaded, edited locally withpython-pptx, and uploaded back to the same Drive ID. The file stays.pptx; sharing settings and links are preserved. - Bulk operations across a Drive folder (
bulk_find_replace_in_folder, with recursive support). - Opt-in local folder mode: the agent cannot touch any file on the local
disk unless the user explicitly opens a folder. Once
open_local_folderis called, the agent can list, read and edit.pptxfiles inside that folder. The project ships with a suggestedpresentations/drop folder;open_local_folder()with no argument opens it. Any other path can be passed explicitly. - Bulk operations across the active local folder
(
bulk_find_replace_in_local_folder,search_in_all_local_files). - Slide tools: list/read slides, inspect shapes and layouts, add/delete/ move slides, set titles, update shape text, add text boxes, tables and images, bulk find-and-replace.
- Multilingual UI: a TR / EN picker at startup; all strings are pulled
from a single
i18nmodule so adding a new language is a one-file change. - Persistent chat memory: conversation history and long-term user
memories are stored in a local SQLite database. The agent remembers
previous turns and durable facts (preferred language, frequently
mentioned files/folders, workflow habits) across terminal restarts. A
small local model running on Ollama (
qwen2.5:3b-instructby default) performs memory extraction in the background — no extra API cost, no presentation/Drive context leaves the machine. The main agent talks to OpenAIgpt-4o-minifor the tool-using work. - Rolling sessions with manual rotation: one active session is kept by
default; type
:newin the terminal to start a fresh session. Old sessions stay in the DB and can be surfaced via session search. - Path-traversal protection: in local folder mode the agent cannot escape the opened folder.
- Secrets stay out of git:
.env,credentials.json,token.jsonand the local DB (agent_data/) are excluded via.gitignore.
PPTX Agent/
├── main.py # Terminal chat entry point
├── pyproject.toml # uv project definition and dependencies
├── uv.lock # uv lockfile
├── .env.example # Environment variable template
├── .gitignore
├── README.md
├── LICENSE
├── credentials.json # (you provide — Google OAuth client)
├── token.json # (auto-generated after the first auth)
├── presentations/ # suggested drop folder for local .pptx files
├── pptx_workdir/ # (runtime) downloaded Drive .pptx files
├── agent_data/ # (runtime) SQLite DB + active session id
└── src/
├── __init__.py
├── agent.py # Agno agent setup + OpenAI gpt-4o-mini
├── google_auth.py # Shared Google OAuth loader + scopes
├── pptx_tools.py # Drive .pptx tools + folder tools
├── local_tools.py # Local folder tools (opt-in)
├── memory.py # SQLite DB + session/user memory wiring
└── i18n.py # All TR/EN strings in one place
The agent operates with four toolkits. It picks the correct one for each task by itself.
Finds and lists files on Drive.
list_files— returns recent files.search_files— Drive query-syntax search.read_file— text-based content read.
For native Google Slides files.
create_presentation,get_presentation,list_presentations,get_presentation_metadata.get_page,get_slide_text,read_all_text,get_slide_thumbnail.add_slide,add_text_box,add_table,set_background_image,duplicate_slide,move_slides.insert_youtube_video,insert_drive_video.delete_slide— removes a single slide.batch_update_presentation— raw Slides API batch requests.
delete_presentation is intentionally disabled — deleting a whole
presentation goes through Drive Trash instead.
For .pptx files on Drive and Drive folders. Every tool name contains
pptx so it never collides with the GoogleSlidesTools names.
Drive transfer:
download_pptx(file_id)— downloads the.pptxintopptx_workdir/.upload_pptx(file_id)— uploads back to the same Drive ID; format is preserved.
Read / inspect (on the downloaded file):
list_pptx_slides,read_pptx_slide,read_all_pptx_textlist_pptx_shapes,list_pptx_slide_layoutsdescribe_pptx— slide count, per-slide shape breakdown.find_text_pptx— locate slides/shapes matching a pattern.
Slide editing:
add_pptx_slide— new slide from a template layout, with optional title/body.delete_pptx_slide,move_pptx_slide.
Shape / content editing:
set_pptx_slide_title,update_pptx_shape_textadd_pptx_text_box,add_pptx_table,add_pptx_image(positions in inches)find_and_replace_pptx— bulk text replace across slides.
Drive-wide file management:
move_drive_file_to_trash(file_id)— recoverable from Drive Trash.rename_drive_file,copy_drive_file.
Creation:
create_drive_pptx_file(name, target_folder_id)— uploads a brand-new empty.pptxto Drive and caches it locally for immediate editing.
Folder level (Drive):
find_folder_by_name(name)list_pptx_in_folder(folder_id, include_slides, recursive, max_results)bulk_find_replace_in_folder(folder_id, find, replace, ..., recursive)— runs the download → find/replace → upload loop on behalf of the agent. Files with zero replacements are not re-uploaded.
There is no slide-duplication tool for .pptx: python-pptx has no
reliable primitive for it. For slide duplication, use a native Google
Slides file (duplicate_slide in GoogleSlidesTools).
For .pptx files on the local disk. Stateful: no tool runs until a
folder is opened.
Workspace lifecycle:
open_local_folder(path)— activates the folder and returns the initial listing. Empty path opens the defaultpresentations/folder.close_local_folder(),show_local_folder().
File system:
list_local_folder(subpath, recursive)— thels. Withrecursive=Trueit walks subdirectories and returns relative paths.
Presentation inspection and editing — local counterparts of the
PptxTools operations:
list_local_slides,read_local_slide,read_all_local_text,list_local_shapes,list_local_slide_layouts,describe_local_pptx,find_text_local_pptx.create_local_pptx_file— creates a new empty.pptx.add_local_slide,delete_local_slide,move_local_slide.set_local_slide_title,update_local_shape_text,add_local_text_box,add_local_table,add_local_image,find_and_replace_local_pptx.
Folder-wide:
bulk_find_replace_in_local_folder(find, replace, ..., recursive)search_in_all_local_files(pattern, ..., recursive)— search only.
File management:
move_local_pptx_file_to_trash— moves the file to the OS Recycle Bin.rename_local_pptx_file,copy_local_pptx_file,move_local_pptx_file.
Local files are saved in place — there is no download/upload step.
The agent reads only credentials.json for Google auth (no env vars).
- In the Google Cloud Console, create an OAuth client of type Desktop app.
- Enable the Google Slides API and the Google Drive API for the project.
- Download the client secret file, rename it to
credentials.json, and place it in the project root. - On the first run a browser window opens for consent;
token.jsonis written and reused on subsequent runs. Both files are gitignored.
Copy .env.example to .env and set OPENAI_API_KEY.
Memory extraction runs on a local Ollama model.
ollama pull qwen2.5:3b-instructMake sure the Ollama daemon is running before starting the agent.
uv syncuv run python main.pyAt startup, pick a language (tr / en). Then just type what you want in
natural language. Examples:
- "which presentations do I have?"
- "open deck.pptx and list its slides"
- "add a title slide: '2024 Results'"
- "in the .pptx, replace 'old title' with 'new title'"
- "open the local folder and show the slides in report.pptx"
Terminal commands:
:new— start a fresh session (the old one stays in the DB).exit/quit/çık— leave.
All user-facing text lives in src/i18n.py. To add a language, add a new
entry to the LOCALES dict with the same keys as tr / en (name,
banner, instructions, ready, user, bye, err_init, err_run,
new_session, exit_words). The language picker lists the new code
automatically.
.env,credentials.jsonandtoken.jsonare in.gitignore— they never enter version control.- In local folder mode the agent cannot do path traversal. Attempts to
escape via
../or absolute paths are rejected. local_*tools refuse to run until a folder is opened; the default posture is safe-by-default.- When uploading a
.pptxback to Drive the same file ID is reused; links and sharing stay intact. - PowerPoint lock files (
~$filename.pptx) are skipped automatically during bulk operations. - There is no permanent-delete tool. Drive files go to Drive Trash; local files go to the OS Recycle Bin.
All commands run through uv:
uv run python main.py # Start the agent
uv run python -c "import src.agent" # Quick import checkManaged in pyproject.toml:
agno— agent framework (also providesGoogleDriveTools/GoogleSlidesTools).openai— OpenAI Python SDK (main agent).google-api-python-client— Slides + Drive REST API.google-auth-httplib2,google-auth-oauthlib— OAuth.python-dotenv—.envsupport.python-pptx—.pptxread/write.send2trash— recoverable local file deletion.sqlalchemy— required by agno's SQLite backend (sessions + memories).ollama— Python client for the local memory-extraction model.
- Main model:
OpenAIChat(id=...)insrc/agent.py. - Memory model:
MEMORY_MODEL_IDinsrc/memory.py(defaults toqwen2.5:3b-instructon Ollama). To use a different model, pull it first (ollama pull <name>) and setMEMORY_MODEL_IDto its tag. - History window:
num_history_runs=10insrc/agent.py. - Past sessions surfaced via search:
num_history_sessions=3. - DB location:
DB_PATHinsrc/memory.py(defaults toagent_data/agent.db). - User identity:
PPTX_AGENT_USER_IDenvironment variable. - OAuth scopes:
SCOPESinsrc/google_auth.py—presentations+ fulldrive(the full Drive scope is required to download/upload arbitrary.pptxfiles).
- Drive
.pptxfiles are updated in place viadrive.files().update, not by copying. Drive ID, link and sharing all stay the same. - Slide delete and reorder are done by manipulating the
<p:sldIdLst>XML directly —python-pptxexposes no public API for either. find_and_replace_pptxjoins a paragraph's runs, replaces on the joined string, then writes the result into the first run. This guarantees the replacement at the cost of collapsing per-run formatting in changed paragraphs.- Slide duplication is intentionally not offered for
.pptx(no reliablepython-pptxprimitive); the agent routes the user to native Google Slides for that. - Folder-wide find/replace skips upload for files with zero replacements (bandwidth saving).
- The python-pptx logic lives in
pptx_tools.py;local_tools.pyimports those helpers so the slide/text logic exists in exactly one place.
"OPENAI_API_KEY is not set in .env"
The .env file must be in the project root. Copy from .env.example and
put the real key inside.
The browser OAuth screen says "access blocked" Add your Gmail address as a test user in Google Cloud Console > OAuth consent screen.
File is not .pptx (mimeType=...)
download_pptx works only on PowerPoint binary files. For native Google
Slides, the agent uses GoogleSlidesTools instead.
Path escapes the active folder
In local folder mode the agent cannot leave the opened folder. Open a
higher-level folder that contains the path you need.
No folder is open. Call open_local_folder(path) first.
Local tools are opt-in. Ask the agent to open a folder first.
Agent doesn't remember what we talked about last time
Memory persistence requires agent_data/agent.db to be present and
writable. Use :new only when you actually want a fresh session.
Ollama connection error / "model not found"
Memory extraction runs on a local Ollama model. Make sure Ollama is
installed and the daemon is running (ollama list should respond), and
that the model is pulled: ollama pull qwen2.5:3b-instruct.
- Folder-wide bulk operations for native Google Slides.
- Slide-level operations on speaker notes.
- Theme / template application across a deck.
- Async processing (parallel execution for large folders).
- A web interface (Streamlit or FastAPI).
This project is distributed under the MIT License. See the LICENSE file
in the project root for the full text.