最近、以下の技術を習得しました(Qiita記事)
LIFFで描画(canvas)して、画像をLINEへ送信する。「お絵描きbot」
https://qiita.com/21HideK/items/022cfdfb7f6f92bf5f46
以前に以下の技術を習得しており、
GASを使い、LINE Botで送信した画像をOCRし、文字情報をLINE Botへ返信 + GoogleSpreadsheetへ記録する。
https://qiita.com/21HideK/items/4005559995ac2f270528
この二つを組み合わせると、疑似チャ〇ンジパッドがつくれるのでは?と思いチャレンジしました。
動作の仕組み
動作の様子
作成手順
1. ImgBBのアカウント作成、 2. LINEbot作成、LIFFを作成
以下の記事を参照してください。
LIFFで描画(canvas)して、画像をLINEへ送信する。「お絵描きbot」
https://qiita.com/21HideK/items/022cfdfb7f6f92bf5f46
3. 以下のコードへ差し替える
① 作成したLIFFスターターアプリ内のコードを
それぞれ(CSS, HTML, JS)、以下のコードに丸ごと書き換える。
効果音は、効果音らぼ(https://soundeffect-lab.info/)から好きな音をダウンロード(100種類)。一つのフォルダ内にsound1.mp3 ~ sound100.mp3 までリネームしたファイルを入れ、フォルダをNetlifyへドラッグアンドドロップでアップロードし、URLをコピー(YOUR_NETLIFY_URL)。
YOUR_LIFF_ID
YOUR_IMGBB_API_KEY
YOUR_NETLIFY_URL
は、ご自分のものへ差し換えてください。
canvasへの描画方法は、
https://tonamao.hatenablog.com/entry/2019/03/03/180739
を参照し作成しました。
index.css
.color > a{
display: inline-block;
width: 40px;
height: 40px;
}
* {
box-sizing: border-box;
}
body{
overflow: hidden; /* スクロールを無効にする */
/* margin: 0; /* マージンをゼロにする */
background: #CCCCCC;
text-align: center;
font-family: 'Courier New', sans-serif;
}
#board {
padding: 0.2em 0.5em;
margin: 2em auto;
width: 320px;
background: #79ffe0;
box-shadow: 0px 0px 0px 10px #79ffd5;
border: dashed 2px white;
}
.title{
padding: 0.0em 0.5em;
margin: 0.5em auto;
width: 300px;
background: #79ffe0;
box-shadow: 0px 0px 0px 10px #79ffd5;
border: dashed 2px white;
}
.title p {
user-select: none;
color: #636e72;
margin: 0;
padding: 2px;
}
canvas{
cursor: pointer;
background: white;
border-radius: 16px;
}
.black {
display: inline-block;
text-decoration: none;
/*background: #87befd;*/
background: #ffeaa7;
width: 40px;
height: 40px;
line-height: 40px;
border-radius: 50%;
text-align: center;
margin-right: 4px;
margin-left: 4px;
margin-top: 0px;
margin-bottom: 0px;
vertical-align: middle;
overflow: hidden;
transition: .4s;
box-shadow:0 0 10px rgb(108, 108, 108);
}
.black i {
/*ボタン自体*/
vertical-align: middle;
color: #272828;
top: 9px;
border-radius: 50%;
font-size: 24px;
}
.black :hover{
opacity:0.5;
}
.eraser {
display: inline-block;
text-decoration: none;
/*background: #87befd;*/
background: #ffeaa7;
width: 40px;
height: 40px;
line-height: 40px;
border-radius: 50%;
text-align: center;
margin-right: 12px;
margin-left: 12px;
margin-top: 0px;
margin-bottom: 0px;
vertical-align: middle;
overflow: hidden;
transition: .4s;
box-shadow:0 0 10px rgb(108, 108, 108);
}
.eraser i {
/*ボタン自体*/
vertical-align: middle;
color: #636e72;
top: 9px;
border-radius: 50%;
font-size: 24px;
}
.eraser :hover{
opacity:0.5;
}
.clear {
display: inline-block;
text-decoration: none;
/*background: #87befd;*/
background: #ffeaa7;
width: 40px;
height: 40px;
line-height: 40px;
border-radius: 50%;
text-align: center;
margin-right: 12px;
margin-left: 12px;
margin-top: 4px;
margin-bottom: 4px;
vertical-align: middle;
overflow: hidden;
transition: .4s;
box-shadow:0 0 10px rgb(108, 108, 108);
}
.clear i {
/*ボタン自体*/
vertical-align: middle;
color: #636e72;
top: 9px;
border-radius: 50%;
font-size: 24px;
}
.clear :hover{
opacity:0.5;
}
.send{
display: flex;
justify-content: center;
}
.button {
width:100px;
height:50px;
font-family:Impact;
font-size:100%;
text-align:center;
box-shadow:0 0 10px rgb(108, 108, 108);
border-radius:20px;
background-color:rgb(245, 227, 123);
}
.button:hover{
opacity:0.8;
}
.kanji {
width:40px;
height:20px;
font-size:100%;
text-align:center;
margin-top: 10px;
margin-bottom: 5px;
box-shadow:0 0 10px rgb(15, 252, 70);
border-radius:10px;
margin-left: auto;
margin-right: auto;
}
.smalltitle {
margin:auto;
text-align:center;
}
.hiragana, .katakana, .kanji_1, .kanji_2, .kanji_3, .kanji_4, .kanji_5, .kanji_6{
width:80px;
height:30px;
font-size:100%;
text-align:center;
box-shadow:0 0 10px rgb(108, 108, 108);
border-radius:10px;
}
.hiragana, .katakana, .kanji_1, .kanji_2, .kanji_3, .kanji_4, .kanji_5, .kanji_6:hover{
opacity:0.8;
}
.hiragana {
background-color:rgb(0, 255, 0);
}
.katakana {
background-color:rgb(0, 255, 255);
}
.kanji_1, .kanji_2, .kanji_3, .kanji_4, .kanji_5, .kanji_6{
background-color:rgb(255, 192, 203);
}
.kanji_4, .kanji_5, .kanji_6{
background-color:rgb(255, 165, 0);
}
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<link rel="stylesheet" href="index.css" />
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
<title>お絵描き</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
</head>
<body>
<div class="title">
<p>もじれん</p>
</div>
<div id="board">
<canvas id="canvas" width="300px" height="300px"></canvas>
</div>
<div class="word">
<div class="kana">
<button class="hiragana" id="hiragana" onclick="hiragana()">ひらがな</button>
<button class="katakana" id="katakana" onclick="katakana()">カタカナ</button>
</div>
<div class = "kanji">
<a class="smalltitle" id="smalltitle">漢字</a><br>
</div>
<div class="kanji_low">
<button class="kanji_1" id="kanji_1" onclick="kanji01()">1年生</button>
<button class="kanji_2" id="kanji_2" onclick="kanji02()">2年生</button>
<button class="kanji_3" id="kanji_3" onclick="kanji03()">3年生</button>
</div>
<div class="kanji_hight">
<button class="kanji_4" id="kanji_4" onclick="kanji04()">4年生</button>
<button class="kanji_5" id="kanji_5" onclick="kanji05()">5年生</button>
<button class="kanji_6" id="kanji_6" onclick="kanji06()">6年生</button>
</div>
</div>
<div class="option">
<a href="#" id="black" class="black" data-color="0, 0, 0, 1" data-bold="5">
<i class="fas fa-paint-brush fa-3x"></i>
</a>
<a href="#" id="eraser" class="eraser" data-color="255, 255, 255, 1" data-bold="20">
<i class="fas fa-eraser fa-3x"></i>
</a>
<a href="#" id="clear" class="clear">
<i class="fas fa-undo-alt fa-3x"></i>
</a>
</div>
<div class="send">
<button class="button" onclick="uploadAndSendToLINE()">Judge!</button>
</div>
<audio id="Sound_effect">
<source id="Sound_kinds" class="Sound_kinds" src="" type="audio/mp3">
</audio>
<script>
window.onload = initializeLIFF;
function initializeLIFF() {
liff.init({
liffId: 'YOUR_LIFF_ID' // あなたのLIFFアプリのIDに置き換えてください
})
.then(() => {
console.log("LIFF initialization successful");
})
.catch((err) => {
console.error("LIFF initialization failed", err);
});
}
// canvas
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
// 変数宣言
const cnvWidth = 300;
const cnvHeight = 300;
var cnvColor = "0, 0, 0, 1"; // 線の色
var cnvBold = 5; // 線の太さ
var drawing = false; // 描画中フラグ
var bgColor = "#ffffff"; //開いた時の最初の背景色(白)
// canvasの背景色を設定(指定がない場合にjpeg保存すると背景が黒になる)
setBgColor();
// canvas上でのイベント
canvas.addEventListener('mousedown', startDrawing);
canvas.addEventListener('mouseup', stopDrawing);
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('touchstart', startDrawing);
canvas.addEventListener('touchend', stopDrawing);
canvas.addEventListener('touchmove', draw);
var netlify_url ="YOUR_NETLIFY_URL"; //YOUR_NETLIFY_URLを書き換えてください。
//ひらがなボタン
function hiragana(){
document.getElementById("hiragana").style.color = "white";
document.getElementById("hiragana").style.background= "blue";
document.getElementById("katakana").style.color = "black";
document.getElementById("katakana").style.background= "aqua";
document.getElementById("kanji_1").style.color = "black";
document.getElementById("kanji_1").style.background= "pink";
document.getElementById("kanji_2").style.color = "black";
document.getElementById("kanji_2").style.background= "pink";
document.getElementById("kanji_3").style.color = "black";
document.getElementById("kanji_3").style.background= "pink";
document.getElementById("kanji_4").style.color = "black";
document.getElementById("kanji_4").style.background= "orange";
document.getElementById("kanji_5").style.color = "black";
document.getElementById("kanji_5").style.background= "orange";
document.getElementById("kanji_6").style.color = "black";
document.getElementById("kanji_6").style.background= "orange";
document.getElementById("Sound_kinds").src = netlify_url + "/sound1.mp3";
document.getElementById("Sound_effect").load();
document.getElementById("Sound_effect").play();
var wordList = [
"あ", "い", "う", "え", "お",
"か", "き", "く", "け", "こ",
"さ", "し", "す", "せ", "そ",
"た", "ち", "つ", "て", "と",
"な", "に", "ぬ", "ね", "の",
"は", "ひ", "ふ", "へ", "ほ",
"ま", "み", "む", "め", "も",
"や", "ゆ", "よ",
"ら", "り", "る", "れ", "ろ",
"わ", "を", "ん"
];
var selectedWord = wordList[Math.floor(Math.random() * wordList.length)];
// 文章の組み立て
var sentence1 = '「' + selectedWord + '」';
var sentence2 = 'を書いてください。';
// Canvasに文章を表示
ctx.clearRect(0, 0, canvas.width, canvas.height);
setBgColor();
// 文字のスタイルを変更
ctx.font = "20px Arial"; // 文字のサイズを大きく
ctx.fillStyle = "red"; // sentence1の文字を赤に
ctx.fillText(sentence1, 10, 30);
ctx.fillStyle = "#000"; //sentence2の文字を黒に
ctx.font = "14px Arial"; // 文字のサイズを小さく
ctx.fillText(sentence2, 70, 30);
};
//カタカナボタン
function katakana(){
document.getElementById("hiragana").style.color = "black";
document.getElementById("hiragana").style.background= "lime";
document.getElementById("katakana").style.color = "white";
document.getElementById("katakana").style.background= "blue";
document.getElementById("kanji_1").style.color = "black";
document.getElementById("kanji_1").style.background= "pink";
document.getElementById("kanji_2").style.color = "black";
document.getElementById("kanji_2").style.background= "pink";
document.getElementById("kanji_3").style.color = "black";
document.getElementById("kanji_3").style.background= "pink";
document.getElementById("kanji_4").style.color = "black";
document.getElementById("kanji_4").style.background= "orange";
document.getElementById("kanji_5").style.color = "black";
document.getElementById("kanji_5").style.background= "orange";
document.getElementById("kanji_6").style.color = "black";
document.getElementById("kanji_6").style.background= "orange";
document.getElementById("Sound_kinds").src = netlify_url + "/sound2.mp3";
document.getElementById("Sound_effect").load();
document.getElementById("Sound_effect").play();
var wordList = [
"ア", "イ", "ウ", "エ", "オ",
"カ", "キ", "ク", "ケ", "コ",
"サ", "シ", "ス", "セ", "ソ",
"タ", "チ", "ツ", "テ", "ト",
"ナ", "ニ", "ヌ", "ネ", "ノ",
"ハ", "ヒ", "フ", "ヘ", "ホ",
"マ", "ミ", "ム", "メ", "モ",
"ヤ", "ユ", "ヨ",
"ラ", "リ", "ル", "レ", "ロ",
"ワ", "ヲ", "ン"
];
var selectedWord = wordList[Math.floor(Math.random() * wordList.length)];
// 文章の組み立て
var sentence1 = '「' + selectedWord + '」';
var sentence2 = 'を書いてください。';
ctx.clearRect(0, 0, canvas.width, canvas.height);
setBgColor();
ctx.font = "20px Arial";
ctx.fillStyle = "red";
ctx.fillText(sentence1, 10, 30);
ctx.fillStyle = "#000";
ctx.font = "14px Arial";
ctx.fillText(sentence2, 70, 30);
};
//漢字1年生ボタン
function kanji01(){
document.getElementById("hiragana").style.color = "black";
document.getElementById("hiragana").style.background= "lime";
document.getElementById("katakana").style.color = "black";
document.getElementById("katakana").style.background= "aqua";
document.getElementById("kanji_1").style.color = "white";
document.getElementById("kanji_1").style.background= "blue";
document.getElementById("kanji_2").style.color = "black";
document.getElementById("kanji_2").style.background= "pink";
document.getElementById("kanji_3").style.color = "black";
document.getElementById("kanji_3").style.background= "pink";
document.getElementById("kanji_4").style.color = "black";
document.getElementById("kanji_4").style.background= "orange";
document.getElementById("kanji_5").style.color = "black";
document.getElementById("kanji_5").style.background= "orange";
document.getElementById("kanji_6").style.color = "black";
document.getElementById("kanji_6").style.background= "orange";
document.getElementById("Sound_kinds").src = netlify_url + "/sound3.mp3";
document.getElementById("Sound_effect").load();
document.getElementById("Sound_effect").play();
var wordList = [
"一", "右", "雨", "円", "王", "音", "下", "火", "花", "貝",
"学", "気", "九", "休", "玉", "金", "空", "月", "犬", "見",
"五", "口", "校", "左", "三", "山", "子", "四", "糸", "字",
"耳", "七", "車", "手", "十", "出", "女", "小", "上", "森",
"人", "水", "正", "生", "青", "夕", "石", "赤", "千", "川",
"先", "早", "草", "足", "村", "大", "男", "竹", "中", "虫",
"町", "天", "田", "土", "二", "日", "入", "年", "白", "八",
"百", "文", "木", "本", "名", "目", "立", "力", "林", "六"
];
var selectedWord = wordList[Math.floor(Math.random() * wordList.length)];
// 文章の組み立て
var sentence1 = '「' + selectedWord + '」';
var sentence2 = 'を書いてください。';
ctx.clearRect(0, 0, canvas.width, canvas.height);
setBgColor();
ctx.font = "20px Arial";
ctx.fillStyle = "red";
ctx.fillText(sentence1, 10, 30);
ctx.fillStyle = "#000";
ctx.font = "14px Arial";
ctx.fillText(sentence2, 70, 30);
};
//漢字2年生ボタン
function kanji02(){
document.getElementById("hiragana").style.color = "black";
document.getElementById("hiragana").style.background= "lime";
document.getElementById("katakana").style.color = "black";
document.getElementById("katakana").style.background= "aqua";
document.getElementById("kanji_1").style.color = "black";
document.getElementById("kanji_1").style.background= "pink";
document.getElementById("kanji_2").style.color = "white";
document.getElementById("kanji_2").style.background= "blue";
document.getElementById("kanji_3").style.color = "black";
document.getElementById("kanji_3").style.background= "pink";
document.getElementById("kanji_4").style.color = "black";
document.getElementById("kanji_4").style.background= "orange";
document.getElementById("kanji_5").style.color = "black";
document.getElementById("kanji_5").style.background= "orange";
document.getElementById("kanji_6").style.color = "black";
document.getElementById("kanji_6").style.background= "orange";
document.getElementById("Sound_kinds").src = netlify_url + "/sound4.mp3";
document.getElementById("Sound_effect").load();
document.getElementById("Sound_effect").play();
var wordList = [
"引", "羽", "雲", "園", "遠", "何", "科", "夏", "家", "歌",
"画", "回", "会", "海", "絵", "外", "角", "楽", "活", "間",
"丸", "岩", "顔", "汽", "記", "帰", "弓", "牛", "魚", "京",
"強", "教", "近", "兄", "形", "計", "元", "言", "原", "戸",
"古", "午", "後", "語", "工", "公", "広", "交", "光", "考",
"行", "高", "黄", "合", "谷", "国", "黒", "今", "才", "細",
"作", "算", "止", "市", "矢", "姉", "思", "紙", "寺", "自",
"時", "室", "社", "弱", "首", "秋", "週", "春", "書", "少",
"場", "色", "食", "心", "新", "親", "図", "数", "西", "声",
"星", "晴", "切", "雪", "船", "線", "前", "組", "走", "多",
"太", "体", "台", "地", "池", "知", "茶", "昼", "長", "鳥",
"朝", "直", "通", "弟", "店", "点", "電", "刀", "冬", "当",
"東", "答", "頭", "同", "道", "読", "内", "南", "肉", "馬",
"売", "買", "麦", "半", "番", "父", "風", "分", "聞", "米",
"歩", "母", "方", "北", "毎", "妹", "万", "明", "鳴", "毛",
"門", "夜", "野", "友", "用", "曜", "来", "里", "理", "話"
];
var selectedWord = wordList[Math.floor(Math.random() * wordList.length)];
// 文章の組み立て
var sentence1 = '「' + selectedWord + '」';
var sentence2 = 'を書いてください。';
ctx.clearRect(0, 0, canvas.width, canvas.height);
setBgColor();
ctx.font = "20px Arial";
ctx.fillStyle = "red";
ctx.fillText(sentence1, 10, 30);
ctx.fillStyle = "#000";
ctx.font = "14px Arial";
ctx.fillText(sentence2, 70, 30);
};
//漢字3年生ボタン
function kanji03(){
document.getElementById("hiragana").style.color = "black";
document.getElementById("hiragana").style.background= "lime";
document.getElementById("katakana").style.color = "black";
document.getElementById("katakana").style.background= "aqua";
document.getElementById("kanji_1").style.color = "black";
document.getElementById("kanji_1").style.background= "pink";
document.getElementById("kanji_2").style.color = "black";
document.getElementById("kanji_2").style.background= "pink";
document.getElementById("kanji_3").style.color = "white";
document.getElementById("kanji_3").style.background= "blue";
document.getElementById("kanji_4").style.color = "black";
document.getElementById("kanji_4").style.background= "orange";
document.getElementById("kanji_5").style.color = "black";
document.getElementById("kanji_5").style.background= "orange";
document.getElementById("kanji_6").style.color = "black";
document.getElementById("kanji_6").style.background= "orange";
document.getElementById("Sound_kinds").src = netlify_url + "/sound5.mp3";
document.getElementById("Sound_effect").load();
document.getElementById("Sound_effect").play();
var wordList = [
"悪", "安", "暗", "医", "委", "意", "育", "員", "院", "飲",
"運", "泳", "駅", "央", "横", "屋", "温", "化", "荷", "界",
"開", "階", "寒", "感", "漢", "館", "岸", "起", "期", "客",
"究", "急", "級", "宮", "球", "去", "橋", "業", "曲", "局",
"銀", "区", "苦", "具", "君", "係", "軽", "血", "決", "研",
"県", "庫", "湖", "向", "幸", "港", "号", "根", "祭", "皿",
"仕", "死", "使", "始", "指", "歯", "詩", "次", "事", "持",
"式", "実", "写", "者", "主", "守", "取", "酒", "受", "州",
"拾", "終", "習", "集", "住", "重", "宿", "所", "暑", "助",
"昭", "消", "商", "章", "勝", "乗", "植", "申", "身", "神",
"真", "深", "進", "世", "整", "昔", "全", "相", "送", "想",
"息", "速", "族", "他", "打", "対", "待", "代", "第", "題",
"炭", "短", "談", "着", "注", "柱", "丁", "帳", "調", "追",
"定", "庭", "笛", "鉄", "転", "都", "度", "投", "豆", "島",
"湯", "登", "等", "動", "童", "農", "波", "配", "倍", "箱",
"畑", "発", "反", "坂", "板", "皮", "悲", "美", "鼻", "筆",
"氷", "表", "秒", "病", "品", "負", "部", "服", "福", "物",
"平", "返", "勉", "放", "味", "命", "面", "問", "役", "薬",
"由", "油", "有", "遊", "予", "羊", "洋", "葉", "陽", "様",
"落", "流", "旅", "両", "緑", "礼", "列", "練", "路", "和"
];
var selectedWord = wordList[Math.floor(Math.random() * wordList.length)];
// 文章の組み立て
var sentence1 = '「' + selectedWord + '」';
var sentence2 = 'を書いてください。';
ctx.clearRect(0, 0, canvas.width, canvas.height);
setBgColor();
ctx.font = "20px Arial";
ctx.fillStyle = "red";
ctx.fillText(sentence1, 10, 30);
ctx.fillStyle = "#000";
ctx.font = "14px Arial";
ctx.fillText(sentence2, 70, 30);
};
//漢字4年生ボタン
function kanji04(){
document.getElementById("hiragana").style.color = "black";
document.getElementById("hiragana").style.background= "lime";
document.getElementById("katakana").style.color = "black";
document.getElementById("katakana").style.background= "aqua";
document.getElementById("kanji_1").style.color = "black";
document.getElementById("kanji_1").style.background= "pink";
document.getElementById("kanji_2").style.color = "black";
document.getElementById("kanji_2").style.background= "pink";
document.getElementById("kanji_3").style.color = "black";
document.getElementById("kanji_3").style.background= "pink";
document.getElementById("kanji_4").style.color = "white";
document.getElementById("kanji_4").style.background= "blue";
document.getElementById("kanji_5").style.color = "black";
document.getElementById("kanji_5").style.background= "orange";
document.getElementById("kanji_6").style.color = "black";
document.getElementById("kanji_6").style.background= "orange";
document.getElementById("Sound_kinds").src = netlify_url + "/sound6.mp3";
document.getElementById("Sound_effect").load();
document.getElementById("Sound_effect").play();
var wordList = [
"愛", "案", "以", "衣", "位", "囲", "胃", "印", "英", "栄",
"塩", "億", "加", "果", "貨", "課", "芽", "改", "械", "害",
"街", "各", "覚", "完", "官", "管", "関", "観", "願", "希",
"季", "紀", "喜", "旗", "器", "機", "議", "求", "泣", "救",
"給", "挙", "漁", "共", "協", "鏡", "競", "極", "訓", "軍",
"郡", "径", "型", "景", "芸", "欠", "結", "建", "健", "験",
"固", "功", "好", "候", "航", "康", "告", "差", "菜", "最",
"材", "昨", "札", "刷", "殺", "察", "参", "産", "散", "残",
"士", "氏", "史", "司", "試", "児", "治", "辞", "失", "借",
"種", "周", "祝", "順", "初", "松", "笑", "唱", "焼", "象",
"照", "賞", "臣", "信", "成", "省", "清", "静", "席", "積",
"折", "節", "説", "浅", "戦", "選", "然", "争", "倉", "巣",
"束", "側", "続", "卒", "孫", "帯", "隊", "達", "単", "置",
"仲", "貯", "兆", "腸", "低", "底", "停", "的", "典", "伝",
"徒", "努", "灯", "堂", "働", "特", "得", "毒", "熱", "念",
"敗", "梅", "博", "飯", "飛", "費", "必", "票", "標", "不",
"夫", "付", "府", "副", "粉", "兵", "別", "辺", "変", "便",
"包", "法", "望", "牧", "末", "満", "未", "脈", "民", "無",
"約", "勇", "要", "養", "浴", "利", "陸", "良", "料", "量",
"輪", "類", "令", "冷", "例", "歴", "連", "老", "労", "録"
];
var selectedWord = wordList[Math.floor(Math.random() * wordList.length)];
// 文章の組み立て
var sentence1 = '「' + selectedWord + '」';
var sentence2 = 'を書いてください。';
ctx.clearRect(0, 0, canvas.width, canvas.height);
setBgColor();
ctx.font = "20px Arial";
ctx.fillStyle = "red";
ctx.fillText(sentence1, 10, 30);
ctx.fillStyle = "#000";
ctx.font = "14px Arial";
ctx.fillText(sentence2, 70, 30);
};
//漢字5年生ボタン
function kanji05(){
document.getElementById("hiragana").style.color = "black";
document.getElementById("hiragana").style.background= "lime";
document.getElementById("katakana").style.color = "black";
document.getElementById("katakana").style.background= "aqua";
document.getElementById("kanji_1").style.color = "black";
document.getElementById("kanji_1").style.background= "pink";
document.getElementById("kanji_2").style.color = "black";
document.getElementById("kanji_2").style.background= "pink";
document.getElementById("kanji_3").style.color = "black";
document.getElementById("kanji_3").style.background= "pink";
document.getElementById("kanji_4").style.color = "black";
document.getElementById("kanji_4").style.background= "orange";
document.getElementById("kanji_5").style.color = "white";
document.getElementById("kanji_5").style.background= "blue";
document.getElementById("kanji_6").style.color = "black";
document.getElementById("kanji_6").style.background= "orange";
document.getElementById("Sound_kinds").src = netlify_url + "/sound7.mp3";
document.getElementById("Sound_effect").load();
document.getElementById("Sound_effect").play();
var wordList = [
"圧", "移", "因", "永", "営", "衛", "易", "益", "液", "演",
"応", "往", "桜", "恩", "可", "仮", "価", "河", "過", "賀",
"快", "解", "格", "確", "額", "刊", "幹", "慣", "眼", "基",
"寄", "規", "技", "義", "逆", "久", "旧", "居", "許", "境",
"均", "禁", "句", "群", "経", "潔", "件", "券", "険", "検",
"限", "現", "減", "故", "個", "護", "効", "厚", "耕", "鉱",
"構", "興", "講", "混", "査", "再", "災", "妻", "採", "際",
"在", "財", "罪", "雑", "酸", "賛", "支", "志", "枝", "師",
"資", "飼", "示", "似", "識", "質", "舎", "謝", "授", "修",
"述", "術", "準", "序", "招", "承", "証", "条", "状", "常",
"情", "織", "職", "制", "性", "政", "勢", "精", "製", "税",
"責", "績", "接", "設", "舌", "絶", "銭", "祖", "素", "総",
"造", "像", "増", "則", "測", "属", "率", "損", "退", "貸",
"態", "団", "断", "築", "張", "提", "程", "適", "敵", "統",
"銅", "導", "徳", "独", "任", "燃", "能", "破", "犯", "判",
"版", "比", "肥", "非", "備", "俵", "評", "貧", "布", "婦",
"富", "武", "復", "複", "仏", "編", "弁", "保", "墓", "報",
"豊", "防", "貿", "暴", "務", "夢", "迷", "綿", "輸", "余",
"預", "容", "略", "留", "領"
];
var selectedWord = wordList[Math.floor(Math.random() * wordList.length)];
// 文章の組み立て
var sentence1 = '「' + selectedWord + '」';
var sentence2 = 'を書いてください。';
ctx.clearRect(0, 0, canvas.width, canvas.height);
setBgColor();
ctx.font = "20px Arial";
ctx.fillStyle = "red";
ctx.fillText(sentence1, 10, 30);
ctx.fillStyle = "#000";
ctx.font = "14px Arial";
ctx.fillText(sentence2, 70, 30);
};
//漢字6年生ボタン
function kanji06(){
document.getElementById("hiragana").style.color = "black";
document.getElementById("hiragana").style.background= "lime";
document.getElementById("katakana").style.color = "black";
document.getElementById("katakana").style.background= "aqua";
document.getElementById("kanji_1").style.color = "black";
document.getElementById("kanji_1").style.background= "pink";
document.getElementById("kanji_2").style.color = "black";
document.getElementById("kanji_2").style.background= "pink";
document.getElementById("kanji_3").style.color = "black";
document.getElementById("kanji_3").style.background= "pink";
document.getElementById("kanji_4").style.color = "black";
document.getElementById("kanji_4").style.background= "orange";
document.getElementById("kanji_5").style.color = "black";
document.getElementById("kanji_5").style.background= "orange";
document.getElementById("kanji_6").style.color = "white";
document.getElementById("kanji_6").style.background= "blue";
document.getElementById("Sound_kinds").src = netlify_url + "/sound8.mp3";
document.getElementById("Sound_effect").load();
document.getElementById("Sound_effect").play();
var wordList = [
"異", "遺", "域", "宇", "映", "延", "沿", "我", "灰", "拡",
"革", "閣", "割", "株", "干", "巻", "看", "簡", "危", "机",
"揮", "貴", "疑", "吸", "供", "胸", "郷", "勤", "筋", "系",
"敬", "警", "劇", "激", "穴", "絹", "権", "憲", "源", "厳",
"己", "呼", "誤", "后", "孝", "皇", "紅", "降", "鋼", "刻",
"穀", "骨", "困", "砂", "座", "済", "裁", "策", "冊", "蚕",
"至", "私", "姿", "視", "詞", "誌", "磁", "射", "捨", "尺",
"若", "樹", "収", "宗", "就", "衆", "従", "縦", "縮", "熟",
"純", "処", "署", "諸", "除", "将", "傷", "障", "城", "蒸",
"針", "仁", "垂", "推", "寸", "盛", "聖", "誠", "宣", "専",
"泉", "洗", "染", "善", "奏", "窓", "創", "装", "層", "操",
"蔵", "臓", "存", "尊", "宅", "担", "探", "誕", "段", "暖",
"値", "宙", "忠", "著", "庁", "頂", "潮", "賃", "痛", "展",
"討", "党", "糖", "届", "難", "乳", "認", "納", "脳", "派",
"拝", "背", "肺", "俳", "班", "晩", "否", "批", "秘", "腹",
"奮", "並", "陛", "閉", "片", "補", "暮", "宝", "訪", "亡",
"忘", "棒", "枚", "幕", "密", "盟", "模", "訳", "郵", "優",
"幼", "欲", "翌", "乱", "卵", "覧", "裏", "律", "臨", "朗",
"論"
];
var selectedWord = wordList[Math.floor(Math.random() * wordList.length)];
// 文章の組み立て
var sentence1 = '「' + selectedWord + '」';
var sentence2 = 'を書いてください。';
ctx.clearRect(0, 0, canvas.width, canvas.height);
setBgColor();
ctx.font = "20px Arial";
ctx.fillStyle = "red";
ctx.fillText(sentence1, 10, 30);
ctx.fillStyle = "#000";
ctx.font = "14px Arial";
ctx.fillText(sentence2, 70, 30);
};
// 描画処理
function draw(e) {
if (!drawing) return;
var x, y;
if (e.type.startsWith('touch')) {
x = e.touches[0].clientX - canvas.offsetLeft;
y = e.touches[0].clientY - canvas.offsetTop;
} else {
x = e.offsetX;
y = e.offsetY;
}
if (drawing) {
ctx.lineTo(x, y);
ctx.stroke();
}
}
// 描画開始
var lastX = 0;
var lastY = 0;
var x, y;
function startDrawing(e) {
drawing = true;
if (e.type.startsWith('touch')) {
x = e.touches[0].clientX - canvas.offsetLeft;
y = e.touches[0].clientY - canvas.offsetTop;
lastX = e.touches[0].clientX - canvas.getBoundingClientRect().left;
lastY = e.touches[0].clientY - canvas.getBoundingClientRect().top;
} else {
x = e.offsetX;
y = e.offsetY;
lastX = e.clientX - canvas.getBoundingClientRect().left;
lastY = e.clientY - canvas.getBoundingClientRect().top;
}
ctx.lineWidth = cnvBold;
ctx.strokeStyle = 'rgba(' + cnvColor + ')';
ctx.beginPath();
ctx.lineCap = "round";
ctx.moveTo(x, y);
}
// 描画終了
function stopDrawing() {
drawing = false;
}
// 黒線描画
$("#black").click(function () {
cnvColor = $(this).data("color");
ctx.strokeStyle = 'rgba(' + cnvColor + ')';
cnvBold = $(this).data("bold");
return false;
});
// 消しゴム
$("#eraser").click(function () {
cnvColor = $(this).data("color");
ctx.strokeStyle = 'rgba(' + cnvColor + ')';
cnvBold = $(this).data("bold");
return false;
});
// 描画クリア
$("#clear").click(function () {
ctx.clearRect(0, 0, cnvWidth, cnvHeight);
setBgColor();
});
function setBgColor() {
ctx.fillStyle = bgColor;
ctx.fillRect(0, 0, cnvWidth, cnvHeight);
}
// LINEへ描画したものを画像として送信する
function uploadAndSendToLINE() {
// LIFFが初期化されているか確認
if (!liff.isInClient()) {
alert('This app must be viewed in the LINE app.');
return;
}
// Canvasから画像データを取得
var imageDataURL = canvas.toDataURL();
// 画像データをBase64に変換
var base64Image = imageDataURL.replace(/^data:image\/(png|jpg);base64,/, '');
// 画像をImgBBにアップロード
// YOUR_IMGBB_API をあなたのImgBB APIに置き換えてください
fetch('https://api.imgbb.com/1/upload?key=YOUR_IMGBB_API', {
method: 'POST',
body: new URLSearchParams({ image: base64Image, album: 'drawing' }),
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
.then(response => response.json())
.then(data => {
var photoURL = data.data.url;
var last_position = photoURL.indexOf('.png') - 17;
var number = photoURL.substr(17, last_position);
// アップロード成功時にLINEに送信
sendImageMessage(number, data.data.url);
})
.catch(error => {
console.error('Error uploading image', error);
});
}
function sendImageMessage(number, imageUrl) {
// 画像のURLをLINEに送信
liff.sendMessages([
{
type: 'image',
originalContentUrl: imageUrl,
previewImageUrl: imageUrl
},
{
type: "text",
text: number
}
])
.then(() => {
// 1秒ごとにカウントダウンを表示
var count = 10;
var countdownInterval = setInterval(function() {
if (count == 10){
var count_A = "⑩";
}else if(count == 9){
var count_A = "⑨";
}else if(count == 8){
var count_A = "⑧";
}else if(count == 7){
var count_A = "⑦";
}else if(count == 6){
var count_A = "⑥";
}else if(count == 5){
var count_A = "⑤";
}else if(count == 4){
var count_A = "④";
}else if(count == 3){
var count_A = "③";
}else if(count == 2){
var count_A = "②";
}else if(count == 1){
var count_A = "①";
}
if (count >= 1) {
ctx.clearRect(0, 0, cnvWidth, cnvHeight);
ctx.font = "150px Arial";
ctx.fillStyle = "blue";
ctx.textAlign = "center";
ctx.fillText(count_A, cnvWidth / 2, cnvHeight *2/ 3);
count--;
var randomNumber = Math.floor(Math.random() * 100) + 1;
//YOUR_NETLIFY_URL:Netlifyにアップロードした音声ファイルの入ったフォルダのURLを入れてください。
document.getElementById("Sound_kinds").src = netlify_url + "/sound" + randomNumber + ".mp3";
document.getElementById("Sound_effect").load();
document.getElementById("Sound_effect").play();
} else {
clearInterval(countdownInterval);
ctx.clearRect(0, 0, cnvWidth, cnvHeight);
ctx.font = "48px Arial";
ctx.fillStyle = "red";
ctx.textAlign = "center";
ctx.fillText("結果発表!", cnvWidth / 2, cnvHeight / 2);
setTimeout(function() {
liff.closeWindow();
}, 3000); // 3秒後にLIFFを閉じる
}
}, 1000); // 1秒ごとに実行
})
.catch((err) => {
console.error('Error sending image', err);
});
}
</script>
</body>
</html>
index.js
import './index.css';
import liff from '@line/liff'
document.addEventListener("DOMContentLoaded", function() {
liff
.init({ liffId: process.env.LIFF_ID })
.then(() => {
console.log("Success! you can do something with LIFF API here.")
})
.catch((error) => {
console.log(error)
})
});
② 再度、Netlifyへデプロイ
LINE公式サイト
https://developers.line.biz/ja/docs/liff/trying-liff-app/#how-to-start-liff-starter-app
の通りに、再度デプロイ。
netlify build
netlify deploy --prod
4. LIFFへ登録、リッチメニューに登録
https://qiita.com/21HideK/items/4005559995ac2f270528
の5.②を参考に、作成。
LIFF URL(2.②B.でコピーしたもの)を登録し、LINEbotのリッチメニューからLIFFを開けるようにする。
5. LIFFから送られた画像をOCR、文字を判定
ここからは、
GASを使い、LINE Botで送信した画像をOCRし、文字情報をLINE Botへ返信 + GoogleSpreadsheetへ記録する。
https://qiita.com/21HideK/items/4005559995ac2f270528
を参照にしながら作ります。
1.LINE Developersコンソール内での準備~5.LINE Botの設定 の通りに作ります。
3.⑥GASへコードを書きこむ は、以下のコードをコピー&ペーストしてください。
判定を返信するFlex menuの画像を用意。成功、読めない、失敗にそれぞれ10枚の画像を用意、ランダムに表示させる。
"seikou", "yomenai", "sippai"というフォルダを作成、それぞれにimage_seikou1~10.png、image_yomenai1~10.png、image_sippai1~10.pngとリネームしたファイルを用意。"seikou", "yomenai", "sippai"フォルダを一つのフォルダに入れ、そのフォルダをNetlifyへドラッグアンドドロップでアップロードし、URLをコピー(YOUR_NETLIFY_URL)。(効果音のフォルダと同じでも可)
YOUR_ACCESS_TOKEN
YOUR_DRIVE_FOLDER_ID
YOUR_SPREADSHEET_ID
YOUR_NETLIFY_URL
YOUR_LIFF_URL
は、ご自分のものへ差し換えてください。
GAS
//★★LINE Messaging APIのチャネルアクセストークン★★
var LINE_ACCESS_TOKEN = "YOUR_ACCESS_TOKEN"; //自分のline アクセストークンを入れてください。
//★★画像を保存するフォルダーID★★
var GOOGLE_DRIVE_FOLDER_ID = "YOUR_DRIVE_FOLDER_ID"; //自分のgoogle Drive idを入れてください。
const search_spreadsheet_id = "YOUR_SPREADSHEET_ID"; //自分のスプレッドシートIDを入れてください。
const targetSheet = SpreadsheetApp.openById(search_spreadsheet_id).getSheetByName("シート1");
//ファイル名に使う現在日時をMomentライブラリーを使って取得
var date = Moment.moment(); //現在日時を取得
var formattedDate = date.format("YYYYMMDD_HHmmss");
//LINE Messaging APIからPOST送信を受けたときに起動する
// e はJSON文字列
function doPost(e){
if (typeof e === "undefined"){
//eがundefinedの場合動作を終了する
return;
}
//JSON文字列をパース(解析)し、変数jsonに格納する
var json = JSON.parse(e.postData.contents);
//受信したメッセージ情報を変数に格納する
var reply_token = json.events[0].replyToken; //reply token
var message = json.events[0].message.text;
var messageId = json.events[0].message.id; //メッセージID
var messageType = json.events[0].message.type; //メッセージタイプ
//LINEで送信されたものが画像以外の場合、LINEで返信し動作を終了する
if(messageType === "text"){
//1秒待つ関数を、A3セルが"img"になるまで、20回繰り返す。
for (let i = 0; i < 20; i++){
var startMsec = new Date();
// 指定ミリ秒間だけループさせる(CPUは常にビジー状態)
while (new Date() - startMsec < 1000);
i = i+1;
if(targetSheet.getRange(3, 1).getValue() == "img") {
break;
}
}
targetSheet.getRange(3, 1).setValue("");
var imgBBUrl = "https://i.ibb.co/" + message + ".png";
getImage(imgBBUrl, reply_token);
}else if(messageType === "image"){
targetSheet.getRange(3, 1).setValue("img");
SpreadsheetApp.flush(); //シートの再描画を行い、スプレッドシート関数の再計算を実行
}else {
var messageNotImage = "もじれんメニューを使ってください"
//変数reply_tokenとmessageNotImageを関数sendMessageに渡し、sendMessageを起動する
sendMessage(reply_token, messageNotImage);
return;
}
}
//Blob形式で画像を取得する
function getImage(imgBBUrl, reply_token){
try {
var response = UrlFetchApp.fetch(imgBBUrl);
var imgblob = response.getBlob();
var folder = DriveApp.getFolderById(GOOGLE_DRIVE_FOLDER_ID);
folder.createFile(imgblob);
for (let i = 0; i < 1; i++){
var startMsec = new Date();
while (new Date() - startMsec < 2000);
i = i+1;
}
//変数imageBlobとreply_tokenを関数saveImageに渡し、saveImageを起動する
get_ocr_Image(reply_token)
} catch(e) {
//例外エラーが起きた時にログを残す
Logger.log(e.message);
}
}
//画像をGoogle Driveのフォルダーに画像を保存(アップロード)、OCRをかけテキストを取得。
//保存された画像、作成されたドキュメントファイルは残す。
//OCRで得られたテキストをLine Botへ返信する。
function get_ocr_Image(reply_token){
try{
//ここからOCRをかけていく
let a = Drive.Children.list(GOOGLE_DRIVE_FOLDER_ID)
// 設定事項を書いていく
let resource = {
title: "OCR結果" + formattedDate // 生成されるGoogleドキュメントのファイル名
};
let option = {
"ocr": true,// OCRを行うかの設定です
"ocrLanguage": "ja",// OCRを行う言語の設定です
}
// 取得したファイル一覧の最初のもののfileIdを変数に格納します
let fileId = a.items[0].id
// 指定したfileIdのファイルをコピーします
let image = Drive.Files.copy(resource, fileId, option)
// コピー先ファイルにはOCRのデータが含まれているのでテキストを取得します
var text_O = DocumentApp.openById(image.id).getBody().getText();
var wrihgt_position = text_O.indexOf('。') +2;
var exa = text_O.substring( 2, 3 );
var wright = text_O.substring( wrihgt_position, wrihgt_position +1 );
targetSheet.getRange(4, 1).setValue(exa);
targetSheet.getRange(5, 1).setValue(wright);
// アップロードした写真、作成したOCRファイルを削除する。
Drive.Files.remove(image.id) //作成したOCRファイルを削除
Drive.Files.remove(fileId) //アップロードした写真を削除
// OCRで得られたテキストを、Line Botへ返信する。
if(exa == wright){
// 用意されたリストからランダムに単語を選択
var wordList = [
"すばらしい!", "天才か‼", "才能あり!", "上手!", "とっても上手!", "めちゃくちゃ上手!", "良いね!", "上手!天才か!", "とても上手! 天才か!", "うまぁーーーーい!", "いいんじゃない!"];
var selectedWord = wordList[Math.floor(Math.random() * wordList.length)];
replymenu1(reply_token, selectedWord);
}else {
if(wright == ""){
var re_message = "すみません、私には読めません…";
replymenu2(reply_token, re_message);
}else {
// 用意されたリストからランダムに単語を選択
var wordList = [
"おしい!", "そうだねぇ。", "もう少し!", "もうちょっと!", "良いけど…", "うーん⁉", "ううーん?", "これはなんでしょうか?", "まあ、そうなんだけど。", "おーーーい!", "おや?"];
var selectedWord = wordList[Math.floor(Math.random() * wordList.length)];
var re_message1 = selectedWord;
var re_message2 = "私はこう読めます。";
var re_message3 = "「" + wright + "」";
replymenu3(reply_token, re_message1, re_message2, re_message3);
}
}
} catch(e){
//例外エラーが起きた時にログを残す
Logger.log(e)
}
}
function replymenu1(reply_token, re_message){
var randomNumber = Math.floor(Math.random() * 10) + 1;
var menu1 = [{
'type':'flex', //ここの宣言が必須
'altText':'this is a flex message',
//↓このcontentsの部分にSimulatorのJSONをコピー
'contents':
{
"type": "bubble",
"size": "kilo",
"hero": {
"type": "image",
"url": "YOUR_NETLIFY_URL/seikou/image_seikou" + randomNumber + ".png", //YOUR_NETLIFY_URLにご自分のnetlify名を入れてください。
"margin": "none",
"size": "full",
"aspectRatio": "20:8"
},
"body": {
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "text",
"text": re_message,
"weight": "bold"
}
],
"alignItems": "center"
},
"footer": {
"type": "box",
"layout": "vertical",
"spacing": "md",
"contents": [
{
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "text",
"text": "つづける",
"size": "15px",
"weight": "bold"
}
],
"margin": "none",
"background": {
"type": "linearGradient",
"angle": "0deg",
"startColor": "#98fb98",
"endColor": "#ffffff"
},
"width": "180px",
"alignItems": "center",
"cornerRadius": "10px",
"action": {
"type": "uri",
"label": "action",
"uri": "YOUR_LIFF_URL" //先ほど作成したLIFFのURLを入れる
},
"spacing": "none",
"offsetBottom": "lg",
"height": "40px",
"justifyContent": "center"
}
],
"flex": 0,
"alignItems": "center"
}
}
}]
sendMessage2(reply_token, menu1)
};
function replymenu2(reply_token, re_message){
var randomNumber = Math.floor(Math.random() * 10) + 1;
var menu2 = [{
'type':'flex', //ここの宣言が必須
'altText':'this is a flex message',
//↓このcontentsの部分にSimulatorのJSONをコピー
'contents':
{
"type": "bubble",
"size": "kilo",
"hero": {
"type": "image",
"url": "YOUR_NETLIFY_URL/yomenai/image_yomenai" + randomNumber + ".png", //YOUR_NETLIFY_URLにご自分のnetlify名を入れてください。
"margin": "none",
"size": "full",
"aspectRatio": "20:8"
},
"body": {
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "text",
"text": re_message,
"weight": "bold"
}
],
"alignItems": "center"
},
"footer": {
"type": "box",
"layout": "vertical",
"spacing": "md",
"contents": [
{
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "text",
"text": "つづける",
"size": "15px",
"weight": "bold"
}
],
"margin": "none",
"background": {
"type": "linearGradient",
"angle": "0deg",
"startColor": "#c7dc68",
"endColor": "#ffffff"
},
"width": "180px",
"alignItems": "center",
"cornerRadius": "10px",
"action": {
"type": "uri",
"label": "action",
"uri": "YOUR_LIFF_URL" //先ほど作成したLIFFのURLを入れる
},
"spacing": "none",
"offsetBottom": "lg",
"height": "40px",
"justifyContent": "center"
}
],
"flex": 0,
"alignItems": "center"
}
}
}]
sendMessage2(reply_token, menu2)
};
function replymenu3(reply_token, re_message1, re_message2, re_message3){
var randomNumber = Math.floor(Math.random() * 10) + 1;
var menu3 = [{
'type':'flex', //ここの宣言が必須
'altText':'this is a flex message',
//↓このcontentsの部分にSimulatorのJSONをコピー
'contents':
{
"type": "bubble",
"size": "kilo",
"hero": {
"type": "image",
"url": "YOUR_NETLIFY_URL/sippai/image_sippai" + randomNumber + ".png", //YOUR_NETLIFY_URLにご自分のnetlify名を入れてください。
"margin": "none",
"size": "full",
"aspectRatio": "20:8"
},
"body": {
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "text",
"text": re_message1,
"weight": "bold"
},
{
"type": "text",
"text": re_message2,
"weight": "bold"
},
{
"type": "text",
"text": re_message3,
"weight": "bold"
}
],
"alignItems": "center"
},
"footer": {
"type": "box",
"layout": "vertical",
"spacing": "md",
"contents": [
{
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "text",
"text": "つづける",
"size": "15px",
"weight": "bold"
}
],
"margin": "none",
"background": {
"type": "linearGradient",
"angle": "0deg",
"startColor": "#ff00ff",
"endColor": "#ffffff"
},
"width": "180px",
"alignItems": "center",
"cornerRadius": "10px",
"action": {
"type": "uri",
"label": "action",
"uri": "YOUR_LIFF_URL" //先ほど作成したLIFFのURLを入れる
},
"spacing": "none",
"offsetBottom": "lg",
"height": "40px",
"justifyContent": "center"
}
],
"flex": 0,
"alignItems": "center"
}
}
}]
sendMessage2(reply_token, menu3)
};
//ユーザーにメッセージを送信する
function sendMessage(reply_token, text){
//返信先URL
var replyUrl = "https://api.line.me/v2/bot/message/reply";
var headers = {
"Content-Type": "application/json; charset=UTF-8",
"Authorization": "Bearer " + LINE_ACCESS_TOKEN
};
var postData = {
"replyToken": reply_token,
"messages": [{
"type": "text",
"text": text
}]
};
var options = {
"method" : "post",
"headers" : headers,
"payload" : JSON.stringify(postData)
};
//LINE Messaging APIにデータを送信する
UrlFetchApp.fetch(replyUrl, options);
}
function sendMessage2(reply_token, menu_message){
//返信先URL
var replyUrl = 'https://api.line.me/v2/bot/message/reply';
var headers = {
"Content-Type": "application/json; charset=UTF-8",
"Authorization": "Bearer " + LINE_ACCESS_TOKEN
};
var postData = {
"replyToken": reply_token,
"messages": menu_message
};
var options = {
"method" : "post",
"headers" : headers,
"payload" : JSON.stringify(postData)
};
//LINE Messaging APIにデータを送信する
UrlFetchApp.fetch(replyUrl, options);
}
工夫ポイント、苦労したポイント
●画像の左上の文字列は、結果照合のために入れています。
画像全体にOCRをかけ、 ”2文字目” と、 ”。の後の文字” が同じであるかを照合し、同じであれば正解、違っていれば不正解と読み取れた文字を、読み取れない(書いた文字がないと判断される)場合は読み取れないメッセージを返すようにしています。
LINEへのテキスト返信でも同様の照合は可能と考えますが、お題と答えを同じ画像に残すと後で見て分かりやすいかなと思い、今回の形式にしています。
●画像の後の文字列(テキスト)送信は、imgBBの画像URLの一部になります。
①LIFF描いた絵をimgBBへ送信、その画像URLをGASで取得simgBB⇒GoogleDiveへ送信
②LIFFで書いた絵を直接GoogleDriveへ送信
本当は、上記の①または②の方法ができればスマートなのですが、①はimgBBへ送信した画像からimgBBのURLを後から読み取る方法(GASで取得する方法)が分からない、②は方法が分からないので、送信時にLINE(その後ろで動くGAS)へ画像URL(LIFFで設定したimgBB画像URL)を送って再利用することにしました。
●画像に対しOCRをかけて返信するまでに10~20秒ほどかかる。
これはネット環境やImgBB、GoogleDriveの応答の問題なので、改善は困難と考えました。そこで、時間稼ぎのため、LIFFを閉じるまでに10秒間カウント(効果音付き)としました。