Skip to content

Instantly share code, notes, and snippets.

@mhawksey
Created February 9, 2026 20:39
Show Gist options
  • Select an option

  • Save mhawksey/7ab1b3e94ef36d58efed2b24ef20603c to your computer and use it in GitHub Desktop.

Select an option

Save mhawksey/7ab1b3e94ef36d58efed2b24ef20603c to your computer and use it in GitHub Desktop.
/**
* 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