Created
February 9, 2026 20:39
-
-
Save mhawksey/7ab1b3e94ef36d58efed2b24ef20603c to your computer and use it in GitHub Desktop.
Based on this example https://github.com/St3ph-fr/Gemini/blob/main/code-execution-tool/split-merge-pdf.gs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * CONFIGURATION | |
| * 1. Replace the API key below or set it in Project Settings > Script Properties | |
| * 2. Ensure you have the Drive API service enabled in your Apps Script project. | |
| * 3. This script should be container-bound to a Google Doc. | |
| */ | |
| const GEMINI_API_KEY = "YOUR_API_KEY_HERE"; | |
| /** | |
| * Main function to run the process: | |
| * Google Doc -> Markdown -> Gemini (python-pptx) -> Google Drive (.pptx) | |
| */ | |
| function generateSummaryPresentation() { | |
| const doc = DocumentApp.getActiveDocument(); | |
| const docId = doc.getId(); | |
| const docName = doc.getName(); | |
| console.log(`Processing Document: ${docName}`); | |
| // 1. Export Google Doc as Markdown using Drive API | |
| const markdownText = exportDocAsMarkdown(docId); | |
| if (!markdownText) { | |
| throw new Error("Failed to export document as Markdown."); | |
| } | |
| // 2. Prepare the prompt for Gemini | |
| // We explicitly ask Gemini to use python-pptx to generate a summary. | |
| const contents = [{ | |
| parts: [ | |
| { | |
| "text": `Task: Analyze the following Markdown content and create a summary PowerPoint presentation (.pptx). | |
| Use the 'python-pptx' library to create a professional summary with at least 3 slides: | |
| a Title slide, a Key Points slide, and a Summary slide. | |
| Content: \n\n${markdownText}` | |
| } | |
| ] | |
| }]; | |
| const tools = [{ "code_execution": {} }]; | |
| // 3. Call Gemini API | |
| const response = callGeminiApi(contents, tools, "You are an expert presentation creator and data analyst."); | |
| if (response && response.candidates) { | |
| const timestamp = Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "yyyy-MM-dd_HH-mm"); | |
| const outputFileName = `${docName} - Summary - ${timestamp}.pptx`; | |
| // 4. Process the binary output from the Python sandbox | |
| processGeminiResponse(response.candidates[0].content.parts, outputFileName); | |
| } else { | |
| console.error("No valid response from Gemini API."); | |
| } | |
| } | |
| /** | |
| * Exports a Google Doc to Markdown format using the Drive API export link. | |
| */ | |
| function exportDocAsMarkdown(docId) { | |
| try { | |
| const url = `https://docs.google.com/feeds/download/documents/export/Export?exportFormat=markdown&id=${docId}`; | |
| const options = { | |
| headers: { | |
| authorization: "Bearer " + ScriptApp.getOAuthToken() | |
| }, | |
| muteHttpExceptions: true | |
| }; | |
| const response = UrlFetchApp.fetch(url, options); | |
| if (response.getResponseCode() === 200) { | |
| return response.getContentText(); | |
| } else { | |
| console.error(`Export failed: ${response.getContentText()}`); | |
| return null; | |
| } | |
| } catch (e) { | |
| console.error(`Error in exportDocAsMarkdown: ${e.message}`); | |
| return null; | |
| } | |
| } | |
| /** | |
| * Helper to handle the API response parts (Python code, logs, and PPTX file generation). | |
| */ | |
| function processGeminiResponse(parts, outputFileName) { | |
| console.log("--- Processing Gemini Response ---"); | |
| parts.forEach((part, index) => { | |
| // 1. Log the Python Code used for debugging | |
| if (part.executableCode) { | |
| console.log(`[Part ${index}] Python Code Generated:\n`, part.executableCode.code); | |
| } | |
| // 2. Log any output/errors from the Python sandbox | |
| else if (part.codeExecutionResult) { | |
| console.log(`[Part ${index}] Sandbox Result (${part.codeExecutionResult.outcome}):\n`, part.codeExecutionResult.output); | |
| } | |
| // 3. Handle Binary File Generation (The .pptx file) | |
| else if (part.inlineData) { | |
| console.log(`[Part ${index}] PPTX data received. Saving to Drive...`); | |
| const decodedData = Utilities.base64Decode(part.inlineData.data); | |
| const newFileBlob = Utilities.newBlob(decodedData, part.inlineData.mimeType, outputFileName); | |
| const newFile = DriveApp.createFile(newFileBlob); | |
| console.log("✅ Presentation saved: " + newFile.getUrl()); | |
| } | |
| // 4. Log text responses | |
| else if (part.text) { | |
| console.log(`[Part ${index}] Text Response:\n`, part.text); | |
| } | |
| }); | |
| } | |
| /** | |
| * Core API Call Logic with Retries | |
| */ | |
| function callGeminiApi(contents, tools, systemInstruction, modelName = "gemini-3-flash-preview") { | |
| const MAX_RETRIES = 3; | |
| const url = `https://generativelanguage.googleapis.com/v1beta/models/${modelName}:generateContent?key=${GEMINI_API_KEY}`; | |
| const payload = { | |
| "contents": contents, | |
| "generationConfig": { | |
| "thinkingConfig": { "thinkingLevel": "LOW" }, | |
| "temperature": 1 | |
| } | |
| }; | |
| if (systemInstruction) { | |
| payload.systemInstruction = { "parts": [{ "text": systemInstruction }] }; | |
| } | |
| if (tools) { | |
| payload.tools = tools; | |
| } | |
| const options = { | |
| 'method': 'post', | |
| 'contentType': 'application/json', | |
| 'payload': JSON.stringify(payload), | |
| 'muteHttpExceptions': true, | |
| }; | |
| for (let attempt = 0; attempt < MAX_RETRIES; attempt++) { | |
| try { | |
| const response = UrlFetchApp.fetch(url, options); | |
| const responseCode = response.getResponseCode(); | |
| const responseText = response.getContentText(); | |
| if (responseCode === 200) { | |
| return JSON.parse(responseText); | |
| } else { | |
| console.warn(`Attempt ${attempt + 1} failed (HTTP ${responseCode}).`); | |
| if (attempt + 1 < MAX_RETRIES) Utilities.sleep(Math.pow(2, attempt) * 1000); | |
| } | |
| } catch (e) { | |
| console.error(`Attempt ${attempt + 1} Error: ${e.toString()}`); | |
| if (attempt + 1 < MAX_RETRIES) Utilities.sleep(Math.pow(2, attempt) * 1000); | |
| } | |
| } | |
| return null; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment