はじめに
GASでPDFなどのファイルのアップロードに対応する
以下のようなアプリを作成します。
ファイルを選択して、処理開始を押すとアップロードが開始されます。
問題なければ以下の様に表示されます。
コード
Code.gs
function processFiles(fileObjects) {
var results = [];
// ファイル格納先のフォルダのIDを指定
var folderId = "ここにフォルダのIDを入れます";
var folder = DriveApp.getFolderById(folderId);
for (var i = 0; i < fileObjects.length; i++) {
var file = fileObjects[i];
var blob = Utilities.newBlob(Utilities.base64Decode(file.data), file.mimeType, file.name);
var uploadedFile = folder.createFile(blob);
var fileId = uploadedFile.getId();
// 処理完了後の表示に使う(要修正)
results.push({ name: file.name, text: file.name, url: file.name });
}
return results;
}
index.html
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<base target="_top">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Web App</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
</head>
<body class="bg-gray-100 dark:bg-gray-900 text-gray-900 dark:text-gray-100">
<div id="app" class="container mx-auto px-4 py-8">
<h1 class="text-3xl font-bold mb-8 text-center">Advanced OCR Web App</h1>
<div class="mb-8">
<label for="fileUpload" class="block text-lg font-medium mb-2">ファイルをアップロード (PDF, PNG, JPG, JPEG)</label>
<input type="file" id="fileUpload" ref="fileUpload" @change="handleFileUpload" multiple accept=".pdf,.png,.jpg,.jpeg" class="block w-full text-sm text-gray-500
file:mr-4 file:py-2 file:px-4
file:rounded-full file:border-0
file:text-sm file:font-semibold
file:bg-blue-50 file:text-blue-700
hover:file:bg-blue-100
"/>
</div>
<button @click="processFiles" :disabled="!files.length || processing" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded disabled:opacity-50 disabled:cursor-not-allowed">
処理開始
</button>
<div v-if="processing" class="mt-4">
<div class="w-full bg-gray-200 rounded-full h-2.5 dark:bg-gray-700">
<div class="bg-blue-600 h-2.5 rounded-full" :style="{ width: `${progress}%` }"></div>
</div>
<p class="text-center mt-2">処理中... {{ progress }}%</p>
</div>
<div v-if="results.length" class="mt-8">
<h2 class="text-2xl font-bold mb-4">処理結果</h2>
<div v-for="(result, index) in results" :key="index" class="mb-4 p-4 bg-white dark:bg-gray-800 rounded shadow">
<h3 class="text-xl font-semibold mb-2">{{ result.name }}</h3>
<pre class="whitespace-pre-wrap">{{ result.text }}</pre>
</div>
</div>
<div v-if="error" class="mt-4 p-4 bg-red-100 border border-red-400 text-red-700 rounded">
{{ error }}
</div>
</div>
<script>
const { createApp, ref, computed } = Vue;
createApp({
setup() {
const files = ref([]);
const results = ref([]);
const processing = ref(false);
const progress = ref(0);
const error = ref('');
const handleFileUpload = (event) => {
files.value = Array.from(event.target.files);
};
const processFiles = async () => {
if (!files.value.length) return;
processing.value = true;
progress.value = 0;
results.value = [];
error.value = '';
const fileObjects = await Promise.all(files.value.map(fileToObject));
try {
const processedResults = await google.script.run
.withSuccessHandler((res) => {
results.value = res;
processing.value = false;
progress.value = 100;
})
.withFailureHandler((err) => {
error.value = `エラーが発生しました: ${err.message || err}`;
processing.value = false;
})
.processFiles(fileObjects);
} catch (err) {
error.value = `エラーが発生しました: ${err.message || err}`;
processing.value = false;
}
};
const fileToObject = (file) => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (e) => {
resolve({
name: file.name,
mimeType: file.type,
data: e.target.result.split(',')[1]
});
progress.value += (100 / files.value.length) / 2;
};
reader.onerror = (e) => reject(e);
reader.readAsDataURL(file);
});
};
return {
files,
results,
processing,
progress,
error,
handleFileUpload,
processFiles
};
}
}).mount('#app');
</script>
</body>
</html>