دمج البيانات في عرض تقديمي

من التطبيقات المفيدة لواجهة برمجة التطبيقات Google Slides API دمج معلومات من مصدر بيانات واحد أو أكثر في مجموعة شرائح نموذجية.

توضّح هذه الصفحة كيفية الحصول على بيانات من مصدر خارجي وإدراجها في عرض تقديمي نموذجي حالي. يشبه المفهوم عملية دمج البريد باستخدام معالج كلمات وجدول بيانات.

هناك عدة أسباب لأهمية هذا النهج:

  • من السهل على المصمّمين تحسين تصميم العرض التقديمي باستخدام محرِّر "العروض التقديمية من Google". وهذا أسهل بكثير من ضبط المَعلمات في تطبيقك لضبط تصميم الشريحة المعروضة.

  • إنّ فصل المحتوى عن العرض هو أحد مبادئ التصميم المعروفة وله العديد من المزايا.

مخطّط مفاهيمي للدمج

وصفة أساسية

في ما يلي مثال على كيفية استخدام واجهة برمجة التطبيقات Slides API لدمج البيانات في عرض تقديمي:

  1. أنشئ عرضك التقديمي بالشكل الذي تريده باستخدام محتوى العنصر النائب لمساعدتك في التصميم.

  2. استبدِل محتوى العنصر النائب بعلامة لكل عنصر محتوى ستُدرجه. العلامات هي مربّعات نص أو أشكال تحتوي على سلسلة فريدة. احرص على استخدام سلاسل من غير المرجّح أن تظهر بشكل طبيعي. على سبيل المثال، قد تكون {{account-holder-name}} علامة جيدة.

  3. في رمزك البرمجي، استخدِم Google Drive API لإنشاء نسخة من ال عرض التقديمي.

  4. في الرمز البرمجي، استخدِم أسلوب batchUpdate Slides API مع مجموعة من طلبات replaceAllText لتنفيذ جميع عمليات استبدال النصوص في العرض التقديمي. استخدِم طلبات replaceAllShapesWithImage لإجراء عمليات استبدال الصور في جميع أنحاء العرض التقديمي.

بعد إنشاء عرض تقديمي يتضمّن علامات، احرص على إنشاء نسخة منه واستخدام Slides API لتعديل النسخة. لا تستخدِم Slides API لتلاعب بنسخة "النموذج" الأساسية.

تتضمّن الأقسام التالية مقتطفات رمز توضّح بعضًا من هذه العملية. يمكنك أيضًا مشاهدة الفيديو أعلاه للاطّلاع على مثال كامل (Python) يجمع العديد من المفاهيم الواردة في الأقسام الفردية أدناه.

دمج النص

يمكنك استخدام طلب replaceAllText لاستبدال جميع تكرارات سلسلة نصية معيّنة في عرض تقديمي بنص جديد. بالنسبة إلى عمليات الدمج، هذا أسهل من العثور على كل نسخة من النص واستبدالها بشكلٍ فردي. يرجع سبب كون هذا النهج هو الأكثر تعقيدًا إلى أنّه من الصعب توقّع معرّفات عناصر الصفحة، خاصةً عندما يُجري المتعاونون تحسينات على عرض قالب الجدول الزمني ويحافظون عليه.

مثال

يستخدم هذا المثال واجهة برمجة التطبيقات Drive API لنسخ عرض تقديمي من نموذج، ما يؤدي إلى إنشاء نسخة جديدة من العرض التقديمي. بعد ذلك، يستخدم التطبيق واجهة برمجة التطبيقات Google Sheets API لقراءة البيانات من جدول بيانات "جداول بيانات Google"، ويستخدم أخيرًا واجهة برمجة التطبيقات Slides API لتعديل الجدول الزمني الجديد.

يأخذ المثال البيانات من 3 خلايا في صف واحد من نطاق مُعنوَن في جدول البيانات. بعد ذلك، يتم استبدال هذه البيانات في العرض التقديمي في أي مكان تظهر فيه سلاسل {{customer-name}} أو {{case-description}} أو {{total-portfolio}}.

برمجة تطبيقات

slides/api/Snippets.gs
/**
 * Use the Sheets API to load data, one record per row.
 * @param {string} templatePresentationId
 * @param {string} dataSpreadsheetId
 * @returns {*[]}
 */
function textMerging(templatePresentationId, dataSpreadsheetId) {
  let responses = [];
  const dataRangeNotation = 'Customers!A2:M6';
  try {
    let values = SpreadsheetApp.openById(dataSpreadsheetId).getRange(dataRangeNotation).getValues();

    // For each record, create a new merged presentation.
    for (let i = 0; i < values.length; ++i) {
      const row = values[i];
      const customerName = row[2]; // name in column 3
      const caseDescription = row[5]; // case description in column 6
      const totalPortfolio = row[11]; // total portfolio in column 12

      // Duplicate the template presentation using the Drive API.
      const copyTitle = customerName + ' presentation';
      let copyFile = {
        title: copyTitle,
        parents: [{id: 'root'}]
      };
      copyFile = Drive.Files.copy(copyFile, templatePresentationId);
      const presentationCopyId = copyFile.id;

      // Create the text merge (replaceAllText) requests for this presentation.
      const requests = [{
        replaceAllText: {
          containsText: {
            text: '{{customer-name}}',
            matchCase: true
          },
          replaceText: customerName
        }
      }, {
        replaceAllText: {
          containsText: {
            text: '{{case-description}}',
            matchCase: true
          },
          replaceText: caseDescription
        }
      }, {
        replaceAllText: {
          containsText: {
            text: '{{total-portfolio}}',
            matchCase: true
          },
          replaceText: totalPortfolio + ''
        }
      }];

      // Execute the requests for this presentation.
      const result = Slides.Presentations.batchUpdate({
        requests: requests
      }, presentationCopyId);
      // Count the total number of replacements made.
      let numReplacements = 0;
      result.replies.forEach(function(reply) {
        numReplacements += reply.replaceAllText.occurrencesChanged;
      });
      console.log('Created presentation for %s with ID: %s', customerName, presentationCopyId);
      console.log('Replaced %s text instances', numReplacements);
    }
  } catch (err) {
    // TODO (Developer) - Handle exception
    console.log('Failed with error: %s', err.error);
  }
};

البدء

slides/snippets/presentations.go
// Use the Sheets API to load data, one record per row.
dataRangeNotation := "Customers!A2:M6"
sheetsResponse, _ := sheetsService.Spreadsheets.Values.Get(dataSpreadsheetId, dataRangeNotation).Do()
values := sheetsResponse.Values

// For each record, create a new merged presentation.
for _, row := range values {
	customerName := row[2].(string)
	caseDescription := row[5].(string)
	totalPortfolio := row[11].(string)

	// Duplicate the template presentation using the Drive API.
	copyTitle := customerName + " presentation"
	file := drive.File{
		Title: copyTitle,
	}
	presentationFile, _ := driveService.Files.Copy(templatePresentationId, &file).Do()
	presentationId := presentationFile.Id

	// Create the text merge (replaceAllText) requests for this presentation.
	requests := []*slides.Request{{
		ReplaceAllText: &slides.ReplaceAllTextRequest{
			ContainsText: &slides.SubstringMatchCriteria{
				Text:      "{{customer-name}}",
				MatchCase: true,
			},
			ReplaceText: customerName,
		},
	}, {
		ReplaceAllText: &slides.ReplaceAllTextRequest{
			ContainsText: &slides.SubstringMatchCriteria{
				Text:      "{{case-description}}",
				MatchCase: true,
			},
			ReplaceText: caseDescription,
		},
	}, {
		ReplaceAllText: &slides.ReplaceAllTextRequest{
			ContainsText: &slides.SubstringMatchCriteria{
				Text:      "{{total-portfolio}}",
				MatchCase: true,
			},
			ReplaceText: totalPortfolio,
		},
	}}

	// Execute the requests for this presentation.
	body := &slides.BatchUpdatePresentationRequest{
		Requests: requests,
	}
	response, _ := slidesService.Presentations.BatchUpdate(presentationId, body).Do()

Java

slides/snippets/src/main/java/TextMerging.java
import com.google.api.client.googleapis.json.GoogleJsonError;
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.model.File;
import com.google.api.services.sheets.v4.Sheets;
import com.google.api.services.sheets.v4.model.ValueRange;
import com.google.api.services.slides.v1.Slides;
import com.google.api.services.slides.v1.SlidesScopes;
import com.google.api.services.slides.v1.model.BatchUpdatePresentationRequest;
import com.google.api.services.slides.v1.model.BatchUpdatePresentationResponse;
import com.google.api.services.slides.v1.model.ReplaceAllTextRequest;
import com.google.api.services.slides.v1.model.Request;
import com.google.api.services.slides.v1.model.Response;
import com.google.api.services.slides.v1.model.SubstringMatchCriteria;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/* Class to demonstrate the use of Slides Text Merging API */
public class TextMerging {
  /**
   * Changes specified texts with data from spreadsheet.
   *
   * @param templatePresentationId - id of the presentation.
   * @param dataSpreadsheetId      - id of the spreadsheet containing data.
   * @return merged presentation id
   * @throws IOException - if credentials file not found.
   */
  public static List<BatchUpdatePresentationResponse> textMerging(
      String templatePresentationId, String dataSpreadsheetId) throws IOException {
        /* Load pre-authorized user credentials from the environment.
           TODO(developer) - See https://developers.google.com/identity for
            guides on implementing OAuth2 for your application. */
    GoogleCredentials credentials = GoogleCredentials.getApplicationDefault()
        .createScoped(Arrays.asList(SlidesScopes.PRESENTATIONS,
            SlidesScopes.DRIVE, SlidesScopes.SPREADSHEETS));
    HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(
        credentials);

    // Create the slides API client
    Slides service = new Slides.Builder(new NetHttpTransport(),
        GsonFactory.getDefaultInstance(),
        requestInitializer)
        .setApplicationName("Slides samples")
        .build();

    // Create the drive API client
    Drive driveService = new Drive.Builder(new NetHttpTransport(),
        GsonFactory.getDefaultInstance(),
        requestInitializer)
        .setApplicationName("Slides samples")
        .build();

    // Create the sheets API client
    Sheets sheetsService = new Sheets.Builder(new NetHttpTransport(),
        GsonFactory.getDefaultInstance(),
        requestInitializer)
        .setApplicationName("Slides samples")
        .build();

    List<BatchUpdatePresentationResponse> responses = new ArrayList<>(5);
    // Use the Sheets API to load data, one record per row.
    String dataRangeNotation = "Customers!A2:M6";
    ValueRange sheetsResponse = sheetsService.spreadsheets().values()
        .get(dataSpreadsheetId, dataRangeNotation).execute();
    List<List<Object>> values = sheetsResponse.getValues();

    try {
      // For each record, create a new merged presentation.
      for (List<Object> row : values) {
        String customerName = row.get(2).toString();     // name in column 3
        String caseDescription = row.get(5).toString();  // case description in column 6
        String totalPortfolio = row.get(11).toString();  // total portfolio in column 12

        // Duplicate the template presentation using the Drive API.
        String copyTitle = customerName + " presentation";
        File content = new File().setName(copyTitle);
        File presentationFile =
            driveService.files().copy(templatePresentationId, content).execute();
        String presentationId = presentationFile.getId();

        // Create the text merge (replaceAllText) requests for this presentation.
        List<Request> requests = new ArrayList<>();
        requests.add(new Request()
            .setReplaceAllText(new ReplaceAllTextRequest()
                .setContainsText(new SubstringMatchCriteria()
                    .setText("{{customer-name}}")
                    .setMatchCase(true))
                .setReplaceText(customerName)));
        requests.add(new Request()
            .setReplaceAllText(new ReplaceAllTextRequest()
                .setContainsText(new SubstringMatchCriteria()
                    .setText("{{case-description}}")
                    .setMatchCase(true))
                .setReplaceText(caseDescription)));
        requests.add(new Request()
            .setReplaceAllText(new ReplaceAllTextRequest()
                .setContainsText(new SubstringMatchCriteria()
                    .setText("{{total-portfolio}}")
                    .setMatchCase(true))
                .setReplaceText(totalPortfolio)));

        // Execute the requests for this presentation.
        BatchUpdatePresentationRequest body =
            new BatchUpdatePresentationRequest().setRequests(requests);
        BatchUpdatePresentationResponse response =
            service.presentations().batchUpdate(presentationId, body).execute();

        // Count total number of replacements made.
        int numReplacements = 0;
        for (Response resp : response.getReplies()) {
          numReplacements += resp.getReplaceAllText().getOccurrencesChanged();
        }
        // Prints the merged presentation id and count of replacements.
        System.out.println("Created merged presentation for " +
            customerName + " with ID: " + presentationId);
        System.out.println("Replaced " + numReplacements + " text instances.");
      }
    } catch (NullPointerException ne) {
      System.out.println("Text not found to replace with image.");
    } catch (GoogleJsonResponseException e) {
      // TODO(developer) - handle error appropriately
      GoogleJsonError error = e.getDetails();
      if (error.getCode() == 404) {
        System.out.printf("Presentation not found with id '%s'.\n", templatePresentationId);
      } else {
        throw e;
      }
    }
    return responses;
  }
}

JavaScript

slides/snippets/slides_text_merging.js
function textMerging(templatePresentationId, dataSpreadsheetId, callback) {
  // Use the Sheets API to load data, one record per row.
  const responses = [];
  const dataRangeNotation = 'Customers!A2:M6';
  try {
    gapi.client.sheets.spreadsheets.values.get({
      spreadsheetId: dataSpreadsheetId,
      range: dataRangeNotation,
    }).then((sheetsResponse) => {
      const values = sheetsResponse.result.values;
      // For each record, create a new merged presentation.
      for (let i = 0; i < values.length; ++i) {
        const row = values[i];
        const customerName = row[2]; // name in column 3
        const caseDescription = row[5]; // case description in column 6
        const totalPortfolio = row[11]; // total portfolio in column 12

        // Duplicate the template presentation using the Drive API.
        const copyTitle = customerName + ' presentation';
        const request = {
          name: copyTitle,
        };
        gapi.client.drive.files.copy({
          fileId: templatePresentationId,
          requests: request,
        }).then((driveResponse) => {
          const presentationCopyId = driveResponse.result.id;

          // Create the text merge (replaceAllText) requests for this presentation.
          const requests = [{
            replaceAllText: {
              containsText: {
                text: '{{customer-name}}',
                matchCase: true,
              },
              replaceText: customerName,
            },
          }, {
            replaceAllText: {
              containsText: {
                text: '{{case-description}}',
                matchCase: true,
              },
              replaceText: caseDescription,
            },
          }, {
            replaceAllText: {
              containsText: {
                text: '{{total-portfolio}}',
                matchCase: true,
              },
              replaceText: totalPortfolio,
            },
          }];

          // Execute the requests for this presentation.
          gapi.client.slides.presentations.batchUpdate({
            presentationId: presentationCopyId,
            requests: requests,
          }).then((batchUpdateResponse) => {
            const result = batchUpdateResponse.result;
            responses.push(result.replies);
            // Count the total number of replacements made.
            let numReplacements = 0;
            for (let i = 0; i < result.replies.length; ++i) {
              numReplacements += result.replies[i].replaceAllText.occurrencesChanged;
            }
            console.log(`Created presentation for ${customerName} with ID: ${presentationCopyId}`);
            console.log(`Replaced ${numReplacements} text instances`);
            if (responses.length === values.length) { // callback for the last value
              if (callback) callback(responses);
            }
          });
        });
      }
    });
  } catch (err) {
    document.getElementById('content').innerText = err.message;
    return;
  }
}

Node.js

slides/snippets/slides_text_merging.js
/**
 * Adds data from a spreadsheet to a template presentation.
 * @param {string} templatePresentationId The template presentation ID.
 * @param {string} dataSpreadsheetId  The data spreadsheet ID.
 */
async function textMerging(templatePresentationId, dataSpreadsheetId) {
  const {GoogleAuth} = require('google-auth-library');
  const {google} = require('googleapis');

  const auth = new GoogleAuth({
    scopes: [
      'https://www.googleapis.com/auth/presentations',
      'https://www.googleapis.com/auth/drive',
      'https://www.googleapis.com/auth/spreadsheets',
    ],
  });

  const slidesService = google.slides({version: 'v1', auth});
  const sheetsService = google.sheets({version: 'v4', auth});
  const driveService = google.drive({version: 'v2', auth});

  // Use the Sheets API to load data, one record per row.
  const responses = [];
  const dataRangeNotation = 'A2:M6';

  try {
    const sheetsResponse = await sheetsService.spreadsheets.values.get({
      spreadsheetId: dataSpreadsheetId,
      range: dataRangeNotation,
    });
    const values = sheetsResponse.data.values;

    // For each record, create a new merged presentation.
    for (let i = 0; i < values.length; ++i) {
      const row = values[i];
      const customerName = row[2]; // name in column 3
      const caseDescription = row[5]; // case description in column 6
      const totalPortfolio = row[11]; // total portfolio in column 12

      // Duplicate the template presentation using the Drive API.
      const copyTitle = customerName + ' presentation';
      let requests = {
        name: copyTitle,
      };

      const driveResponse = await driveService.files.copy({
        fileId: templatePresentationId,
        requests,
      });

      const presentationCopyId = driveResponse.data.id;
      // Create the text merge (replaceAllText) requests for this presentation.
      requests = [
        {
          replaceAllText: {
            containsText: {
              text: '{{customer-name}}',
              matchCase: true,
            },
            replaceText: customerName,
          },
        },
        {
          replaceAllText: {
            containsText: {
              text: '{{case-description}}',
              matchCase: true,
            },
            replaceText: caseDescription,
          },
        },
        {
          replaceAllText: {
            containsText: {
              text: '{{total-portfolio}}',
              matchCase: true,
            },
            replaceText: totalPortfolio,
          },
        },
      ];
      // Execute the requests for this presentation.
      const batchUpdateResponse = await slidesService.presentations.batchUpdate(
          {
            presentationId: presentationCopyId,
            resource: {
              requests,
            },
          },
      );
      const result = batchUpdateResponse.data;
      // Count the total number of replacements made.
      let numReplacements = 0;
      for (let i = 0; i < result.replies.length; ++i) {
        numReplacements += result.replies[i].replaceAllText.occurrencesChanged;
      }
      console.log(
          `Created presentation for ${customerName} with ID: ` +
          presentationCopyId,
      );
      console.log(`Replaced ${numReplacements} text instances`);
      return result;
    }
  } catch (err) {
    // TODO (developer) - Handle exception
    throw err;
  }
}

PHP

slides/snippets/src/SlidesTextMerging.php
use Google\Client;
use Google\Service\Drive;
use Google\Service\Slides;
use Google\Service\Slides\Request;

function textMerging($templatePresentationId, $dataSpreadsheetId)
{

    /* Load pre-authorized user credentials from the environment.
       TODO(developer) - See https://developers.google.com/identity for
        guides on implementing OAuth2 for your application. */
    $client = new Google\Client();
    $client->useApplicationDefaultCredentials();
    $client->addScope(Google\Service\Drive::DRIVE);
    $slidesService = new Google_Service_Slides($client);
    $driveService = new Google_Service_Drive($client);
    $sheetsService = new Google_Service_Sheets($client);
    try {
        $responses = array();
        // Use the Sheets API to load data, one record per row.
        $dataRangeNotation = 'Customers!A2:M6';
        $sheetsResponse =
            $sheetsService->spreadsheets_values->get($dataSpreadsheetId, $dataRangeNotation);
        $values = $sheetsResponse['values'];

        // For each record, create a new merged presentation.
        foreach ($values as $row) {
            $customerName = $row[2];     // name in column 3
            $caseDescription = $row[5];  // case description in column 6
            $totalPortfolio = $row[11];  // total portfolio in column 12

            // Duplicate the template presentation using the Drive API.
            $copy = new Google_Service_Drive_DriveFile(array(
                'name' => $customerName . ' presentation'
            ));
            $driveResponse = $driveService->files->copy($templatePresentationId, $copy);
            $presentationCopyId = $driveResponse->id;

            // Create the text merge (replaceAllText) requests for this presentation.
            $requests = array();
            $requests[] = new Google_Service_Slides_Request(array(
                'replaceAllText' => array(
                    'containsText' => array(
                        'text' => '{{customer-name}}',
                        'matchCase' => true
                    ),
                    'replaceText' => $customerName
                )
            ));
            $requests[] = new Google_Service_Slides_Request(array(
                'replaceAllText' => array(
                    'containsText' => array(
                        'text' => '{{case-description}}',
                        'matchCase' => true
                    ),
                    'replaceText' => $caseDescription
                )
            ));
            $requests[] = new Google_Service_Slides_Request(array(
                'replaceAllText' => array(
                    'containsText' => array(
                        'text' => '{{total-portfolio}}',
                        'matchCase' => true
                    ),
                    'replaceText' => $totalPortfolio
                )
            ));

            // Execute the requests for this presentation.
            $batchUpdateRequest = new Google_Service_Slides_BatchUpdatePresentationRequest(array(
                'requests' => $requests
            ));
            $response =
                $slidesService->presentations->batchUpdate($presentationCopyId, $batchUpdateRequest);
            $responses[] = $response;
            // Count the total number of replacements made.
            $numReplacements = 0;
            foreach ($response->getReplies() as $reply) {
                $numReplacements += $reply->getReplaceAllText()->getOccurrencesChanged();
            }
            printf("Created presentation for %s with ID: %s\n", $customerName, $presentationCopyId);
            printf("Replaced %d text instances.\n", $numReplacements);
        }
        return $responses;
    } catch (Exception $e) {
        echo 'Message: ' . $e->getMessage();
    }
}

Python

slides/snippets/slides_text_merging.py
import google.auth
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError


def text_merging(template_presentation_id, data_spreadsheet_id):
  """
  Run Text merging the user has access to.
  Load pre-authorized user credentials from the environment.
  TODO(developer) - See https://developers.google.com/identity
  for guides on implementing OAuth2 for the application.
  """
  creds, _ = google.auth.default()
  # pylint: disable=maybe-no-member

  try:
    service = build("slides", "v1", credentials=creds)
    sheets_service = build("sheets", "v4", credentials=creds)
    drive_service = build("drive", "v3", credentials=creds)
    # Use the Sheets API to load data, one record per row.
    data_range_notation = "Customers!A2:M6"
    sheets_response = (
        sheets_service.spreadsheets()
        .values()
        .get(spreadsheetId=data_spreadsheet_id, range=data_range_notation)
        .execute()
    )
    values = sheets_response.get("values")

    # For each record, create a new merged presentation.
    for row in values:
      customer_name = row[2]  # name in column 3
      case_description = row[5]  # case description in column 6
      total_portfolio = row[11]  # total portfolio in column 12

      # Duplicate the template presentation using the Drive API.
      copy_title = customer_name + " presentation"
      body = {"name": copy_title}
      drive_response = (
          drive_service.files()
          .copy(fileId=template_presentation_id, body=body)
          .execute()
      )
      presentation_copy_id = drive_response.get("id")

      # Create the text merge (replaceAllText) requests
      # for this presentation.
      requests = [
          {
              "replaceAllText": {
                  "containsText": {
                      "text": "{{customer-name}}",
                      "matchCase": True,
                  },
                  "replaceText": customer_name,
              }
          },
          {
              "replaceAllText": {
                  "containsText": {
                      "text": "{{case-description}}",
                      "matchCase": True,
                  },
                  "replaceText": case_description,
              }
          },
          {
              "replaceAllText": {
                  "containsText": {
                      "text": "{{total-portfolio}}",
                      "matchCase": True,
                  },
                  "replaceText": total_portfolio,
              }
          },
      ]

      # Execute the requests for this presentation.
      body = {"requests": requests}
      response = (
          service.presentations()
          .batchUpdate(presentationId=presentation_copy_id, body=body)
          .execute()
      )

      # Count the total number of replacements made.
      num_replacements = 0
      for reply in response.get("replies"):
        if reply.get("occurrencesChanged") is not None:
          num_replacements += reply.get("replaceAllText").get(
              "occurrencesChanged"
          )
      print(
          "Created presentation for "
          f"{customer_name} with ID: {presentation_copy_id}"
      )
      print(f"Replaced {num_replacements} text instances")

  except HttpError as error:
    print(f"An error occurred: {error}")
    return error


if __name__ == "__main__":
  # Put the template_presentation_id, data_spreadsheet_id
  # of slides

  text_merging(
      "10QnVUx1X2qHsL17WUidGpPh_SQhXYx40CgIxaKk8jU4",
      "17eqFZl_WK4WVixX8PjvjfLD77DraoFwMDXeiHB3dvuM",
  )

Ruby

slides/snippets/lib/file_snippets.rb
# Use the Sheets API to load data, one record per row.
data_range_notation = 'Customers!A2:M6'
sheets_response = sheets_service.get_spreadsheet_values(
  data_spreadsheet_id,
  data_range_notation
)
values = sheets_response.values

# For each record, create a new merged presentation.
values.each do |row|
  customer_name = row[2]       # name in column 3
  case_description = row[5]    # case description in column 6
  total_portfolio = row[11]    # total portfolio in column 12

  # Duplicate the template presentation using the Drive API.
  copy_title = customer_name + ' presentation'
  body = Google::Apis::SlidesV1::Presentation.new
  body.title = copy_title
  drive_response = drive_service.copy_file(template_presentation_id, body)
  presentation_copy_id = drive_response.id

  # Create the text merge (replace_all_text) requests for this presentation.
  requests = [] << {
    replace_all_text: {
      contains_text: {
        text:       '{{customer-name}}',
        match_case: true
      },
      replace_text:  customer_name
    }
  } << {
    replace_all_text: {
      contains_text: {
        text:       '{{case-description}}',
        match_case: true
      },
      replace_text:  case_description
    }
  } << {
    replace_all_text: {
      contains_text: {
        text:       '{{total-portfolio}}',
        match_case: true
      },
      replace_text:  total_portfolio
    }
  }

  # Execute the requests for this presentation.
  req = Google::Apis::SlidesV1::BatchUpdatePresentationRequest.new(requests: requests)
  response = slides_service.batch_update_presentation(
    presentation_copy_id,
    req
  )

دمج الصور

يمكنك أيضًا دمج الصور في عرضك التقديمي باستخدام طلب replaceAllShapesWithImage. يستبدل هذا الطلب جميع المثيلات للأشكال التي تحتوي على السلسلة النصية المقدَّمة بالصورة المقدَّمة. يحدِّد الطلب تلقائيًا موضع الصورة ويغيّر حجمها ليتم احتواؤها ضمن حدود شكل العلامة مع الحفاظ على نسبة العرض إلى الارتفاع للصورة.

مثال

يستخدم هذا المثال Google Drive API لنسخ نموذج عرض تقديمي، ما يؤدي إلى إنشاء مثيل جديد للعرض التقديمي. بعد ذلك، يستخدم التطبيق واجهة برمجة التطبيقات Slides API للعثور على أي شكل يتضمّن النص {{company-logo}} واستبداله بصورة شعار الشركة. يستبدل الطلب أيضًا أي شكل بالنص {{customer-graphic}} بصورة مختلفة.

برمجة تطبيقات

slides/api/Snippets.gs
/**
 * Duplicate the template presentation using the Drive API.
 * @param {string} templatePresentationId
 * @param {string} imageUrl
 * @param {string} customerName
 * @returns {*}
 */
function imageMerging(templatePresentationId, imageUrl, customerName) {
  const logoUrl = imageUrl;
  const customerGraphicUrl = imageUrl;

  const copyTitle = customerName + ' presentation';
  let copyFile = {
    title: copyTitle,
    parents: [{id: 'root'}]
  };

  try {
    copyFile = Drive.Files.copy(copyFile, templatePresentationId);
    const presentationCopyId = copyFile.id;

    // Create the image merge (replaceAllShapesWithImage) requests.
    const requests = [{
      replaceAllShapesWithImage: {
        imageUrl: logoUrl,
        imageReplaceMethod: 'CENTER_INSIDE',
        containsText: {
          text: '{{company-logo}}',
          matchCase: true
        }
      }
    }, {
      replaceAllShapesWithImage: {
        imageUrl: customerGraphicUrl,
        imageReplaceMethod: 'CENTER_INSIDE',
        containsText: {
          text: '{{customer-graphic}}',
          matchCase: true
        }
      }
    }];

    // Execute the requests for this presentation.
    let batchUpdateResponse = Slides.Presentations.batchUpdate({
      requests: requests
    }, presentationCopyId);
    let numReplacements = 0;
    batchUpdateResponse.replies.forEach(function(reply) {
      numReplacements += reply.replaceAllShapesWithImage.occurrencesChanged;
    });
    console.log('Created merged presentation with ID: %s', presentationCopyId);
    console.log('Replaced %s shapes with images.', numReplacements);

    return batchUpdateResponse;
  } catch (err) {
    // TODO (Developer) - Handle exception
    console.log('Failed with error: %s', err.error);
  }
};

البدء

slides/snippets/presentations.go
// Duplicate the template presentation using the Drive API.
copyTitle := customerName + " presentation"
file := drive.File{
	Title: copyTitle,
}
presentationFile, _ := driveService.Files.Copy(templatePresentationId, &file).Do()
presentationId := presentationFile.Id

// Create the image merge (replaceAllShapesWithImage) requests.
requests := []*slides.Request{{
	ReplaceAllShapesWithImage: &slides.ReplaceAllShapesWithImageRequest{
		ImageUrl:      logoURL,
		ReplaceMethod: "CENTER_INSIDE",
		ContainsText: &slides.SubstringMatchCriteria{
			Text:      "{{company-logo}}",
			MatchCase: true,
		},
	},
}, {
	ReplaceAllShapesWithImage: &slides.ReplaceAllShapesWithImageRequest{
		ImageUrl:      customerGraphicURL,
		ReplaceMethod: "CENTER_INSIDE",
		ContainsText: &slides.SubstringMatchCriteria{
			Text:      "{{customer-graphic}}",
			MatchCase: true,
		},
	},
}}

// Execute the requests for this presentation.
body := &slides.BatchUpdatePresentationRequest{Requests: requests}
response, _ := slidesService.Presentations.BatchUpdate(presentationId, body).Do()

// Count total number of replacements made.
var numReplacements int64 = 0
for _, resp := range response.Replies {
	numReplacements += resp.ReplaceAllShapesWithImage.OccurrencesChanged
}
fmt.Printf("Created merged presentation with ID %s\n", presentationId)
fmt.Printf("Replaced %d shapes instances with images.\n", numReplacements)

Java

slides/snippets/src/main/java/ImageMerging.java
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.model.File;
import com.google.api.services.slides.v1.Slides;
import com.google.api.services.slides.v1.SlidesScopes;
import com.google.api.services.slides.v1.model.BatchUpdatePresentationRequest;
import com.google.api.services.slides.v1.model.BatchUpdatePresentationResponse;
import com.google.api.services.slides.v1.model.Request;
import com.google.api.services.slides.v1.model.Response;
import com.google.api.services.slides.v1.model.ReplaceAllShapesWithImageRequest;
import com.google.api.services.slides.v1.model.SubstringMatchCriteria;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/* Class to demonstrate the use of Slides Image Merging API */
public class ImageMerging {
  /**
   * Changes specified texts into images.
   *
   * @param templatePresentationId - id of the presentation.
   * @param imageUrl               - Url of the image.
   * @param customerName           - Name of the customer.
   * @return merged presentation id
   * @throws IOException - if credentials file not found.
   */
  public static BatchUpdatePresentationResponse imageMerging(String templatePresentationId,
                                                             String imageUrl,
                                                             String customerName)
      throws IOException {
        /* Load pre-authorized user credentials from the environment.
           TODO(developer) - See https://developers.google.com/identity for
            guides on implementing OAuth2 for your application. */
    GoogleCredentials credentials = GoogleCredentials.getApplicationDefault()
        .createScoped(Arrays.asList(SlidesScopes.PRESENTATIONS,
            SlidesScopes.DRIVE));
    HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(
        credentials);

    // Create the slides API client
    Slides service = new Slides.Builder(new NetHttpTransport(),
        GsonFactory.getDefaultInstance(),
        requestInitializer)
        .setApplicationName("Slides samples")
        .build();

    // Create the drive API client
    Drive driveService = new Drive.Builder(new NetHttpTransport(),
        GsonFactory.getDefaultInstance(),
        requestInitializer)
        .setApplicationName("Slides samples")
        .build();

    // Duplicate the template presentation using the Drive API.
    String copyTitle = customerName + " presentation";
    File content = new File().setName(copyTitle);
    File presentationFile =
        driveService.files().copy(templatePresentationId, content).execute();
    String presentationId = presentationFile.getId();

    // Create the image merge (replaceAllShapesWithImage) requests.
    List<Request> requests = new ArrayList<>();
    requests.add(new Request()
        .setReplaceAllShapesWithImage(new ReplaceAllShapesWithImageRequest()
            .setImageUrl(imageUrl)
            .setImageReplaceMethod("CENTER_INSIDE")
            .setContainsText(new SubstringMatchCriteria()
                .setText("{{company-logo}}")
                .setMatchCase(true))));

    // Execute the requests.
    BatchUpdatePresentationRequest body =
        new BatchUpdatePresentationRequest().setRequests(requests);
    BatchUpdatePresentationResponse response =
        service.presentations().batchUpdate(presentationId, body).execute();

    int numReplacements = 0;
    try {
      // Count total number of replacements made.
      for (Response resp : response.getReplies()) {
        numReplacements += resp.getReplaceAllShapesWithImage().getOccurrencesChanged();
      }

      // Prints the merged presentation id and count of replacements.
      System.out.println("Created merged presentation with ID: " + presentationId);
      System.out.println("Replaced " + numReplacements + " shapes instances with images.");
    } catch (NullPointerException ne) {
      System.out.println("Text not found to replace with image.");
    }
    return response;
  }
}

JavaScript

slides/snippets/slides_image_merging.js
function imageMerging(
    templatePresentationId,
    imageUrl,
    customerName,
    callback,
) {
  const logoUrl = imageUrl;
  const customerGraphicUrl = imageUrl;

  // Duplicate the template presentation using the Drive API.
  const copyTitle = customerName + ' presentation';
  try {
    gapi.client.drive.files
        .copy({
          fileId: templatePresentationId,
          resource: {
            name: copyTitle,
          },
        })
        .then((driveResponse) => {
          const presentationCopyId = driveResponse.result.id;

          // Create the image merge (replaceAllShapesWithImage) requests.
          const requests = [
            {
              replaceAllShapesWithImage: {
                imageUrl: logoUrl,
                replaceMethod: 'CENTER_INSIDE',
                containsText: {
                  text: '{{company-logo}}',
                  matchCase: true,
                },
              },
            },
            {
              replaceAllShapesWithImage: {
                imageUrl: customerGraphicUrl,
                replaceMethod: 'CENTER_INSIDE',
                containsText: {
                  text: '{{customer-graphic}}',
                  matchCase: true,
                },
              },
            },
          ];
          // Execute the requests for this presentation.
          gapi.client.slides.presentations
              .batchUpdate({
                presentationId: presentationCopyId,
                requests: requests,
              })
              .then((batchUpdateResponse) => {
                let numReplacements = 0;
                for (
                  let i = 0;
                  i < batchUpdateResponse.result.replies.length;
                  ++i
                ) {
                  numReplacements +=
                batchUpdateResponse.result.replies[i].replaceAllShapesWithImage
                    .occurrencesChanged;
                }
                console.log(
                    `Created merged presentation with ID: ${presentationCopyId}`,
                );
                console.log(`Replaced ${numReplacements} shapes with images.`);
                if (callback) callback(batchUpdateResponse.result);
              });
        });
  } catch (err) {
    document.getElementById('content').innerText = err.message;
    return;
  }
}

Node.js

slides/snippets/slides_image_merging.js
/**
 * Add an image to a template presentation.
 * @param {string} templatePresentationId The template presentation ID.
 * @param {string} imageUrl The image URL
 * @param {string} customerName A customer name used for the title
 */
async function imageMerging(templatePresentationId, imageUrl, customerName) {
  const {GoogleAuth} = require('google-auth-library');
  const {google} = require('googleapis');

  const auth = new GoogleAuth({
    scopes: [
      'https://www.googleapis.com/auth/presentations',
      'https://www.googleapis.com/auth/drive',
    ],
  });

  const slidesService = google.slides({version: 'v1', auth});
  const driveService = google.drive({version: 'v2', auth});
  const logoUrl = imageUrl;
  const customerGraphicUrl = imageUrl;

  // Duplicate the template presentation using the Drive API.
  const copyTitle = customerName + ' presentation';
  try {
    const driveResponse = await driveService.files.copy({
      fileId: templatePresentationId,
      resource: {
        name: copyTitle,
      },
    });
    const presentationCopyId = driveResponse.data.id;

    // Create the image merge (replaceAllShapesWithImage) requests.
    const requests = [
      {
        replaceAllShapesWithImage: {
          imageUrl: logoUrl,
          replaceMethod: 'CENTER_INSIDE',
          containsText: {
            text: '{{company-logo}}',
            matchCase: true,
          },
        },
      },
      {
        replaceAllShapesWithImage: {
          imageUrl: customerGraphicUrl,
          replaceMethod: 'CENTER_INSIDE',
          containsText: {
            text: '{{customer-graphic}}',
            matchCase: true,
          },
        },
      },
    ];

    // Execute the requests for this presentation.
    const batchUpdateResponse = await slidesService.presentations.batchUpdate({
      presentationId: presentationCopyId,
      resource: {
        requests,
      },
    });
    let numReplacements = 0;
    for (let i = 0; i < batchUpdateResponse.data.replies.length; ++i) {
      numReplacements +=
        batchUpdateResponse.data.replies[i].replaceAllShapesWithImage
            .occurrencesChanged;
    }
    console.log(`Created merged presentation with ID: ${presentationCopyId}`);
    console.log(`Replaced ${numReplacements} shapes with images.`);
    return batchUpdateResponse.data;
  } catch (err) {
    // TODO (developer) - Handle exception
    throw err;
  }
}

PHP

slides/snippets/src/SlidesImageMerging.php
use Google\Client;
use Google\Service\Drive;
use Google\Service\Slides;
use Google\Service\DriveFile;
use Google\Service\Slides\Request;


function imageMerging($templatePresentationId, $imageUrl, $customerName)
{
    /* Load pre-authorized user credentials from the environment.
       TODO(developer) - See https://developers.google.com/identity for
        guides on implementing OAuth2 for your application. */
    $client = new Google\Client();
    $client->useApplicationDefaultCredentials();
    $client->addScope(Google\Service\Drive::DRIVE);
    $slidesService = new Google_Service_Slides($client);
    $driveService = new Google_Service_Drive($client);
    // Duplicate the template presentation using the Drive API.
    $copy = new Google_Service_Drive_DriveFile([
        'name' => $customerName . ' presentation'
    ]);

    $driveResponse = $driveService->files->copy($templatePresentationId, $copy);
    $presentationCopyId = $driveResponse->id;

    // Create the image merge (replaceAllShapesWithImage) requests.

    $requests[] = new Google_Service_Slides_Request([
        'replaceAllShapesWithImage' => [
            'imageUrl' => $imageUrl,
            'replaceMethod' => 'CENTER_INSIDE',
            'containsText' => [
                'text' => '{{company-logo}}',
                'matchCase' => true
            ]
        ]
    ]);
    $requests[] = new Google_Service_Slides_Request([
        'replaceAllShapesWithImage' => [
            'imageUrl' => $imageUrl,
            'replaceMethod' => 'CENTER_INSIDE',
            'containsText' => [
                'text' => '{{customer-graphic}}',
                'matchCase' => true
            ]
        ]
    ]);

    // Execute the requests.
    $batchUpdateRequest = new Google_Service_Slides_BatchUpdatePresentationRequest([
        'requests' => $requests
    ]);
    $response =
        $slidesService->presentations->batchUpdate($presentationCopyId, $batchUpdateRequest);

    // Count the total number of replacements made.
    $numReplacements = 0;
    foreach ($response->getReplies() as $reply) {
        $numReplacements += $reply->getReplaceAllShapesWithImage()->getOccurrencesChanged();
    }
    printf("Created presentation for %s with ID: %s\n", $customerName, $presentationCopyId);
    printf("Replaced %d shapes with images.\n", $numReplacements);
    return $response;
}

Python

slides/snippets/slides_image_merging.py
import google.auth
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError


def image_merging(template_presentation_id, image_url, customer_name):
  """image_merging require template_presentation_id,
  image_url and customer_name
  Load pre-authorized user credentials from the environment.
  TODO(developer) - See https://developers.google.com/identity
  for guides on implementing OAuth2 for the application.
  """
  creds, _ = google.auth.default()
  # pylint: disable=maybe-no-member
  try:
    slides_service = build("slides", "v1", credentials=creds)
    drive_service = build("drive", "v3", credentials=creds)
    logo_url = image_url

    customer_graphic_url = image_url

    # Duplicate the template presentation using the Drive API.
    copy_title = customer_name + " presentation"
    drive_response = (
        drive_service.files()
        .copy(fileId=template_presentation_id, body={"name": copy_title})
        .execute()
    )
    presentation_copy_id = drive_response.get("id")

    # Create the image merge (replaceAllShapesWithImage) requests.
    requests = []
    requests.append(
        {
            "replaceAllShapesWithImage": {
                "imageUrl": logo_url,
                "replaceMethod": "CENTER_INSIDE",
                "containsText": {
                    "text": "{{company-logo}}",
                    "matchCase": True,
                },
            }
        }
    )
    requests.append(
        {
            "replaceAllShapesWithImage": {
                "imageUrl": customer_graphic_url,
                "replaceMethod": "CENTER_INSIDE",
                "containsText": {
                    "text": "{{customer-graphic}}",
                    "matchCase": True,
                },
            }
        }
    )

    # Execute the requests.
    body = {"requests": requests}
    response = (
        slides_service.presentations()
        .batchUpdate(presentationId=presentation_copy_id, body=body)
        .execute()
    )

    # Count the number of replacements made.
    num_replacements = 0

    for reply in response.get("replies"):
      # add below line

      if reply.get("occurrencesChanged") is not None:
        # end tag
        num_replacements += reply.get("replaceAllShapesWithImage").get(
            "occurrencesChanged"
        )

    print(f"Created merged presentation with ID:{presentation_copy_id}")
    print(f"Replaced {num_replacements} shapes with images")
  except HttpError as error:
    print(f"An error occurred: {error}")
    print("Images is not merged")
    return error

  return response


if __name__ == "__main__":
  # Put the template_presentation_id, image_url and customer_name

  image_merging(
      "10QnVUx1X2qHsL17WUidGpPh_SQhXYx40CgIxaKk8jU4",
      "https://www.google.com/images/branding/"
      "googlelogo/2x/googlelogo_color_272x92dp.png",
      "Fake Customer",
  )

Ruby

slides/snippets/lib/file_snippets.rb
# Duplicate the template presentation using the Drive API.
copy_title = customer_name + ' presentation'
body = Google::Apis::SlidesV1::Presentation.new
body.title = copy_title
drive_response = drive_service.copy_file(template_presentation_id, body)
presentation_copy_id = drive_response.id

# Create the image merge (replace_all_shapes_with_image) requests.
requests = [] << {
  replace_all_shapes_with_image: {
    image_url:      logo_url,
    replace_method: 'CENTER_INSIDE',
    contains_text:  {
      text:       '{{company-logo}}',
      match_case: true
    }
  }
} << {
  replace_all_shapes_with_image: {
    image_url:      customer_graphic_url,
    replace_method: 'CENTER_INSIDE',
    contains_text:  {
      text:       '{{customer-graphic}}',
      match_case: true
    }
  }
}

# Execute the requests.
req = Google::Apis::SlidesV1::BatchUpdatePresentationRequest.new(requests: requests)
response = slides_service.batch_update_presentation(
  presentation_copy_id,
  req
)

# Count the number of replacements made.
num_replacements = 0
response.replies.each do |reply|
  num_replacements += reply.replace_all_shapes_with_image.occurrences_changed
end
puts "Created presentation for #{customer_name} with ID: #{presentation_copy_id}"
puts "Replaced #{num_replacements} shapes with images"

استبدال نُسخ معيّنة من مربّع نص أو صورة

تكون طلبات replaceAllText وreplaceAllShapesWithImage مفيدة لاستبدال العلامات في جميع أنحاء العرض التقديمي، ولكن في بعض الأحيان، تحتاج فقط إلى استبدال العناصر وفقًا لمعايير أخرى، مثل الموقع الجغرافي على شريحة معيّنة.

في هذه الحالات، عليك استرداد أرقام تعريف أشكال العلامات التي تريد استبدالها. بالنسبة إلى عمليات استبدال النصوص، يمكنك حذف النص الحالي في هذه الأشكال ثم إدراج النص الجديد (اطّلِع على ตัวอย่าง تعديل نص في شكل محدّد).

عمليات استبدال الصور أكثر تعقيدًا. لدمج صورة، عليك اتّباع الخطوات التالية:

  1. احصل على رقم تعريف شكل العلامة.
  2. انسخ الحجم وحوِّل المعلومات من العلامة.
  3. أضِف صورتك إلى الصفحة باستخدام معلومات الحجم والتحويل.
  4. احذِف شكل العلامة.

قد يتطلّب الحفاظ على نسبة عرض إلى ارتفاع الصورة أثناء توسيعها إلى الحجم المطلوب بعض الحذر، كما هو موضّح في القسم التالي. اطّلِع أيضًا على هذا العيّنة: استبدال علامة شكل بصورة.

الحفاظ على نسبة العرض إلى الارتفاع

عند إنشاء صور باستخدام واجهة برمجة التطبيقات Slides API، تستند عمليات ضبط نسبة العرض إلى الارتفاع إلى حجم الصورة فقط، وليس إلى حجم البيانات وتحويلها. تُعتبَر بيانات الحجم التي تقدّمها في طلب createImage هي الحجم المطلوب للصورة. تُكيّف واجهة برمجة التطبيقات نسبتَي عرض إلى ارتفاع الصورة لتتلاءم مع هذا الحجم المطلوب، ثم تُطبّق عملية التحويل المقدَّمة.

عند استبدال علامة بصورة، يمكنك الحفاظ على نسبة قياس شاشة الصورة من خلال ضبط حجم الصورة ودرجة تكبيرها على النحو التالي:

  • width: يتم ضبطه على حاصل ضرب width وscaleX للعلامة.
  • height: يتم ضبطه على ناتج height وscaleY للعلامة
  • scale_x: تم ضبطه على 1
  • scale_y: تم ضبطه على 1

يؤدي ذلك إلى أن تضبط Slides API نسبة العرض إلى الارتفاع للصورة وفقًا لحجم العلامة المرئية، بدلاً من حجمها غير المُعدَّل (راجِع استبدال علامة شكل بصورة). يؤدي ضبط مَعلمات تغيير الحجم على 1 إلى منع تغيير حجم الصورة مرّتين.

يضمن هذا الترتيب الحفاظ على نسبة العرض إلى الارتفاع للصورة، ويمنع الصورة من تجاوز حجم شكل العلامة. تحتوي الصورة على نقطة المركز نفسها في شكل العلامة.

إدارة النماذج

بالنسبة إلى عروض النماذج التي يحدّدها التطبيق ويملكها، أنشئ النموذج باستخدام حساب مخصّص يمثّل التطبيق. حسابات الخدمة هي خيار جيد وتتجنّب التعقيدات المتعلقة بسياسات Google Workspace التي تفرض قيودًا على المشارَكة.

عند إنشاء نُسخ من العروض التقديمية من النماذج، استخدِم دائمًا بيانات اعتماد المستخدم النهائي. يمنح ذلك المستخدمين إمكانية التحكّم الكامل في العروض الترويجية الناتجة ويمنع مشاكل التوسيع المرتبطة بالحدود المفروضة على كل مستخدم في Google Drive.

لإنشاء نموذج باستخدام حساب خدمة، نفِّذ الخطوات التالية باستخدام بيانات اعتماد التطبيق:

  1. أنشئ عرضًا تقديميًا باستخدام presentations.create في Slides API.
  2. عدِّل الأذونات للسماح لمستلمي العرض التقديمي بقراءته باستخدام permissions.create في واجهة برمجة التطبيقات Drive API.
  3. عدِّل الأذونات للسماح لمؤلفي النماذج بالكتابة فيها باستخدام permissions.create في Drive API.
  4. عدِّل النموذج حسب الحاجة.

لإنشاء مثيل للعرض التقديمي، اتّبِع الخطوات التالية مع بيانات اعتماد المستخدم:

  1. أنشئ نسخة من النموذج باستخدام files.copy في Drive API.
  2. استبدِل القيم باستخدام presentation.batchUpdate في Slides API.