hyeyeon-sun

final

Showing 71 changed files with 5132 additions and 0 deletions
1 +node_modules/
1 +MIT License
2 +
3 +Copyright (c) 2016 Jerry Wang (https://jw84.co)
4 +
5 +Permission is hereby granted, free of charge, to any person obtaining a copy
6 +of this software and associated documentation files (the "Software"), to deal
7 +in the Software without restriction, including without limitation the rights
8 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 +copies of the Software, and to permit persons to whom the Software is
10 +furnished to do so, subject to the following conditions:
11 +
12 +The above copyright notice and this permission notice shall be included in all
13 +copies or substantial portions of the Software.
14 +
15 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 +SOFTWARE.
1 +web: node index.js
1 +import tensorflow as tf
2 +import numpy as np
3 +import sys
4 +from random import randint
5 +import datetime
6 +from sklearn.utils import shuffle
7 +import pickle
8 +import os
9 +# Removes an annoying Tensorflow warning
10 +import sys
11 +sys.stdout.reconfigure(encoding='utf-8')
12 +os.environ['TF_CPP_MIN_LOG_LEVEL']='2'
13 +
14 +
15 +
16 +def createTrainingMatrices(conversationFileName, wList, maxLen):
17 + conversationDictionary = np.load(conversationFileName, allow_pickle=True).item()
18 + numExamples = len(conversationDictionary)
19 + xTrain = np.zeros((numExamples, maxLen), dtype='int32')
20 + yTrain = np.zeros((numExamples, maxLen), dtype='int32')
21 + for index,(key,value) in enumerate(conversationDictionary.items()):
22 + # Will store integerized representation of strings here (initialized as padding)
23 + encoderMessage = np.full((maxLen), wList.index('<pad>'), dtype='int32')
24 + decoderMessage = np.full((maxLen), wList.index('<pad>'), dtype='int32')
25 + # Getting all the individual words in the strings
26 + keySplit = key.split()
27 + valueSplit = value.split()
28 + keyCount = len(keySplit)
29 + valueCount = len(valueSplit)
30 + # Throw out sequences that are too long or are empty
31 + if (keyCount > (maxLen - 1) or valueCount > (maxLen - 1) or valueCount == 0 or keyCount == 0):
32 + continue
33 + # Integerize the encoder string
34 + for keyIndex, word in enumerate(keySplit):
35 + try:
36 + encoderMessage[keyIndex] = wList.index(word)
37 + except ValueError:
38 + # TODO: This isnt really the right way to handle this scenario
39 + encoderMessage[keyIndex] = 0
40 + encoderMessage[keyIndex + 1] = wList.index('<EOS>')
41 + # Integerize the decoder stringd
42 + for valueIndex, word in enumerate(valueSplit):
43 + try:
44 + decoderMessage[valueIndex] = wList.index(word)
45 + except ValueError:
46 + decoderMessage[valueIndex] = 0
47 + decoderMessage[valueIndex + 1] = wList.index('<EOS>')
48 + xTrain[index] = encoderMessage
49 + yTrain[index] = decoderMessage
50 + # Remove rows with all zeros
51 + yTrain = yTrain[~np.all(yTrain == 0, axis=1)]
52 + xTrain = xTrain[~np.all(xTrain == 0, axis=1)]
53 + numExamples = xTrain.shape[0]
54 + return numExamples, xTrain, yTrain
55 +
56 +def getTrainingBatch(localXTrain, localYTrain, localBatchSize, maxLen):
57 + num = randint(0,numTrainingExamples - localBatchSize - 1)
58 + arr = localXTrain[num:num + localBatchSize]
59 + labels = localYTrain[num:num + localBatchSize]
60 + # Reversing the order of encoder string apparently helps as per 2014 paper
61 + reversedList = list(arr)
62 + for index,example in enumerate(reversedList):
63 + reversedList[index] = list(reversed(example))
64 +
65 + # Lagged labels are for the training input into the decoder
66 + laggedLabels = []
67 + EOStokenIndex = wordList.index('<EOS>')
68 + padTokenIndex = wordList.index('<pad>')
69 + for example in labels:
70 + eosFound = np.argwhere(example==EOStokenIndex)[0]
71 + shiftedExample = np.roll(example,1)
72 + shiftedExample[0] = EOStokenIndex
73 + # The EOS token was already at the end, so no need for pad
74 + if (eosFound != (maxLen - 1)):
75 + shiftedExample[eosFound+1] = padTokenIndex
76 + laggedLabels.append(shiftedExample)
77 +
78 + # Need to transpose these
79 + reversedList = np.asarray(reversedList).T.tolist()
80 + labels = labels.T.tolist()
81 + laggedLabels = np.asarray(laggedLabels).T.tolist()
82 + return reversedList, labels, laggedLabels
83 +
84 +def translateToSentences(inputs, wList, encoder=False):
85 + EOStokenIndex = wList.index('<EOS>')
86 + padTokenIndex = wList.index('<pad>')
87 + numStrings = len(inputs[0])
88 + numLengthOfStrings = len(inputs)
89 + listOfStrings = [''] * numStrings
90 + for mySet in inputs:
91 + for index,num in enumerate(mySet):
92 + if (num != EOStokenIndex and num != padTokenIndex):
93 + if (encoder):
94 + # Encodings are in reverse!
95 + listOfStrings[index] = wList[num] + " " + listOfStrings[index]
96 + else:
97 + listOfStrings[index] = listOfStrings[index] + " " + wList[num]
98 + listOfStrings = [string.strip() for string in listOfStrings]
99 + return listOfStrings
100 +
101 +def getTestInput(inputMessage, wList, maxLen):
102 + encoderMessage = np.full((maxLen), wList.index('<pad>'), dtype='int32')
103 + inputSplit = inputMessage.lower().split()
104 + for index,word in enumerate(inputSplit):
105 + try:
106 + encoderMessage[index] = wList.index(word)
107 + except ValueError:
108 + continue
109 + encoderMessage[index + 1] = wList.index('<EOS>')
110 + encoderMessage = encoderMessage[::-1]
111 + encoderMessageList=[]
112 + for num in encoderMessage:
113 + encoderMessageList.append([num])
114 + return encoderMessageList
115 +
116 +def idsToSentence(ids, wList):
117 + EOStokenIndex = wList.index('<EOS>')
118 + padTokenIndex = wList.index('<pad>')
119 + myStr = ""
120 + listOfResponses=[]
121 + for num in ids:
122 + if (num[0] == EOStokenIndex or num[0] == padTokenIndex):
123 + listOfResponses.append(myStr)
124 + myStr = ""
125 + else:
126 + myStr = myStr + wList[num[0]] + " "
127 + if myStr:
128 + listOfResponses.append(myStr)
129 + listOfResponses = [i for i in listOfResponses if i]
130 + return listOfResponses
131 +
132 +# Hyperparamters
133 +batchSize = 24
134 +maxEncoderLength = 15
135 +maxDecoderLength = maxEncoderLength
136 +lstmUnits = 112
137 +embeddingDim = lstmUnits
138 +numLayersLSTM = 3
139 +numIterations = 500000
140 +
141 +# Loading in all the data structures
142 +with open("wordList.txt", "rb") as fp:
143 + wordList = pickle.load(fp)
144 +
145 +vocabSize = len(wordList)
146 +
147 +# If you've run the entirety of word2vec.py then these lines will load in
148 +# the embedding matrix.
149 +if (os.path.isfile('embeddingMatrix.npy')):
150 + wordVectors = np.load('embeddingMatrix.npy')
151 + wordVecDimensions = wordVectors.shape[1]
152 +else:
153 + question = 'Since we cant find an embedding matrix, how many dimensions do you want your word vectors to be?: '
154 + wordVecDimensions = 2
155 +
156 +# Add two entries to the word vector matrix. One to represent padding tokens,
157 +# and one to represent an end of sentence token
158 +padVector = np.zeros((1, wordVecDimensions), dtype='int32')
159 +EOSVector = np.ones((1, wordVecDimensions), dtype='int32')
160 +if (os.path.isfile('embeddingMatrix.npy')):
161 + wordVectors = np.concatenate((wordVectors,padVector), axis=0)
162 + wordVectors = np.concatenate((wordVectors,EOSVector), axis=0)
163 +
164 +# Need to modify the word list as well
165 +wordList.append('<pad>')
166 +wordList.append('<EOS>')
167 +vocabSize = vocabSize + 2
168 +
169 +if (os.path.isfile('Seq2SeqXTrain.npy') and os.path.isfile('Seq2SeqYTrain.npy')):
170 + xTrain = np.load('Seq2SeqXTrain.npy')
171 + yTrain = np.load('Seq2SeqYTrain.npy')
172 + print ('Finished loading training matrices')
173 + numTrainingExamples = xTrain.shape[0]
174 +else:
175 + numTrainingExamples, xTrain, yTrain = createTrainingMatrices(r'C:\Users\dlgpd\Desktop\20-1\oss\term-project\Learn_for_yourself\final\conversationDictionary.npy', wordList, maxEncoderLength)
176 + np.save('Seq2SeqXTrain.npy', xTrain)
177 + np.save('Seq2SeqYTrain.npy', yTrain)
178 + print ('Finished creating training matrices')
179 +
180 +tf.compat.v1.reset_default_graph()
181 +
182 +# Create the placeholders
183 +encoderInputs = [tf.placeholder(tf.int32, shape=(None,)) for i in range(maxEncoderLength)]
184 +decoderLabels = [tf.placeholder(tf.int32, shape=(None,)) for i in range(maxDecoderLength)]
185 +decoderInputs = [tf.placeholder(tf.int32, shape=(None,)) for i in range(maxDecoderLength)]
186 +feedPrevious = tf.placeholder(tf.bool)
187 +
188 +encoderLSTM = tf.nn.rnn_cell.BasicLSTMCell(lstmUnits, state_is_tuple=True)
189 +
190 +#encoderLSTM = tf.nn.rnn_cell.MultiRNNCell([singleCell]*numLayersLSTM, state_is_tuple=True)
191 +# Architectural choice of of whether or not to include ^
192 +
193 +decoderOutputs, decoderFinalState = tf.contrib.legacy_seq2seq.embedding_rnn_seq2seq(encoderInputs, decoderInputs, encoderLSTM,
194 + vocabSize, vocabSize, embeddingDim, feed_previous=feedPrevious)
195 +
196 +decoderPrediction = tf.argmax(decoderOutputs, 2)
197 +
198 +lossWeights = [tf.ones_like(l, dtype=tf.float32) for l in decoderLabels]
199 +loss = tf.contrib.legacy_seq2seq.sequence_loss(decoderOutputs, decoderLabels, lossWeights, vocabSize)
200 +optimizer = tf.train.AdamOptimizer(1e-4).minimize(loss)
201 +
202 +sess = tf.Session()
203 +saver = tf.train.Saver()
204 +# If you're loading in a saved model, uncomment the following line and comment out line 202
205 +#saver.restore(sess, tf.train.latest_checkpoint('models/'))
206 +sess.run(tf.global_variables_initializer())
207 +
208 +# Uploading results to Tensorboard
209 +tf.summary.scalar('Loss', loss)
210 +merged = tf.summary.merge_all()
211 +logdir = "tensorboard/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S") + "/"
212 +writer = tf.summary.FileWriter(logdir, sess.graph)
213 +
214 +# Some test strings that we'll use as input at intervals during training
215 +encoderTestStrings = ["밥먹었어?",
216 + "이모티콘",
217 + "잘쟈",
218 + "어머나"
219 + ]
220 +
221 +zeroVector = np.zeros((1), dtype='int32')
222 +
223 +for i in range(numIterations):
224 +
225 + encoderTrain, decoderTargetTrain, decoderInputTrain = getTrainingBatch(xTrain, yTrain, batchSize, maxEncoderLength)
226 + feedDict = {encoderInputs[t]: encoderTrain[t] for t in range(maxEncoderLength)}
227 + feedDict.update({decoderLabels[t]: decoderTargetTrain[t] for t in range(maxDecoderLength)})
228 + feedDict.update({decoderInputs[t]: decoderInputTrain[t] for t in range(maxDecoderLength)})
229 + feedDict.update({feedPrevious: False})
230 +
231 + curLoss, _, pred = sess.run([loss, optimizer, decoderPrediction], feed_dict=feedDict)
232 +
233 + if (i % 50 == 0):
234 + print('Current loss:', curLoss, 'at iteration', i)
235 + summary = sess.run(merged, feed_dict=feedDict)
236 + writer.add_summary(summary, i)
237 + if (i % 25 == 0 and i != 0):
238 + num = randint(0,len(encoderTestStrings) - 1)
239 + print (encoderTestStrings[num])
240 + inputVector = getTestInput(encoderTestStrings[num], wordList, maxEncoderLength);
241 + feedDict = {encoderInputs[t]: inputVector[t] for t in range(maxEncoderLength)}
242 + feedDict.update({decoderLabels[t]: zeroVector for t in range(maxDecoderLength)})
243 + feedDict.update({decoderInputs[t]: zeroVector for t in range(maxDecoderLength)})
244 + feedDict.update({feedPrevious: True})
245 + ids = (sess.run(decoderPrediction, feed_dict=feedDict))
246 + print (idsToSentence(ids, wordList))
247 +
248 + if (i % 100 == 0 and i != 0):
249 + savePath = saver.save(sess, "models/pretrained_seq2seq.ckpt", global_step=i)
1 +import tensorflow as tf
2 +import numpy as np
3 +import re
4 +from collections import Counter
5 +import sys
6 +import math
7 +from random import randint
8 +import pickle
9 +import os
10 +import sys
11 +sys.stdout.reconfigure(encoding='utf-8')
12 +
13 +# This Word2Vec implementation is largely based on this paper
14 +# https://papers.nips.cc/paper/5021-distributed-representations-of-words-and-phrases-and-their-compositionality.pdf
15 +# It's a bit old, but Word2Vec is still SOTA and relatively simple, so I'm going with it
16 +
17 +# Check out Tensorflow's documentation which is pretty good for Word2Vec
18 +# https://www.tensorflow.org/tutorials/word2vec
19 +
20 +wordVecDimensions = 100
21 +batchSize = 128
22 +numNegativeSample = 64
23 +windowSize = 5
24 +numIterations = 100000
25 +
26 +# This function just takes in the conversation data and makes it
27 +# into one huge string, and then uses a Counter to identify words
28 +# and the number of occurences
29 +def processDataset(filename):
30 + openedFile = open(filename, 'r', encoding='UTF8')
31 + allLines = openedFile.readlines()
32 + myStr = ""
33 + for line in allLines:
34 + myStr += line
35 + finalDict = Counter(myStr.split())
36 + return myStr, finalDict
37 +
38 +def createTrainingMatrices(dictionary, corpus):
39 + allUniqueWords = list(dictionary.keys())
40 + allWords = corpus.split()
41 + numTotalWords = len(allWords)
42 + xTrain=[]
43 + yTrain=[]
44 + for i in range(numTotalWords):
45 + if i % 100000 == 0:
46 + print ('Finished %d/%d total words' % (i, numTotalWords))
47 + wordsAfter = allWords[i + 1:i + windowSize + 1]
48 + wordsBefore = allWords[max(0, i - windowSize):i]
49 + wordsAdded = wordsAfter + wordsBefore
50 + for word in wordsAdded:
51 + xTrain.append(allUniqueWords.index(allWords[i]))
52 + yTrain.append(allUniqueWords.index(word))
53 + return xTrain, yTrain
54 +
55 +def getTrainingBatch():
56 + num = randint(0,numTrainingExamples - batchSize - 1)
57 + arr = xTrain[num:num + batchSize]
58 + labels = yTrain[num:num + batchSize]
59 + return arr, labels[:,np.newaxis]
60 +
61 +continueWord2Vec = True
62 +# Loading the data structures if they are present in the directory
63 +if (os.path.isfile('Word2VecXTrain.npy') and os.path.isfile('Word2VecYTrain.npy') and os.path.isfile('wordList.txt')):
64 + xTrain = np.load('Word2VecXTrain.npy')
65 + yTrain = np.load('Word2VecYTrain.npy')
66 + print ('Finished loading training matrices')
67 + with open("wordList.txt", "rb") as fp:
68 + wordList = pickle.load(fp)
69 + print ('Finished loading word list')
70 +
71 +else:
72 + fullCorpus, datasetDictionary = processDataset(r'C:\Users\dlgpd\Desktop\20-1\oss\term-project\Learn_for_yourself\final\conversationData.txt')
73 + print ('Finished parsing and cleaning dataset')
74 + wordList = list(datasetDictionary.keys())
75 + createOwnVectors = 'y'
76 + if (createOwnVectors == 'y'):
77 + xTrain, yTrain = createTrainingMatrices(datasetDictionary, fullCorpus)
78 + print ('Finished creating training matrices')
79 + np.save(r'C:\Users\dlgpd\Desktop\20-1\oss\term-project\Learn_for_yourself\final\Word2VecXTrain.npy', xTrain)
80 + np.save(r'C:\Users\dlgpd\Desktop\20-1\oss\term-project\Learn_for_yourself\final\Word2VecYTrain.npy', yTrain)
81 + else:
82 + continueWord2Vec = False
83 + with open(r"C:\Users\dlgpd\Desktop\20-1\oss\term-project\Learn_for_yourself\final\wordList.txt", "wb") as fp:
84 + pickle.dump(wordList, fp)
1 +// call all the required packages
2 +var express = require('express')
3 +var bodyParser= require('body-parser')
4 +var multer = require('multer');
5 +let { PythonShell } = require ( 'python-shell' )
6 +
7 +//CREATE EXPRESS APP
8 +var app = express();
9 +
10 +app.use(bodyParser.urlencoded({extended: true}))
11 +app.use('/users', express.static('uploads'))
12 +
13 +var options = {
14 + mode: 'text',
15 + pythonPath: '',
16 + pythonOptions: ['-u'],
17 + scriptPath: '',
18 + // args: ['value1', 'value2', 'value3'],
19 + encoding: 'utf8'
20 + };
21 +
22 +
23 +//ROUTES WILL GO HERE
24 +app.get('/',function(req,res){
25 + res.sendFile(__dirname + '/index.html');
26 + });
27 +
28 +var storage = multer.diskStorage({
29 + destination: function (req, file, cb) {
30 + cb(null, 'uploads')
31 + },
32 + filename: function (req, file, cb) {
33 + cb(null, "dataset.txt")
34 + }
35 + })
36 +
37 +var upload = multer({ storage: storage })
38 +
39 +app.post('/uploadfile', upload.single('myFile'), (req, res, next) => {
40 +const file = req.file
41 + if (!file) {
42 + const error = new Error('Please upload a file')
43 + error.httpStatusCode = 400
44 + return next(error)
45 + }
46 + res.send(file)
47 + })
48 +
49 +var upload = multer({ storage: storage })
50 +
51 +app.get('/makebot', (req, res) => {
52 + res.sendFile(__dirname + '/index.html');
53 +
54 + PythonShell.run('createDataset.py', options, (err, results) => {
55 + if (err) throw err;
56 + console.log('results: %j', results);
57 + });
58 + res.send("create Data set")
59 +
60 + PythonShell.run('Word2Vec.py', options, (err, results) => {
61 + if (err) throw err;
62 + console.log('results: %j', results);
63 + });
64 + res.send("word to vector")
65 +
66 + PythonShell.run('Seq2Seq.py', options, (err, results) => {
67 + if (err) throw err;
68 + console.log('results: %j', results);
69 + res.send("seq 2 seq")
70 +
71 +
72 +
73 +
74 + });
75 + })
76 +
77 +
78 +app.listen(3000, () => console.log('Server started on port 3000'));
...\ No newline at end of file ...\ No newline at end of file
1 +import pandas as pd
2 +import numpy as np
3 +import os
4 +import re
5 +from datetime import datetime
6 +import sys
7 +sys.stdout.reconfigure(encoding='utf-8')
8 +
9 +currentPath = os.getcwd()
10 +
11 +
12 +def getFacebookData():
13 + print("function active")
14 + personName = "이혜연"
15 + personName = personName.rstrip('\r')
16 + responseDictionary = dict()
17 + with open(r'C:\Users\dlgpd\Desktop\20-1\oss\term-project\Learn_for_yourself\final\uploads\dataset.txt', 'r', encoding='UTF8') as fbFile:
18 + allLines = fbFile.readlines()
19 +
20 + myMessage, otherPersonsMessage, currentSpeaker = "","",""
21 +
22 + for index,lines in enumerate(allLines):
23 + rightBracket = lines.find(':') + 5
24 + justMessage = lines[rightBracket:]
25 + colon = justMessage.find(':')
26 + # Find messages that I sent
27 +
28 +
29 + if (justMessage[:colon-1] == personName):
30 + if not myMessage:
31 + # Want to find the first message that I send (if I send multiple
32 + # in a row)
33 + startMessageIndex = index - 1
34 + myMessage += justMessage[colon + 2:]
35 +
36 + elif myMessage:
37 + # Now go and see what message the other person sent by looking at
38 + # previous messages
39 + for counter in range(startMessageIndex, 0, -1):
40 + currentLine = allLines[counter]
41 + rightBracket = currentLine.find(':') + 5
42 + justMessage = currentLine[rightBracket:]
43 + colon = justMessage.find(':')
44 + if not currentSpeaker:
45 + # The first speaker not named me
46 + currentSpeaker = justMessage[:colon]
47 + elif (currentSpeaker != justMessage[:colon] and otherPersonsMessage):
48 + # A different person started speaking, so now I know that the
49 + # first person's message is done
50 + otherPersonsMessage = cleanMessage(otherPersonsMessage)
51 + myMessage = cleanMessage(myMessage)
52 + responseDictionary[otherPersonsMessage] = myMessage
53 + break
54 + otherPersonsMessage = justMessage[colon + 2:] + otherPersonsMessage
55 + myMessage, otherPersonsMessage, currentSpeaker = "","",""
56 +
57 + return responseDictionary
58 +
59 +
60 +
61 +def cleanMessage(message):
62 + # Remove new lines within message
63 + cleanedMessage = message.replace('\n',' ').lower()
64 + # Deal with some weird tokens
65 + cleanedMessage = cleanedMessage.replace("\xc2\xa0", "")
66 + # Remove punctuation
67 + cleanedMessage = re.sub('([.,!?])','', cleanedMessage)
68 + # Remove multiple spaces in message
69 + cleanedMessage = re.sub(' +',' ', cleanedMessage)
70 + return cleanedMessage
71 +
72 +combinedDictionary = {}
73 +
74 +combinedDictionary.update(getFacebookData())
75 +
76 +print ('Total len of dictionary', len(combinedDictionary))
77 +
78 +print('Saving conversation data dictionary')
79 +np.save(r'C:\Users\dlgpd\Desktop\20-1\oss\term-project\Learn_for_yourself\final\conversationDictionary.npy', combinedDictionary)
80 +
81 +conversationFile = open(r'C:\Users\dlgpd\Desktop\20-1\oss\term-project\Learn_for_yourself\final\conversationData.txt', 'w', encoding='UTF8')
82 +for key, value in combinedDictionary.items():
83 + if (not key.strip() or not value.strip()):
84 + # If there are empty strings
85 + continue
86 + conversationFile.write(key.strip() + value.strip())
1 +import numpy as np
2 +import pickle
3 +import tensorflow as tf
4 +from flask import Flask, jsonify, render_template, request
5 +import model
6 +
7 +# Load in data structures
8 +with open("data/wordList.txt", "rb") as fp:
9 + wordList = pickle.load(fp)
10 +wordList.append('<pad>')
11 +wordList.append('<EOS>')
12 +
13 +# Load in hyperparamters
14 +vocabSize = len(wordList)
15 +batchSize = 24
16 +maxEncoderLength = 15
17 +maxDecoderLength = 15
18 +lstmUnits = 112
19 +numLayersLSTM = 3
20 +
21 +# Create placeholders
22 +encoderInputs = [tf.placeholder(tf.int32, shape=(None,)) for i in range(maxEncoderLength)]
23 +decoderLabels = [tf.placeholder(tf.int32, shape=(None,)) for i in range(maxDecoderLength)]
24 +decoderInputs = [tf.placeholder(tf.int32, shape=(None,)) for i in range(maxDecoderLength)]
25 +feedPrevious = tf.placeholder(tf.bool)
26 +
27 +encoderLSTM = tf.nn.rnn_cell.BasicLSTMCell(lstmUnits, state_is_tuple=True)
28 +#encoderLSTM = tf.nn.rnn_cell.MultiRNNCell([singleCell]*numLayersLSTM, state_is_tuple=True)
29 +decoderOutputs, decoderFinalState = tf.contrib.legacy_seq2seq.embedding_rnn_seq2seq(encoderInputs, decoderInputs, encoderLSTM,
30 + vocabSize, vocabSize, lstmUnits, feed_previous=feedPrevious)
31 +
32 +decoderPrediction = tf.argmax(decoderOutputs, 2)
33 +
34 +# Start session and get graph
35 +sess = tf.Session()
36 +#y, variables = model.getModel(encoderInputs, decoderLabels, decoderInputs, feedPrevious)
37 +
38 +# Load in pretrained model
39 +saver = tf.train.Saver()
40 +saver.restore(sess, tf.train.latest_checkpoint('models'))
41 +zeroVector = np.zeros((1), dtype='int32')
42 +
43 +def pred(inputString):
44 + inputVector = model.getTestInput(inputString, wordList, maxEncoderLength)
45 + feedDict = {encoderInputs[t]: inputVector[t] for t in range(maxEncoderLength)}
46 + feedDict.update({decoderLabels[t]: zeroVector for t in range(maxDecoderLength)})
47 + feedDict.update({decoderInputs[t]: zeroVector for t in range(maxDecoderLength)})
48 + feedDict.update({feedPrevious: True})
49 + ids = (sess.run(decoderPrediction, feed_dict=feedDict))
50 + return model.idsToSentence(ids, wordList)
51 +
52 +# webapp
53 +app = Flask(__name__, template_folder='./')
...\ No newline at end of file ...\ No newline at end of file
1 +<!DOCTYPE html>
2 +<html lang="en">
3 +<head>
4 + <meta charset="UTF-8">
5 + <title>MY APP</title>
6 +</head>
7 +<body>
8 +
9 +<div>
10 + <script type ="text/javascript">
11 + function movepage() {
12 + location.href = "/makebot";
13 + }
14 + </script>
15 +
16 +<form action="/uploadfile" enctype="multipart/form-data" method="POST">
17 + <input type="file" name="myFile" />
18 + <input type="submit" value="Upload a file"/>
19 +</form>
20 + <input type="button" value="make chatbot" onclick="movepage()"/>
21 +</div>
22 +
23 +
24 +</body>
25 +</html>
...\ No newline at end of file ...\ No newline at end of file
1 +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 +
3 +# database
4 +/database.json
5 +
6 +# dependencies
7 +/node_modules
8 +/.pnp
9 +.pnp.js
10 +
11 +# testing
12 +/coverage
13 +
14 +# production
15 +/build
16 +
17 +# misc
18 +.DS_Store
19 +.env.local
20 +.env.development.local
21 +.env.test.local
22 +.env.production.local
23 +
24 +npm-debug.log*
25 +yarn-debug.log*
26 +yarn-error.log*
1 +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 +
3 +# dependencies
4 +/node_modules
5 +/.pnp
6 +.pnp.js
7 +
8 +# testing
9 +/coverage
10 +
11 +# production
12 +/build
13 +
14 +# misc
15 +.DS_Store
16 +.env.local
17 +.env.development.local
18 +.env.test.local
19 +.env.production.local
20 +
21 +npm-debug.log*
22 +yarn-debug.log*
23 +yarn-error.log*
1 +This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
2 +
3 +## Available Scripts
4 +
5 +In the project directory, you can run:
6 +
7 +### `npm start`
8 +
9 +Runs the app in the development mode.<br />
10 +Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
11 +
12 +The page will reload if you make edits.<br />
13 +You will also see any lint errors in the console.
14 +
15 +### `npm test`
16 +
17 +Launches the test runner in the interactive watch mode.<br />
18 +See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
19 +
20 +### `npm run build`
21 +
22 +Builds the app for production to the `build` folder.<br />
23 +It correctly bundles React in production mode and optimizes the build for the best performance.
24 +
25 +The build is minified and the filenames include the hashes.<br />
26 +Your app is ready to be deployed!
27 +
28 +See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
29 +
30 +### `npm run eject`
31 +
32 +**Note: this is a one-way operation. Once you `eject`, you can’t go back!**
33 +
34 +If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
35 +
36 +Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
37 +
38 +You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
39 +
40 +## Learn More
41 +
42 +You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
43 +
44 +To learn React, check out the [React documentation](https://reactjs.org/).
45 +
46 +### Code Splitting
47 +
48 +This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
49 +
50 +### Analyzing the Bundle Size
51 +
52 +This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
53 +
54 +### Making a Progressive Web App
55 +
56 +This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
57 +
58 +### Advanced Configuration
59 +
60 +This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
61 +
62 +### Deployment
63 +
64 +This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
65 +
66 +### `npm run build` fails to minify
67 +
68 +This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify
This diff could not be displayed because it is too large.
1 +{
2 + "name": "management",
3 + "version": "0.1.0",
4 + "private": true,
5 + "dependencies": {
6 + "@material-ui/core": "^4.10.2",
7 + "@testing-library/jest-dom": "^4.2.4",
8 + "@testing-library/react": "^9.5.0",
9 + "@testing-library/user-event": "^7.2.1",
10 + "react": "^16.13.1",
11 + "react-dom": "^16.13.1",
12 + "react-scripts": "3.4.1"
13 + },
14 + "scripts": {
15 + "start": "react-scripts start",
16 + "build": "react-scripts build",
17 + "test": "react-scripts test",
18 + "eject": "react-scripts eject"
19 + },
20 + "eslintConfig": {
21 + "extends": "react-app"
22 + },
23 + "browserslist": {
24 + "production": [
25 + ">0.2%",
26 + "not dead",
27 + "not op_mini all"
28 + ],
29 + "development": [
30 + "last 1 chrome version",
31 + "last 1 firefox version",
32 + "last 1 safari version"
33 + ]
34 + },
35 + "proxy": "http://localhost:5000/"
36 +}
No preview for this file type
1 +<!DOCTYPE html>
2 +<html lang="en">
3 + <head>
4 + <meta charset="utf-8" />
5 + <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
6 + <meta name="viewport" content="width=device-width, initial-scale=1" />
7 + <meta name="theme-color" content="#000000" />
8 + <meta
9 + name="description"
10 + content="Web site created using create-react-app"
11 + />
12 + <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
13 + <!--
14 + manifest.json provides metadata used when your web app is installed on a
15 + user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
16 + -->
17 + <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
18 + <!--
19 + Notice the use of %PUBLIC_URL% in the tags above.
20 + It will be replaced with the URL of the `public` folder during the build.
21 + Only files inside the `public` folder can be referenced from the HTML.
22 +
23 + Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
24 + work correctly both with client-side routing and a non-root public URL.
25 + Learn how to configure a non-root public URL by running `npm run build`.
26 + -->
27 + <title>React App</title>
28 + </head>
29 + <body>
30 + <noscript>You need to enable JavaScript to run this app.</noscript>
31 + <div id="root"></div>
32 + <!--
33 + This HTML file is a template.
34 + If you open it directly in the browser, you will see an empty page.
35 +
36 + You can add webfonts, meta tags, or analytics to this file.
37 + The build step will place the bundled scripts into the <body> tag.
38 +
39 + To begin the development, run `npm start` or `yarn start`.
40 + To create a production bundle, use `npm run build` or `yarn build`.
41 + -->
42 + </body>
43 +</html>
1 +{
2 + "short_name": "React App",
3 + "name": "Create React App Sample",
4 + "icons": [
5 + {
6 + "src": "favicon.ico",
7 + "sizes": "64x64 32x32 24x24 16x16",
8 + "type": "image/x-icon"
9 + },
10 + {
11 + "src": "logo192.png",
12 + "type": "image/png",
13 + "sizes": "192x192"
14 + },
15 + {
16 + "src": "logo512.png",
17 + "type": "image/png",
18 + "sizes": "512x512"
19 + }
20 + ],
21 + "start_url": ".",
22 + "display": "standalone",
23 + "theme_color": "#000000",
24 + "background_color": "#ffffff"
25 +}
1 +# https://www.robotstxt.org/robotstxt.html
2 +User-agent: *
3 +Disallow:
1 +.App {
2 + text-align: center;
3 +}
4 +
5 +.App-logo {
6 + height: 40vmin;
7 + pointer-events: none;
8 +}
9 +
10 +@media (prefers-reduced-motion: no-preference) {
11 + .App-logo {
12 + animation: App-logo-spin infinite 20s linear;
13 + }
14 +}
15 +
16 +.App-header {
17 + background-color: #282c34;
18 + min-height: 100vh;
19 + display: flex;
20 + flex-direction: column;
21 + align-items: center;
22 + justify-content: center;
23 + font-size: calc(10px + 2vmin);
24 + color: white;
25 +}
26 +
27 +.App-link {
28 + color: #61dafb;
29 +}
30 +
31 +@keyframes App-logo-spin {
32 + from {
33 + transform: rotate(0deg);
34 + }
35 + to {
36 + transform: rotate(360deg);
37 + }
38 +}
1 +import React, { Component } from 'react';
2 +import './App.css';
3 +import Customer from './components/Customer';
4 +import Paper from '@material-ui/core/Paper';
5 +import Table from '@material-ui/core/Table';
6 +import TableHead from '@material-ui/core/TableHead';
7 +import TableBody from '@material-ui/core/TableBody';
8 +import TableRow from '@material-ui/core/TableRow';
9 +import TableCell from '@material-ui/core/TableCell';
10 +import { withStyles } from '@material-ui/core/styles';
11 +import CircularProgress from '@material-ui/core/CircularProgress';
12 +
13 +const styles = theme => ({
14 + root: {
15 + width: '100%',
16 + marginTop: theme.spacing.unit*3,
17 + overflowX: "auto"
18 + },
19 + table: {
20 + minWidth: 1080
21 + },
22 + progress: {
23 + margine: theme.spacing.unit*2
24 + }
25 +})
26 +
27 +class App extends Component {
28 + state = {
29 + customers: "",
30 + completed: 0
31 + }
32 +
33 + //모든 컴포넌트 준비 완료일 때 실행 -- react가 라이브러리이기 때문 !
34 + componentDidMount() {
35 + this.timer = setInterval(this.progress,20);
36 + this.callApi()
37 + .then(res => this.setState({customers: res}))
38 + .catch(err => console.log(err));
39 + }
40 +
41 + callApi = async() => {
42 + //local의/api/customers에 접속해 response로 받아오고 이를 body변수에 담아주겠다
43 + const response = await fetch('/api/customers');
44 + const body = await response.json();
45 + return body;
46 + }
47 +
48 + progress = () => {
49 + const { completed } = this.state;
50 + this.setState({completed : completed >=100 ? 0: completed +1});
51 + }
52 +
53 + render() {
54 + const { classes } = this.props;
55 + return (
56 + <Paper className = {classes.root}>
57 + <Table className = {classes.table}>
58 + <TableHead>
59 + <TableRow>
60 + <TableCell>번호</TableCell>
61 + <TableCell>이미지</TableCell>
62 + <TableCell>이름</TableCell>
63 + <TableCell>생년월일</TableCell>
64 + <TableCell>성별</TableCell>
65 + <TableCell>직업</TableCell>
66 + </TableRow>
67 + </TableHead>
68 +
69 + <TableBody>
70 + {this.state.customers ? this.state.customers.map (c=> {
71 + return (<Customer key={c.id} id={c.id} image={c.image} name={c.name} birthday={c.birthday} gender={c.gender} job={c.job} />)
72 + }) :
73 + <TableRow>
74 + <TableCell colSpan="6" align="center">
75 + <CircularProgress className={classes.progress} varient="determinate" value={this.state.completed}/>
76 + </TableCell>
77 + </TableRow>
78 + }
79 + </TableBody>
80 + </Table>
81 + </Paper>
82 + );
83 + }
84 +}
85 +
86 +export default withStyles(styles)(App);
1 +import React from 'react';
2 +import { render } from '@testing-library/react';
3 +import App from './App';
4 +
5 +test('renders learn react link', () => {
6 + const { getByText } = render(<App />);
7 + const linkElement = getByText(/learn react/i);
8 + expect(linkElement).toBeInTheDocument();
9 +});
1 +import React from 'react';
2 +import TableRow from '@material-ui/core/TableRow';
3 +import TableCell from '@material-ui/core/TableCell';
4 +
5 +class Customer extends React.Component {
6 + render(){
7 + return(
8 + <TableRow>
9 + <TableCell>{this.props.id}</TableCell>
10 + <TableCell><img src={this.props.image} alt="profile"/></TableCell>
11 + <TableCell>{this.props.name}</TableCell>
12 + <TableCell>{this.props.birthday}</TableCell>
13 + <TableCell>{this.props.gender}</TableCell>
14 + <TableCell>{this.props.job}</TableCell>
15 + </TableRow>
16 + );
17 + }
18 +}
19 +
20 +
21 +
22 +export default Customer;
...\ No newline at end of file ...\ No newline at end of file
1 +body {
2 + margin: 0;
3 + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 + sans-serif;
6 + -webkit-font-smoothing: antialiased;
7 + -moz-osx-font-smoothing: grayscale;
8 +}
9 +
10 +code {
11 + font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 + monospace;
13 +}
1 +import React from 'react';
2 +import ReactDOM from 'react-dom';
3 +import './index.css';
4 +import App from './App';
5 +import * as serviceWorker from './serviceWorker';
6 +
7 +ReactDOM.render(
8 + <React.StrictMode>
9 + <App />
10 + </React.StrictMode>,
11 + document.getElementById('root')
12 +);
13 +
14 +// If you want your app to work offline and load faster, you can change
15 +// unregister() to register() below. Note this comes with some pitfalls.
16 +// Learn more about service workers: https://bit.ly/CRA-PWA
17 +serviceWorker.unregister();
1 +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3">
2 + <g fill="#61DAFB">
3 + <path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/>
4 + <circle cx="420.9" cy="296.5" r="45.7"/>
5 + <path d="M520.5 78.1z"/>
6 + </g>
7 +</svg>
1 +// This optional code is used to register a service worker.
2 +// register() is not called by default.
3 +
4 +// This lets the app load faster on subsequent visits in production, and gives
5 +// it offline capabilities. However, it also means that developers (and users)
6 +// will only see deployed updates on subsequent visits to a page, after all the
7 +// existing tabs open on the page have been closed, since previously cached
8 +// resources are updated in the background.
9 +
10 +// To learn more about the benefits of this model and instructions on how to
11 +// opt-in, read https://bit.ly/CRA-PWA
12 +
13 +const isLocalhost = Boolean(
14 + window.location.hostname === 'localhost' ||
15 + // [::1] is the IPv6 localhost address.
16 + window.location.hostname === '[::1]' ||
17 + // 127.0.0.0/8 are considered localhost for IPv4.
18 + window.location.hostname.match(
19 + /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
20 + )
21 +);
22 +
23 +export function register(config) {
24 + if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
25 + // The URL constructor is available in all browsers that support SW.
26 + const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
27 + if (publicUrl.origin !== window.location.origin) {
28 + // Our service worker won't work if PUBLIC_URL is on a different origin
29 + // from what our page is served on. This might happen if a CDN is used to
30 + // serve assets; see https://github.com/facebook/create-react-app/issues/2374
31 + return;
32 + }
33 +
34 + window.addEventListener('load', () => {
35 + const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
36 +
37 + if (isLocalhost) {
38 + // This is running on localhost. Let's check if a service worker still exists or not.
39 + checkValidServiceWorker(swUrl, config);
40 +
41 + // Add some additional logging to localhost, pointing developers to the
42 + // service worker/PWA documentation.
43 + navigator.serviceWorker.ready.then(() => {
44 + console.log(
45 + 'This web app is being served cache-first by a service ' +
46 + 'worker. To learn more, visit https://bit.ly/CRA-PWA'
47 + );
48 + });
49 + } else {
50 + // Is not localhost. Just register service worker
51 + registerValidSW(swUrl, config);
52 + }
53 + });
54 + }
55 +}
56 +
57 +function registerValidSW(swUrl, config) {
58 + navigator.serviceWorker
59 + .register(swUrl)
60 + .then(registration => {
61 + registration.onupdatefound = () => {
62 + const installingWorker = registration.installing;
63 + if (installingWorker == null) {
64 + return;
65 + }
66 + installingWorker.onstatechange = () => {
67 + if (installingWorker.state === 'installed') {
68 + if (navigator.serviceWorker.controller) {
69 + // At this point, the updated precached content has been fetched,
70 + // but the previous service worker will still serve the older
71 + // content until all client tabs are closed.
72 + console.log(
73 + 'New content is available and will be used when all ' +
74 + 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
75 + );
76 +
77 + // Execute callback
78 + if (config && config.onUpdate) {
79 + config.onUpdate(registration);
80 + }
81 + } else {
82 + // At this point, everything has been precached.
83 + // It's the perfect time to display a
84 + // "Content is cached for offline use." message.
85 + console.log('Content is cached for offline use.');
86 +
87 + // Execute callback
88 + if (config && config.onSuccess) {
89 + config.onSuccess(registration);
90 + }
91 + }
92 + }
93 + };
94 + };
95 + })
96 + .catch(error => {
97 + console.error('Error during service worker registration:', error);
98 + });
99 +}
100 +
101 +function checkValidServiceWorker(swUrl, config) {
102 + // Check if the service worker can be found. If it can't reload the page.
103 + fetch(swUrl, {
104 + headers: { 'Service-Worker': 'script' },
105 + })
106 + .then(response => {
107 + // Ensure service worker exists, and that we really are getting a JS file.
108 + const contentType = response.headers.get('content-type');
109 + if (
110 + response.status === 404 ||
111 + (contentType != null && contentType.indexOf('javascript') === -1)
112 + ) {
113 + // No service worker found. Probably a different app. Reload the page.
114 + navigator.serviceWorker.ready.then(registration => {
115 + registration.unregister().then(() => {
116 + window.location.reload();
117 + });
118 + });
119 + } else {
120 + // Service worker found. Proceed as normal.
121 + registerValidSW(swUrl, config);
122 + }
123 + })
124 + .catch(() => {
125 + console.log(
126 + 'No internet connection found. App is running in offline mode.'
127 + );
128 + });
129 +}
130 +
131 +export function unregister() {
132 + if ('serviceWorker' in navigator) {
133 + navigator.serviceWorker.ready
134 + .then(registration => {
135 + registration.unregister();
136 + })
137 + .catch(error => {
138 + console.error(error.message);
139 + });
140 + }
141 +}
1 +// jest-dom adds custom jest matchers for asserting on DOM nodes.
2 +// allows you to do things like:
3 +// expect(element).toHaveTextContent(/react/i)
4 +// learn more: https://github.com/testing-library/jest-dom
5 +import '@testing-library/jest-dom/extend-expect';
1 +{
2 + "name": "management",
3 + "version": "1.0.0",
4 + "lockfileVersion": 1,
5 + "requires": true,
6 + "dependencies": {
7 + "accepts": {
8 + "version": "1.3.7",
9 + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
10 + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
11 + "requires": {
12 + "mime-types": "~2.1.24",
13 + "negotiator": "0.6.2"
14 + }
15 + },
16 + "array-flatten": {
17 + "version": "1.1.1",
18 + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
19 + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
20 + },
21 + "bignumber.js": {
22 + "version": "9.0.0",
23 + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz",
24 + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A=="
25 + },
26 + "body-parser": {
27 + "version": "1.19.0",
28 + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
29 + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
30 + "requires": {
31 + "bytes": "3.1.0",
32 + "content-type": "~1.0.4",
33 + "debug": "2.6.9",
34 + "depd": "~1.1.2",
35 + "http-errors": "1.7.2",
36 + "iconv-lite": "0.4.24",
37 + "on-finished": "~2.3.0",
38 + "qs": "6.7.0",
39 + "raw-body": "2.4.0",
40 + "type-is": "~1.6.17"
41 + }
42 + },
43 + "bytes": {
44 + "version": "3.1.0",
45 + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
46 + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
47 + },
48 + "content-disposition": {
49 + "version": "0.5.3",
50 + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
51 + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
52 + "requires": {
53 + "safe-buffer": "5.1.2"
54 + }
55 + },
56 + "content-type": {
57 + "version": "1.0.4",
58 + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
59 + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
60 + },
61 + "cookie": {
62 + "version": "0.4.0",
63 + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
64 + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
65 + },
66 + "cookie-signature": {
67 + "version": "1.0.6",
68 + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
69 + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
70 + },
71 + "core-util-is": {
72 + "version": "1.0.2",
73 + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
74 + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
75 + },
76 + "debug": {
77 + "version": "2.6.9",
78 + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
79 + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
80 + "requires": {
81 + "ms": "2.0.0"
82 + }
83 + },
84 + "depd": {
85 + "version": "1.1.2",
86 + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
87 + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
88 + },
89 + "destroy": {
90 + "version": "1.0.4",
91 + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
92 + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
93 + },
94 + "ee-first": {
95 + "version": "1.1.1",
96 + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
97 + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
98 + },
99 + "encodeurl": {
100 + "version": "1.0.2",
101 + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
102 + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
103 + },
104 + "escape-html": {
105 + "version": "1.0.3",
106 + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
107 + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
108 + },
109 + "etag": {
110 + "version": "1.8.1",
111 + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
112 + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
113 + },
114 + "express": {
115 + "version": "4.17.1",
116 + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
117 + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
118 + "requires": {
119 + "accepts": "~1.3.7",
120 + "array-flatten": "1.1.1",
121 + "body-parser": "1.19.0",
122 + "content-disposition": "0.5.3",
123 + "content-type": "~1.0.4",
124 + "cookie": "0.4.0",
125 + "cookie-signature": "1.0.6",
126 + "debug": "2.6.9",
127 + "depd": "~1.1.2",
128 + "encodeurl": "~1.0.2",
129 + "escape-html": "~1.0.3",
130 + "etag": "~1.8.1",
131 + "finalhandler": "~1.1.2",
132 + "fresh": "0.5.2",
133 + "merge-descriptors": "1.0.1",
134 + "methods": "~1.1.2",
135 + "on-finished": "~2.3.0",
136 + "parseurl": "~1.3.3",
137 + "path-to-regexp": "0.1.7",
138 + "proxy-addr": "~2.0.5",
139 + "qs": "6.7.0",
140 + "range-parser": "~1.2.1",
141 + "safe-buffer": "5.1.2",
142 + "send": "0.17.1",
143 + "serve-static": "1.14.1",
144 + "setprototypeof": "1.1.1",
145 + "statuses": "~1.5.0",
146 + "type-is": "~1.6.18",
147 + "utils-merge": "1.0.1",
148 + "vary": "~1.1.2"
149 + }
150 + },
151 + "finalhandler": {
152 + "version": "1.1.2",
153 + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
154 + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
155 + "requires": {
156 + "debug": "2.6.9",
157 + "encodeurl": "~1.0.2",
158 + "escape-html": "~1.0.3",
159 + "on-finished": "~2.3.0",
160 + "parseurl": "~1.3.3",
161 + "statuses": "~1.5.0",
162 + "unpipe": "~1.0.0"
163 + }
164 + },
165 + "forwarded": {
166 + "version": "0.1.2",
167 + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
168 + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
169 + },
170 + "fresh": {
171 + "version": "0.5.2",
172 + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
173 + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
174 + },
175 + "http-errors": {
176 + "version": "1.7.2",
177 + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
178 + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
179 + "requires": {
180 + "depd": "~1.1.2",
181 + "inherits": "2.0.3",
182 + "setprototypeof": "1.1.1",
183 + "statuses": ">= 1.5.0 < 2",
184 + "toidentifier": "1.0.0"
185 + }
186 + },
187 + "iconv-lite": {
188 + "version": "0.4.24",
189 + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
190 + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
191 + "requires": {
192 + "safer-buffer": ">= 2.1.2 < 3"
193 + }
194 + },
195 + "inherits": {
196 + "version": "2.0.3",
197 + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
198 + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
199 + },
200 + "ipaddr.js": {
201 + "version": "1.9.0",
202 + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz",
203 + "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA=="
204 + },
205 + "media-typer": {
206 + "version": "0.3.0",
207 + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
208 + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
209 + },
210 + "merge-descriptors": {
211 + "version": "1.0.1",
212 + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
213 + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
214 + },
215 + "methods": {
216 + "version": "1.1.2",
217 + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
218 + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
219 + },
220 + "mime": {
221 + "version": "1.6.0",
222 + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
223 + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
224 + },
225 + "mime-db": {
226 + "version": "1.42.0",
227 + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz",
228 + "integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ=="
229 + },
230 + "mime-types": {
231 + "version": "2.1.25",
232 + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.25.tgz",
233 + "integrity": "sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==",
234 + "requires": {
235 + "mime-db": "1.42.0"
236 + }
237 + },
238 + "ms": {
239 + "version": "2.0.0",
240 + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
241 + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
242 + },
243 + "mysql": {
244 + "version": "2.18.1",
245 + "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz",
246 + "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==",
247 + "requires": {
248 + "bignumber.js": "9.0.0",
249 + "readable-stream": "2.3.7",
250 + "safe-buffer": "5.1.2",
251 + "sqlstring": "2.3.1"
252 + },
253 + "dependencies": {
254 + "isarray": {
255 + "version": "1.0.0",
256 + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
257 + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
258 + },
259 + "readable-stream": {
260 + "version": "2.3.7",
261 + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
262 + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
263 + "requires": {
264 + "core-util-is": "~1.0.0",
265 + "inherits": "~2.0.3",
266 + "isarray": "~1.0.0",
267 + "process-nextick-args": "~2.0.0",
268 + "safe-buffer": "~5.1.1",
269 + "string_decoder": "~1.1.1",
270 + "util-deprecate": "~1.0.1"
271 + }
272 + },
273 + "string_decoder": {
274 + "version": "1.1.1",
275 + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
276 + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
277 + "requires": {
278 + "safe-buffer": "~5.1.0"
279 + }
280 + }
281 + }
282 + },
283 + "negotiator": {
284 + "version": "0.6.2",
285 + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
286 + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
287 + },
288 + "on-finished": {
289 + "version": "2.3.0",
290 + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
291 + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
292 + "requires": {
293 + "ee-first": "1.1.1"
294 + }
295 + },
296 + "parseurl": {
297 + "version": "1.3.3",
298 + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
299 + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
300 + },
301 + "path-to-regexp": {
302 + "version": "0.1.7",
303 + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
304 + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
305 + },
306 + "process-nextick-args": {
307 + "version": "2.0.1",
308 + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
309 + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
310 + },
311 + "proxy-addr": {
312 + "version": "2.0.5",
313 + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz",
314 + "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==",
315 + "requires": {
316 + "forwarded": "~0.1.2",
317 + "ipaddr.js": "1.9.0"
318 + }
319 + },
320 + "qs": {
321 + "version": "6.7.0",
322 + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
323 + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
324 + },
325 + "range-parser": {
326 + "version": "1.2.1",
327 + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
328 + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
329 + },
330 + "raw-body": {
331 + "version": "2.4.0",
332 + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
333 + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
334 + "requires": {
335 + "bytes": "3.1.0",
336 + "http-errors": "1.7.2",
337 + "iconv-lite": "0.4.24",
338 + "unpipe": "1.0.0"
339 + }
340 + },
341 + "safe-buffer": {
342 + "version": "5.1.2",
343 + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
344 + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
345 + },
346 + "safer-buffer": {
347 + "version": "2.1.2",
348 + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
349 + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
350 + },
351 + "send": {
352 + "version": "0.17.1",
353 + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
354 + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
355 + "requires": {
356 + "debug": "2.6.9",
357 + "depd": "~1.1.2",
358 + "destroy": "~1.0.4",
359 + "encodeurl": "~1.0.2",
360 + "escape-html": "~1.0.3",
361 + "etag": "~1.8.1",
362 + "fresh": "0.5.2",
363 + "http-errors": "~1.7.2",
364 + "mime": "1.6.0",
365 + "ms": "2.1.1",
366 + "on-finished": "~2.3.0",
367 + "range-parser": "~1.2.1",
368 + "statuses": "~1.5.0"
369 + },
370 + "dependencies": {
371 + "ms": {
372 + "version": "2.1.1",
373 + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
374 + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
375 + }
376 + }
377 + },
378 + "serve-static": {
379 + "version": "1.14.1",
380 + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
381 + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
382 + "requires": {
383 + "encodeurl": "~1.0.2",
384 + "escape-html": "~1.0.3",
385 + "parseurl": "~1.3.3",
386 + "send": "0.17.1"
387 + }
388 + },
389 + "setprototypeof": {
390 + "version": "1.1.1",
391 + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
392 + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
393 + },
394 + "sqlstring": {
395 + "version": "2.3.1",
396 + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz",
397 + "integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A="
398 + },
399 + "statuses": {
400 + "version": "1.5.0",
401 + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
402 + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
403 + },
404 + "toidentifier": {
405 + "version": "1.0.0",
406 + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
407 + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
408 + },
409 + "type-is": {
410 + "version": "1.6.18",
411 + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
412 + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
413 + "requires": {
414 + "media-typer": "0.3.0",
415 + "mime-types": "~2.1.24"
416 + }
417 + },
418 + "unpipe": {
419 + "version": "1.0.0",
420 + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
421 + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
422 + },
423 + "util-deprecate": {
424 + "version": "1.0.2",
425 + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
426 + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
427 + },
428 + "utils-merge": {
429 + "version": "1.0.1",
430 + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
431 + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
432 + },
433 + "vary": {
434 + "version": "1.1.2",
435 + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
436 + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
437 + }
438 + }
439 +}
1 +{
2 + "name" : "management",
3 + "version": "1.0.0",
4 + "scripts":{
5 + "client": "cd client && yarn start",
6 + "server": "node server.js",
7 + "dev": "concurrently --kill-others-on-fail \"yarn server\" \"yarn client\""
8 + },
9 + "dependencies": {
10 + "body-parser": "^1.18.3",
11 + "express": "^4.16.4"
12 + },
13 + "devDependencies": {
14 + "concurrently":"^"
15 + }
16 +}
1 +const fs = require('fs');
2 +const express = require('express');
3 +const bodyParser = require('body-parser');
4 +const app = express();
5 +const port = process.env.PORT || 5000;
6 +
7 +app.use(bodyParser.json());
8 +app.use(bodyParser.urlencoded({ exrended : true }));
9 +
10 +const data = fs.readFileSync('./database.json');
11 +const conf = JSON.parse(data);
12 +const mysql = require('mysql');
13 +
14 +const connection = mysql.createConnection({
15 + host: conf.host,
16 + user: conf.user,
17 + password: conf.password,
18 + port: conf.port,
19 + database: conf.databse
20 +});
21 +connection.connect();
22 +
23 +
24 +app.get('/api/customers', (req, res) => {
25 + connection.query(
26 + "SELECT * FROM CUSTOMER",
27 + (err,rows,fields) => {
28 + res.send(rows);
29 + }
30 + )
31 +})
32 +
33 +app.listen(port, () => console.log(`Listening on port ${port}`));
...\ No newline at end of file ...\ No newline at end of file
1 +model_checkpoint_path: "pretrained_seq2seq.ckpt-108300"
2 +all_model_checkpoint_paths: "pretrained_seq2seq.ckpt-107900"
3 +all_model_checkpoint_paths: "pretrained_seq2seq.ckpt-108000"
4 +all_model_checkpoint_paths: "pretrained_seq2seq.ckpt-108100"
5 +all_model_checkpoint_paths: "pretrained_seq2seq.ckpt-108200"
6 +all_model_checkpoint_paths: "pretrained_seq2seq.ckpt-108300"
1 +/* eslint-disable */
2 +module.exports = {
3 + "extends": "standard",
4 + "rules": {
5 + "semi": [2, "always"],
6 + "indent": [2, 4],
7 + "no-return-await": 0,
8 + "space-before-function-paren": [2, {
9 + "named": "never",
10 + "anonymous": "never",
11 + "asyncArrow": "always"
12 + }],
13 + "template-curly-spacing": [2, "always"]
14 + }
15 +};
...\ No newline at end of file ...\ No newline at end of file
1 +node_modules
2 +lib
3 +.env
1 +# my-own-bot
2 +
3 +like me
4 +
5 +This bot has been created using [Bot Framework](https://dev.botframework.com), it shows how to create a simple bot that accepts input from the user and echoes it back.
6 +
7 +## Prerequisites
8 +
9 +- [Node.js](https://nodejs.org) version 10.14.1 or higher
10 +
11 + ```bash
12 + # determine node version
13 + node --version
14 + ```
15 +
16 +## To run the bot
17 +
18 +- Install modules
19 +
20 + ```bash
21 + npm install
22 + ```
23 +
24 +- Start the bot
25 +
26 + ```bash
27 + npm start
28 + ```
29 +
30 +## Testing the bot using Bot Framework Emulator
31 +
32 +[Bot Framework Emulator](https://github.com/microsoft/botframework-emulator) is a desktop application that allows bot developers to test and debug their bots on localhost or running remotely through a tunnel.
33 +
34 +- Install the Bot Framework Emulator version 4.9.0 or greater from [here](https://github.com/Microsoft/BotFramework-Emulator/releases)
35 +
36 +### Connect to the bot using Bot Framework Emulator
37 +
38 +- Launch Bot Framework Emulator
39 +- File -> Open Bot
40 +- Enter a Bot URL of `http://localhost:3978/api/messages`
41 +
42 +## Deploy the bot to Azure
43 +
44 +To learn more about deploying a bot to Azure, see [Deploy your bot to Azure](https://aka.ms/azuredeployment) for a complete list of deployment instructions.
45 +
46 +
47 +## Further reading
48 +
49 +- [Bot Framework Documentation](https://docs.botframework.com)
50 +- [Bot Basics](https://docs.microsoft.com/azure/bot-service/bot-builder-basics?view=azure-bot-service-4.0)
51 +- [Dialogs](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-concept-dialog?view=azure-bot-service-4.0)
52 +- [Gathering Input Using Prompts](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-prompts?view=azure-bot-service-4.0)
53 +- [Activity processing](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-concept-activity-processing?view=azure-bot-service-4.0)
54 +- [Azure Bot Service Introduction](https://docs.microsoft.com/azure/bot-service/bot-service-overview-introduction?view=azure-bot-service-4.0)
55 +- [Azure Bot Service Documentation](https://docs.microsoft.com/azure/bot-service/?view=azure-bot-service-4.0)
56 +- [Azure CLI](https://docs.microsoft.com/cli/azure/?view=azure-cli-latest)
57 +- [Azure Portal](https://portal.azure.com)
58 +- [Language Understanding using LUIS](https://docs.microsoft.com/en-us/azure/cognitive-services/luis/)
59 +- [Channels and Bot Connector Service](https://docs.microsoft.com/en-us/azure/bot-service/bot-concepts?view=azure-bot-service-4.0)
60 +- [Restify](https://www.npmjs.com/package/restify)
61 +- [dotenv](https://www.npmjs.com/package/dotenv)
1 +// Copyright (c) Microsoft Corporation. All rights reserved.
2 +// Licensed under the MIT License.
3 +
4 +const { ActivityHandler, MessageFactory } = require('botbuilder');
5 +
6 +class EchoBot extends ActivityHandler {
7 + constructor() {
8 + super();
9 + // See https://aka.ms/about-bot-activity-message to learn more about the message and other activity types.
10 + this.onMessage(async (context, next) => {
11 + const replyText = `Echo: ${ context.activity.text }`;
12 + await context.sendActivity(MessageFactory.text(replyText, replyText));
13 + // By calling next() you ensure that the next BotHandler is run.
14 + await next();
15 + });
16 +
17 + this.onMembersAdded(async (context, next) => {
18 + const membersAdded = context.activity.membersAdded;
19 + const welcomeText = 'Hello and welcome!';
20 + for (let cnt = 0; cnt < membersAdded.length; ++cnt) {
21 + if (membersAdded[cnt].id !== context.activity.recipient.id) {
22 + await context.sendActivity(MessageFactory.text(welcomeText, welcomeText));
23 + }
24 + }
25 + // By calling next() you ensure that the next BotHandler is run.
26 + await next();
27 + });
28 + }
29 +}
30 +
31 +module.exports.EchoBot = EchoBot;
1 +{
2 + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
3 + "contentVersion": "1.0.0.0",
4 + "parameters": {
5 + "groupLocation": {
6 + "value": ""
7 + },
8 + "groupName": {
9 + "value": ""
10 + },
11 + "appId": {
12 + "value": ""
13 + },
14 + "appSecret": {
15 + "value": ""
16 + },
17 + "botId": {
18 + "value": ""
19 + },
20 + "botSku": {
21 + "value": ""
22 + },
23 + "newAppServicePlanName": {
24 + "value": ""
25 + },
26 + "newAppServicePlanSku": {
27 + "value": {
28 + "name": "S1",
29 + "tier": "Standard",
30 + "size": "S1",
31 + "family": "S",
32 + "capacity": 1
33 + }
34 + },
35 + "newAppServicePlanLocation": {
36 + "value": ""
37 + },
38 + "newWebAppName": {
39 + "value": ""
40 + }
41 + }
42 +}
...\ No newline at end of file ...\ No newline at end of file
1 +{
2 + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
3 + "contentVersion": "1.0.0.0",
4 + "parameters": {
5 + "appId": {
6 + "value": ""
7 + },
8 + "appSecret": {
9 + "value": ""
10 + },
11 + "botId": {
12 + "value": ""
13 + },
14 + "botSku": {
15 + "value": ""
16 + },
17 + "newAppServicePlanName": {
18 + "value": ""
19 + },
20 + "newAppServicePlanSku": {
21 + "value": {
22 + "name": "S1",
23 + "tier": "Standard",
24 + "size": "S1",
25 + "family": "S",
26 + "capacity": 1
27 + }
28 + },
29 + "appServicePlanLocation": {
30 + "value": ""
31 + },
32 + "existingAppServicePlan": {
33 + "value": ""
34 + },
35 + "newWebAppName": {
36 + "value": ""
37 + }
38 + }
39 +}
...\ No newline at end of file ...\ No newline at end of file
1 +{
2 + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
3 + "contentVersion": "1.0.0.0",
4 + "parameters": {
5 + "groupLocation": {
6 + "type": "string",
7 + "metadata": {
8 + "description": "Specifies the location of the Resource Group."
9 + }
10 + },
11 + "groupName": {
12 + "type": "string",
13 + "metadata": {
14 + "description": "Specifies the name of the Resource Group."
15 + }
16 + },
17 + "appId": {
18 + "type": "string",
19 + "metadata": {
20 + "description": "Active Directory App ID, set as MicrosoftAppId in the Web App's Application Settings."
21 + }
22 + },
23 + "appSecret": {
24 + "type": "string",
25 + "metadata": {
26 + "description": "Active Directory App Password, set as MicrosoftAppPassword in the Web App's Application Settings."
27 + }
28 + },
29 + "botId": {
30 + "type": "string",
31 + "metadata": {
32 + "description": "The globally unique and immutable bot ID. Also used to configure the displayName of the bot, which is mutable."
33 + }
34 + },
35 + "botSku": {
36 + "type": "string",
37 + "metadata": {
38 + "description": "The pricing tier of the Bot Service Registration. Acceptable values are F0 and S1."
39 + }
40 + },
41 + "newAppServicePlanName": {
42 + "type": "string",
43 + "metadata": {
44 + "description": "The name of the App Service Plan."
45 + }
46 + },
47 + "newAppServicePlanSku": {
48 + "type": "object",
49 + "defaultValue": {
50 + "name": "S1",
51 + "tier": "Standard",
52 + "size": "S1",
53 + "family": "S",
54 + "capacity": 1
55 + },
56 + "metadata": {
57 + "description": "The SKU of the App Service Plan. Defaults to Standard values."
58 + }
59 + },
60 + "newAppServicePlanLocation": {
61 + "type": "string",
62 + "metadata": {
63 + "description": "The location of the App Service Plan. Defaults to \"westus\"."
64 + }
65 + },
66 + "newWebAppName": {
67 + "type": "string",
68 + "defaultValue": "",
69 + "metadata": {
70 + "description": "The globally unique name of the Web App. Defaults to the value passed in for \"botId\"."
71 + }
72 + }
73 + },
74 + "variables": {
75 + "appServicePlanName": "[parameters('newAppServicePlanName')]",
76 + "resourcesLocation": "[parameters('newAppServicePlanLocation')]",
77 + "webAppName": "[if(empty(parameters('newWebAppName')), parameters('botId'), parameters('newWebAppName'))]",
78 + "siteHost": "[concat(variables('webAppName'), '.azurewebsites.net')]",
79 + "botEndpoint": "[concat('https://', variables('siteHost'), '/api/messages')]"
80 + },
81 + "resources": [
82 + {
83 + "name": "[parameters('groupName')]",
84 + "type": "Microsoft.Resources/resourceGroups",
85 + "apiVersion": "2018-05-01",
86 + "location": "[parameters('groupLocation')]",
87 + "properties": {
88 + }
89 + },
90 + {
91 + "type": "Microsoft.Resources/deployments",
92 + "apiVersion": "2018-05-01",
93 + "name": "storageDeployment",
94 + "resourceGroup": "[parameters('groupName')]",
95 + "dependsOn": [
96 + "[resourceId('Microsoft.Resources/resourceGroups/', parameters('groupName'))]"
97 + ],
98 + "properties": {
99 + "mode": "Incremental",
100 + "template": {
101 + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
102 + "contentVersion": "1.0.0.0",
103 + "parameters": {},
104 + "variables": {},
105 + "resources": [
106 + {
107 + "comments": "Create a new App Service Plan",
108 + "type": "Microsoft.Web/serverfarms",
109 + "name": "[variables('appServicePlanName')]",
110 + "apiVersion": "2018-02-01",
111 + "location": "[variables('resourcesLocation')]",
112 + "sku": "[parameters('newAppServicePlanSku')]",
113 + "properties": {
114 + "name": "[variables('appServicePlanName')]"
115 + }
116 + },
117 + {
118 + "comments": "Create a Web App using the new App Service Plan",
119 + "type": "Microsoft.Web/sites",
120 + "apiVersion": "2015-08-01",
121 + "location": "[variables('resourcesLocation')]",
122 + "kind": "app",
123 + "dependsOn": [
124 + "[resourceId('Microsoft.Web/serverfarms/', variables('appServicePlanName'))]"
125 + ],
126 + "name": "[variables('webAppName')]",
127 + "properties": {
128 + "name": "[variables('webAppName')]",
129 + "serverFarmId": "[variables('appServicePlanName')]",
130 + "siteConfig": {
131 + "appSettings": [
132 + {
133 + "name": "WEBSITE_NODE_DEFAULT_VERSION",
134 + "value": "10.14.1"
135 + },
136 + {
137 + "name": "MicrosoftAppId",
138 + "value": "[parameters('appId')]"
139 + },
140 + {
141 + "name": "MicrosoftAppPassword",
142 + "value": "[parameters('appSecret')]"
143 + }
144 + ],
145 + "cors": {
146 + "allowedOrigins": [
147 + "https://botservice.hosting.portal.azure.net",
148 + "https://hosting.onecloud.azure-test.net/"
149 + ]
150 + }
151 + }
152 + }
153 + },
154 + {
155 + "apiVersion": "2017-12-01",
156 + "type": "Microsoft.BotService/botServices",
157 + "name": "[parameters('botId')]",
158 + "location": "global",
159 + "kind": "bot",
160 + "sku": {
161 + "name": "[parameters('botSku')]"
162 + },
163 + "properties": {
164 + "name": "[parameters('botId')]",
165 + "displayName": "[parameters('botId')]",
166 + "endpoint": "[variables('botEndpoint')]",
167 + "msaAppId": "[parameters('appId')]",
168 + "developerAppInsightsApplicationId": null,
169 + "developerAppInsightKey": null,
170 + "publishingCredentials": null,
171 + "storageResourceId": null
172 + },
173 + "dependsOn": [
174 + "[resourceId('Microsoft.Web/sites/', variables('webAppName'))]"
175 + ]
176 + }
177 + ],
178 + "outputs": {}
179 + }
180 + }
181 + }
182 + ]
183 +}
...\ No newline at end of file ...\ No newline at end of file
1 +{
2 + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
3 + "contentVersion": "1.0.0.0",
4 + "parameters": {
5 + "appId": {
6 + "type": "string",
7 + "metadata": {
8 + "description": "Active Directory App ID, set as MicrosoftAppId in the Web App's Application Settings."
9 + }
10 + },
11 + "appSecret": {
12 + "type": "string",
13 + "metadata": {
14 + "description": "Active Directory App Password, set as MicrosoftAppPassword in the Web App's Application Settings. Defaults to \"\"."
15 + }
16 + },
17 + "botId": {
18 + "type": "string",
19 + "metadata": {
20 + "description": "The globally unique and immutable bot ID. Also used to configure the displayName of the bot, which is mutable."
21 + }
22 + },
23 + "botSku": {
24 + "defaultValue": "F0",
25 + "type": "string",
26 + "metadata": {
27 + "description": "The pricing tier of the Bot Service Registration. Acceptable values are F0 and S1."
28 + }
29 + },
30 + "newAppServicePlanName": {
31 + "type": "string",
32 + "defaultValue": "",
33 + "metadata": {
34 + "description": "The name of the new App Service Plan."
35 + }
36 + },
37 + "newAppServicePlanSku": {
38 + "type": "object",
39 + "defaultValue": {
40 + "name": "S1",
41 + "tier": "Standard",
42 + "size": "S1",
43 + "family": "S",
44 + "capacity": 1
45 + },
46 + "metadata": {
47 + "description": "The SKU of the App Service Plan. Defaults to Standard values."
48 + }
49 + },
50 + "appServicePlanLocation": {
51 + "type": "string",
52 + "metadata": {
53 + "description": "The location of the App Service Plan."
54 + }
55 + },
56 + "existingAppServicePlan": {
57 + "type": "string",
58 + "defaultValue": "",
59 + "metadata": {
60 + "description": "Name of the existing App Service Plan used to create the Web App for the bot."
61 + }
62 + },
63 + "newWebAppName": {
64 + "type": "string",
65 + "defaultValue": "",
66 + "metadata": {
67 + "description": "The globally unique name of the Web App. Defaults to the value passed in for \"botId\"."
68 + }
69 + }
70 + },
71 + "variables": {
72 + "defaultAppServicePlanName": "[if(empty(parameters('existingAppServicePlan')), 'createNewAppServicePlan', parameters('existingAppServicePlan'))]",
73 + "useExistingAppServicePlan": "[not(equals(variables('defaultAppServicePlanName'), 'createNewAppServicePlan'))]",
74 + "servicePlanName": "[if(variables('useExistingAppServicePlan'), parameters('existingAppServicePlan'), parameters('newAppServicePlanName'))]",
75 + "resourcesLocation": "[parameters('appServicePlanLocation')]",
76 + "webAppName": "[if(empty(parameters('newWebAppName')), parameters('botId'), parameters('newWebAppName'))]",
77 + "siteHost": "[concat(variables('webAppName'), '.azurewebsites.net')]",
78 + "botEndpoint": "[concat('https://', variables('siteHost'), '/api/messages')]"
79 + },
80 + "resources": [
81 + {
82 + "comments": "Create a new App Service Plan if no existing App Service Plan name was passed in.",
83 + "type": "Microsoft.Web/serverfarms",
84 + "condition": "[not(variables('useExistingAppServicePlan'))]",
85 + "name": "[variables('servicePlanName')]",
86 + "apiVersion": "2018-02-01",
87 + "location": "[variables('resourcesLocation')]",
88 + "sku": "[parameters('newAppServicePlanSku')]",
89 + "properties": {
90 + "name": "[variables('servicePlanName')]"
91 + }
92 + },
93 + {
94 + "comments": "Create a Web App using an App Service Plan",
95 + "type": "Microsoft.Web/sites",
96 + "apiVersion": "2015-08-01",
97 + "location": "[variables('resourcesLocation')]",
98 + "kind": "app",
99 + "dependsOn": [
100 + "[resourceId('Microsoft.Web/serverfarms/', variables('servicePlanName'))]"
101 + ],
102 + "name": "[variables('webAppName')]",
103 + "properties": {
104 + "name": "[variables('webAppName')]",
105 + "serverFarmId": "[variables('servicePlanName')]",
106 + "siteConfig": {
107 + "appSettings": [
108 + {
109 + "name": "WEBSITE_NODE_DEFAULT_VERSION",
110 + "value": "10.14.1"
111 + },
112 + {
113 + "name": "MicrosoftAppId",
114 + "value": "[parameters('appId')]"
115 + },
116 + {
117 + "name": "MicrosoftAppPassword",
118 + "value": "[parameters('appSecret')]"
119 + }
120 + ],
121 + "cors": {
122 + "allowedOrigins": [
123 + "https://botservice.hosting.portal.azure.net",
124 + "https://hosting.onecloud.azure-test.net/"
125 + ]
126 + }
127 + }
128 + }
129 + },
130 + {
131 + "apiVersion": "2017-12-01",
132 + "type": "Microsoft.BotService/botServices",
133 + "name": "[parameters('botId')]",
134 + "location": "global",
135 + "kind": "bot",
136 + "sku": {
137 + "name": "[parameters('botSku')]"
138 + },
139 + "properties": {
140 + "name": "[parameters('botId')]",
141 + "displayName": "[parameters('botId')]",
142 + "endpoint": "[variables('botEndpoint')]",
143 + "msaAppId": "[parameters('appId')]",
144 + "developerAppInsightsApplicationId": null,
145 + "developerAppInsightKey": null,
146 + "publishingCredentials": null,
147 + "storageResourceId": null
148 + },
149 + "dependsOn": [
150 + "[resourceId('Microsoft.Web/sites/', variables('webAppName'))]"
151 + ]
152 + }
153 + ]
154 +}
...\ No newline at end of file ...\ No newline at end of file
1 +//This is still work in progress
2 +/*
3 +Please report any bugs to nicomwaks@gmail.com
4 +
5 +i have added console.log on line 48
6 +
7 +
8 +
9 +
10 + */
11 +'use strict'
12 +
13 +const express = require('express')
14 +const bodyParser = require('body-parser')
15 +const request = require('request')
16 +const app = express()
17 +
18 +app.set('port', (process.env.PORT || 5000))
19 +
20 +// parse application/x-www-form-urlencoded
21 +app.use(bodyParser.urlencoded({extended: false}))
22 +
23 +// parse application/json
24 +app.use(bodyParser.json())
25 +
26 +// index
27 +app.get('/', function (req, res) {
28 + res.send('hello world i am a secret bot')
29 +})
30 +
31 +// for facebook verification
32 +app.get('/webhook/', function (req, res) {
33 + if (req.query['hub.verify_token'] === 'my_voice_is_my_password_verify_me') {
34 + res.send(req.query['hub.challenge'])
35 + } else {
36 + res.send('Error, wrong token')
37 + }
38 +})
39 +
40 +// to post data
41 +app.post('/webhook/', function (req, res) {
42 + let messaging_events = req.body.entry[0].messaging
43 + for (let i = 0; i < messaging_events.length; i++) {
44 + let event = req.body.entry[0].messaging[i]
45 + let sender = event.sender.id
46 + if (event.message && event.message.text) {
47 + let text = event.message.text
48 + if (text === 'Generic'){
49 + console.log("welcome to chatbot")
50 + //sendGenericMessage(sender)
51 + continue
52 + }
53 + sendTextMessage(sender, "Text received, echo: " + text.substring(0, 200))
54 + }
55 + if (event.postback) {
56 + let text = JSON.stringify(event.postback)
57 + sendTextMessage(sender, "Postback received: "+text.substring(0, 200), token)
58 + continue
59 + }
60 + }
61 + res.sendStatus(200)
62 +})
63 +
64 +
65 +// recommended to inject access tokens as environmental variables, e.g.
66 +// const token = process.env.FB_PAGE_ACCESS_TOKEN
67 +const token = "EAAupaHJrQWABAEqni9O28fmMkpTvq5TO9T9OdPVlEBbj7ZCodF9B8rKeChVGduhGNjxr4zSPXWZA6LKdWZBkCxkuHoYZBmgrmQsrol7RiPoeh8NgvHy60VTcAu5TxdcQdBVSaZBaJIEA8cBbJKuP84CMa8UnroXdZAqALIK8gj1VKGNY3JNvWG"
68 +
69 +function sendTextMessage(sender, text) {
70 + let messageData = { text:text }
71 +
72 + request({
73 + url: 'https://graph.facebook.com/v2.6/me/messages',
74 + qs: {access_token:token},
75 + method: 'POST',
76 + json: {
77 + recipient: {id:sender},
78 + message: messageData,
79 + }
80 + }, function(error, response, body) {
81 + if (error) {
82 + console.log('Error sending messages: ', error)
83 + } else if (response.body.error) {
84 + console.log('Error: ', response.body.error)
85 + }
86 + })
87 +}
88 +
89 +function sendGenericMessage(sender) {
90 + let messageData = {
91 + "attachment": {
92 + "type": "template",
93 + "payload": {
94 + "template_type": "generic",
95 + "elements": [{
96 + "title": "First card",
97 + "subtitle": "Element #1 of an hscroll",
98 + "image_url": "http://messengerdemo.parseapp.com/img/rift.png",
99 + "buttons": [{
100 + "type": "web_url",
101 + "url": "https://www.messenger.com",
102 + "title": "web url"
103 + }, {
104 + "type": "postback",
105 + "title": "Postback",
106 + "payload": "Payload for first element in a generic bubble",
107 + }],
108 + }, {
109 + "title": "Second card",
110 + "subtitle": "Element #2 of an hscroll",
111 + "image_url": "http://messengerdemo.parseapp.com/img/gearvr.png",
112 + "buttons": [{
113 + "type": "postback",
114 + "title": "Postback",
115 + "payload": "Payload for second element in a generic bubble",
116 + }],
117 + }]
118 + }
119 + }
120 + }
121 + request({
122 + url: 'https://graph.facebook.com/v2.6/me/messages',
123 + qs: {access_token:token},
124 + method: 'POST',
125 + json: {
126 + recipient: {id:sender},
127 + message: messageData,
128 + }
129 + }, function(error, response, body) {
130 + if (error) {
131 + console.log('Error sending messages: ', error)
132 + } else if (response.body.error) {
133 + console.log('Error: ', response.body.error)
134 + }
135 + })
136 +}
137 +
138 +// spin spin sugar
139 +app.listen(app.get('port'), function() {
140 + console.log('running on port', app.get('port'))
141 +})
This diff could not be displayed because it is too large.
1 +{
2 + "name": "my-own-bot",
3 + "version": "1.0.0",
4 + "description": "like me",
5 + "author": "Generated using Microsoft Bot Builder Yeoman generator v4.9.0",
6 + "license": "MIT",
7 + "main": "index.js",
8 + "scripts": {
9 + "start": "node ./index.js",
10 + "watch": "nodemon ./index.js",
11 + "lint": "eslint .",
12 + "test": "echo \"Error: no test specified\" && exit 1"
13 + },
14 + "repository": {
15 + "type": "git",
16 + "url": "https://github.com"
17 + },
18 + "dependencies": {
19 + "botbuilder": "~4.9.0",
20 + "dotenv": "^8.2.0",
21 + "restify": "~8.5.1"
22 + },
23 + "devDependencies": {
24 + "eslint": "^7.0.0",
25 + "eslint-config-standard": "^14.1.1",
26 + "eslint-plugin-import": "^2.20.2",
27 + "eslint-plugin-node": "^11.1.0",
28 + "eslint-plugin-promise": "^4.2.1",
29 + "eslint-plugin-standard": "^4.0.1",
30 + "nodemon": "~2.0.4"
31 + }
32 +}
1 +{
2 + "name": "secretbots",
3 + "version": "1.0.0",
4 + "lockfileVersion": 1,
5 + "requires": true,
6 + "dependencies": {
7 + "accepts": {
8 + "version": "1.3.7",
9 + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
10 + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
11 + "requires": {
12 + "mime-types": "~2.1.24",
13 + "negotiator": "0.6.2"
14 + }
15 + },
16 + "ajv": {
17 + "version": "6.12.2",
18 + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz",
19 + "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==",
20 + "requires": {
21 + "fast-deep-equal": "^3.1.1",
22 + "fast-json-stable-stringify": "^2.0.0",
23 + "json-schema-traverse": "^0.4.1",
24 + "uri-js": "^4.2.2"
25 + }
26 + },
27 + "array-flatten": {
28 + "version": "1.1.1",
29 + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
30 + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
31 + },
32 + "asn1": {
33 + "version": "0.2.4",
34 + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
35 + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
36 + "requires": {
37 + "safer-buffer": "~2.1.0"
38 + }
39 + },
40 + "assert-plus": {
41 + "version": "1.0.0",
42 + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
43 + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
44 + },
45 + "asynckit": {
46 + "version": "0.4.0",
47 + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
48 + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
49 + },
50 + "aws-sign2": {
51 + "version": "0.7.0",
52 + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
53 + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
54 + },
55 + "aws4": {
56 + "version": "1.10.0",
57 + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.0.tgz",
58 + "integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA=="
59 + },
60 + "bcrypt-pbkdf": {
61 + "version": "1.0.2",
62 + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
63 + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
64 + "requires": {
65 + "tweetnacl": "^0.14.3"
66 + }
67 + },
68 + "body-parser": {
69 + "version": "1.19.0",
70 + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
71 + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
72 + "requires": {
73 + "bytes": "3.1.0",
74 + "content-type": "~1.0.4",
75 + "debug": "2.6.9",
76 + "depd": "~1.1.2",
77 + "http-errors": "1.7.2",
78 + "iconv-lite": "0.4.24",
79 + "on-finished": "~2.3.0",
80 + "qs": "6.7.0",
81 + "raw-body": "2.4.0",
82 + "type-is": "~1.6.17"
83 + }
84 + },
85 + "bytes": {
86 + "version": "3.1.0",
87 + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
88 + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
89 + },
90 + "caseless": {
91 + "version": "0.12.0",
92 + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
93 + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
94 + },
95 + "combined-stream": {
96 + "version": "1.0.8",
97 + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
98 + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
99 + "requires": {
100 + "delayed-stream": "~1.0.0"
101 + }
102 + },
103 + "content-disposition": {
104 + "version": "0.5.3",
105 + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
106 + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
107 + "requires": {
108 + "safe-buffer": "5.1.2"
109 + }
110 + },
111 + "content-type": {
112 + "version": "1.0.4",
113 + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
114 + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
115 + },
116 + "cookie": {
117 + "version": "0.4.0",
118 + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
119 + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
120 + },
121 + "cookie-signature": {
122 + "version": "1.0.6",
123 + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
124 + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
125 + },
126 + "core-util-is": {
127 + "version": "1.0.2",
128 + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
129 + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
130 + },
131 + "dashdash": {
132 + "version": "1.14.1",
133 + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
134 + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
135 + "requires": {
136 + "assert-plus": "^1.0.0"
137 + }
138 + },
139 + "debug": {
140 + "version": "2.6.9",
141 + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
142 + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
143 + "requires": {
144 + "ms": "2.0.0"
145 + }
146 + },
147 + "delayed-stream": {
148 + "version": "1.0.0",
149 + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
150 + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
151 + },
152 + "depd": {
153 + "version": "1.1.2",
154 + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
155 + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
156 + },
157 + "destroy": {
158 + "version": "1.0.4",
159 + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
160 + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
161 + },
162 + "ecc-jsbn": {
163 + "version": "0.1.2",
164 + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
165 + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
166 + "requires": {
167 + "jsbn": "~0.1.0",
168 + "safer-buffer": "^2.1.0"
169 + }
170 + },
171 + "ee-first": {
172 + "version": "1.1.1",
173 + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
174 + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
175 + },
176 + "encodeurl": {
177 + "version": "1.0.2",
178 + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
179 + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
180 + },
181 + "escape-html": {
182 + "version": "1.0.3",
183 + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
184 + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
185 + },
186 + "etag": {
187 + "version": "1.8.1",
188 + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
189 + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
190 + },
191 + "express": {
192 + "version": "4.17.1",
193 + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
194 + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
195 + "requires": {
196 + "accepts": "~1.3.7",
197 + "array-flatten": "1.1.1",
198 + "body-parser": "1.19.0",
199 + "content-disposition": "0.5.3",
200 + "content-type": "~1.0.4",
201 + "cookie": "0.4.0",
202 + "cookie-signature": "1.0.6",
203 + "debug": "2.6.9",
204 + "depd": "~1.1.2",
205 + "encodeurl": "~1.0.2",
206 + "escape-html": "~1.0.3",
207 + "etag": "~1.8.1",
208 + "finalhandler": "~1.1.2",
209 + "fresh": "0.5.2",
210 + "merge-descriptors": "1.0.1",
211 + "methods": "~1.1.2",
212 + "on-finished": "~2.3.0",
213 + "parseurl": "~1.3.3",
214 + "path-to-regexp": "0.1.7",
215 + "proxy-addr": "~2.0.5",
216 + "qs": "6.7.0",
217 + "range-parser": "~1.2.1",
218 + "safe-buffer": "5.1.2",
219 + "send": "0.17.1",
220 + "serve-static": "1.14.1",
221 + "setprototypeof": "1.1.1",
222 + "statuses": "~1.5.0",
223 + "type-is": "~1.6.18",
224 + "utils-merge": "1.0.1",
225 + "vary": "~1.1.2"
226 + }
227 + },
228 + "extend": {
229 + "version": "3.0.2",
230 + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
231 + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
232 + },
233 + "extsprintf": {
234 + "version": "1.3.0",
235 + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
236 + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
237 + },
238 + "fast-deep-equal": {
239 + "version": "3.1.3",
240 + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
241 + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
242 + },
243 + "fast-json-stable-stringify": {
244 + "version": "2.1.0",
245 + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
246 + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
247 + },
248 + "finalhandler": {
249 + "version": "1.1.2",
250 + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
251 + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
252 + "requires": {
253 + "debug": "2.6.9",
254 + "encodeurl": "~1.0.2",
255 + "escape-html": "~1.0.3",
256 + "on-finished": "~2.3.0",
257 + "parseurl": "~1.3.3",
258 + "statuses": "~1.5.0",
259 + "unpipe": "~1.0.0"
260 + }
261 + },
262 + "forever-agent": {
263 + "version": "0.6.1",
264 + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
265 + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
266 + },
267 + "form-data": {
268 + "version": "2.3.3",
269 + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
270 + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
271 + "requires": {
272 + "asynckit": "^0.4.0",
273 + "combined-stream": "^1.0.6",
274 + "mime-types": "^2.1.12"
275 + }
276 + },
277 + "forwarded": {
278 + "version": "0.1.2",
279 + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
280 + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
281 + },
282 + "fresh": {
283 + "version": "0.5.2",
284 + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
285 + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
286 + },
287 + "getpass": {
288 + "version": "0.1.7",
289 + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
290 + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
291 + "requires": {
292 + "assert-plus": "^1.0.0"
293 + }
294 + },
295 + "har-schema": {
296 + "version": "2.0.0",
297 + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
298 + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
299 + },
300 + "har-validator": {
301 + "version": "5.1.3",
302 + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
303 + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
304 + "requires": {
305 + "ajv": "^6.5.5",
306 + "har-schema": "^2.0.0"
307 + }
308 + },
309 + "http-errors": {
310 + "version": "1.7.2",
311 + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
312 + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
313 + "requires": {
314 + "depd": "~1.1.2",
315 + "inherits": "2.0.3",
316 + "setprototypeof": "1.1.1",
317 + "statuses": ">= 1.5.0 < 2",
318 + "toidentifier": "1.0.0"
319 + }
320 + },
321 + "http-signature": {
322 + "version": "1.2.0",
323 + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
324 + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
325 + "requires": {
326 + "assert-plus": "^1.0.0",
327 + "jsprim": "^1.2.2",
328 + "sshpk": "^1.7.0"
329 + }
330 + },
331 + "iconv-lite": {
332 + "version": "0.4.24",
333 + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
334 + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
335 + "requires": {
336 + "safer-buffer": ">= 2.1.2 < 3"
337 + }
338 + },
339 + "inherits": {
340 + "version": "2.0.3",
341 + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
342 + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
343 + },
344 + "ipaddr.js": {
345 + "version": "1.9.1",
346 + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
347 + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
348 + },
349 + "is-typedarray": {
350 + "version": "1.0.0",
351 + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
352 + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
353 + },
354 + "isstream": {
355 + "version": "0.1.2",
356 + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
357 + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
358 + },
359 + "jsbn": {
360 + "version": "0.1.1",
361 + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
362 + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
363 + },
364 + "json-schema": {
365 + "version": "0.2.3",
366 + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
367 + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
368 + },
369 + "json-schema-traverse": {
370 + "version": "0.4.1",
371 + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
372 + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
373 + },
374 + "json-stringify-safe": {
375 + "version": "5.0.1",
376 + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
377 + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
378 + },
379 + "jsprim": {
380 + "version": "1.4.1",
381 + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
382 + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
383 + "requires": {
384 + "assert-plus": "1.0.0",
385 + "extsprintf": "1.3.0",
386 + "json-schema": "0.2.3",
387 + "verror": "1.10.0"
388 + }
389 + },
390 + "media-typer": {
391 + "version": "0.3.0",
392 + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
393 + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
394 + },
395 + "merge-descriptors": {
396 + "version": "1.0.1",
397 + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
398 + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
399 + },
400 + "methods": {
401 + "version": "1.1.2",
402 + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
403 + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
404 + },
405 + "mime": {
406 + "version": "1.6.0",
407 + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
408 + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
409 + },
410 + "mime-db": {
411 + "version": "1.44.0",
412 + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
413 + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg=="
414 + },
415 + "mime-types": {
416 + "version": "2.1.27",
417 + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
418 + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
419 + "requires": {
420 + "mime-db": "1.44.0"
421 + }
422 + },
423 + "ms": {
424 + "version": "2.0.0",
425 + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
426 + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
427 + },
428 + "negotiator": {
429 + "version": "0.6.2",
430 + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
431 + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
432 + },
433 + "oauth-sign": {
434 + "version": "0.9.0",
435 + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
436 + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
437 + },
438 + "on-finished": {
439 + "version": "2.3.0",
440 + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
441 + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
442 + "requires": {
443 + "ee-first": "1.1.1"
444 + }
445 + },
446 + "parseurl": {
447 + "version": "1.3.3",
448 + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
449 + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
450 + },
451 + "path-to-regexp": {
452 + "version": "0.1.7",
453 + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
454 + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
455 + },
456 + "performance-now": {
457 + "version": "2.1.0",
458 + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
459 + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
460 + },
461 + "proxy-addr": {
462 + "version": "2.0.6",
463 + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
464 + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==",
465 + "requires": {
466 + "forwarded": "~0.1.2",
467 + "ipaddr.js": "1.9.1"
468 + }
469 + },
470 + "psl": {
471 + "version": "1.8.0",
472 + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
473 + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ=="
474 + },
475 + "punycode": {
476 + "version": "2.1.1",
477 + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
478 + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
479 + },
480 + "qs": {
481 + "version": "6.7.0",
482 + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
483 + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
484 + },
485 + "range-parser": {
486 + "version": "1.2.1",
487 + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
488 + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
489 + },
490 + "raw-body": {
491 + "version": "2.4.0",
492 + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
493 + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
494 + "requires": {
495 + "bytes": "3.1.0",
496 + "http-errors": "1.7.2",
497 + "iconv-lite": "0.4.24",
498 + "unpipe": "1.0.0"
499 + }
500 + },
501 + "request": {
502 + "version": "2.88.2",
503 + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
504 + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
505 + "requires": {
506 + "aws-sign2": "~0.7.0",
507 + "aws4": "^1.8.0",
508 + "caseless": "~0.12.0",
509 + "combined-stream": "~1.0.6",
510 + "extend": "~3.0.2",
511 + "forever-agent": "~0.6.1",
512 + "form-data": "~2.3.2",
513 + "har-validator": "~5.1.3",
514 + "http-signature": "~1.2.0",
515 + "is-typedarray": "~1.0.0",
516 + "isstream": "~0.1.2",
517 + "json-stringify-safe": "~5.0.1",
518 + "mime-types": "~2.1.19",
519 + "oauth-sign": "~0.9.0",
520 + "performance-now": "^2.1.0",
521 + "qs": "~6.5.2",
522 + "safe-buffer": "^5.1.2",
523 + "tough-cookie": "~2.5.0",
524 + "tunnel-agent": "^0.6.0",
525 + "uuid": "^3.3.2"
526 + },
527 + "dependencies": {
528 + "qs": {
529 + "version": "6.5.2",
530 + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
531 + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
532 + }
533 + }
534 + },
535 + "safe-buffer": {
536 + "version": "5.1.2",
537 + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
538 + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
539 + },
540 + "safer-buffer": {
541 + "version": "2.1.2",
542 + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
543 + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
544 + },
545 + "send": {
546 + "version": "0.17.1",
547 + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
548 + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
549 + "requires": {
550 + "debug": "2.6.9",
551 + "depd": "~1.1.2",
552 + "destroy": "~1.0.4",
553 + "encodeurl": "~1.0.2",
554 + "escape-html": "~1.0.3",
555 + "etag": "~1.8.1",
556 + "fresh": "0.5.2",
557 + "http-errors": "~1.7.2",
558 + "mime": "1.6.0",
559 + "ms": "2.1.1",
560 + "on-finished": "~2.3.0",
561 + "range-parser": "~1.2.1",
562 + "statuses": "~1.5.0"
563 + },
564 + "dependencies": {
565 + "ms": {
566 + "version": "2.1.1",
567 + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
568 + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
569 + }
570 + }
571 + },
572 + "serve-static": {
573 + "version": "1.14.1",
574 + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
575 + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
576 + "requires": {
577 + "encodeurl": "~1.0.2",
578 + "escape-html": "~1.0.3",
579 + "parseurl": "~1.3.3",
580 + "send": "0.17.1"
581 + }
582 + },
583 + "setprototypeof": {
584 + "version": "1.1.1",
585 + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
586 + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
587 + },
588 + "sshpk": {
589 + "version": "1.16.1",
590 + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
591 + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
592 + "requires": {
593 + "asn1": "~0.2.3",
594 + "assert-plus": "^1.0.0",
595 + "bcrypt-pbkdf": "^1.0.0",
596 + "dashdash": "^1.12.0",
597 + "ecc-jsbn": "~0.1.1",
598 + "getpass": "^0.1.1",
599 + "jsbn": "~0.1.0",
600 + "safer-buffer": "^2.0.2",
601 + "tweetnacl": "~0.14.0"
602 + }
603 + },
604 + "statuses": {
605 + "version": "1.5.0",
606 + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
607 + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
608 + },
609 + "toidentifier": {
610 + "version": "1.0.0",
611 + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
612 + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
613 + },
614 + "tough-cookie": {
615 + "version": "2.5.0",
616 + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
617 + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
618 + "requires": {
619 + "psl": "^1.1.28",
620 + "punycode": "^2.1.1"
621 + }
622 + },
623 + "tunnel-agent": {
624 + "version": "0.6.0",
625 + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
626 + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
627 + "requires": {
628 + "safe-buffer": "^5.0.1"
629 + }
630 + },
631 + "tweetnacl": {
632 + "version": "0.14.5",
633 + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
634 + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
635 + },
636 + "type-is": {
637 + "version": "1.6.18",
638 + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
639 + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
640 + "requires": {
641 + "media-typer": "0.3.0",
642 + "mime-types": "~2.1.24"
643 + }
644 + },
645 + "unpipe": {
646 + "version": "1.0.0",
647 + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
648 + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
649 + },
650 + "uri-js": {
651 + "version": "4.2.2",
652 + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
653 + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
654 + "requires": {
655 + "punycode": "^2.1.0"
656 + }
657 + },
658 + "utils-merge": {
659 + "version": "1.0.1",
660 + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
661 + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
662 + },
663 + "uuid": {
664 + "version": "3.4.0",
665 + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
666 + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
667 + },
668 + "vary": {
669 + "version": "1.1.2",
670 + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
671 + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
672 + },
673 + "verror": {
674 + "version": "1.10.0",
675 + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
676 + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
677 + "requires": {
678 + "assert-plus": "^1.0.0",
679 + "core-util-is": "1.0.2",
680 + "extsprintf": "^1.2.0"
681 + }
682 + }
683 + }
684 +}
1 +{
2 + "name": "secretbots",
3 + "version": "1.0.0",
4 + "description": "",
5 + "main": "index.js",
6 + "scripts": {
7 + "test": "echo \"Error: no test specified\" && exit 1"
8 + },
9 + "author": "",
10 + "license": "ISC",
11 + "dependencies": {
12 + "body-parser": "^1.15.0",
13 + "express": "^4.13.4",
14 + "request": "^2.71.0"
15 + }
16 +}
1 +"use strict";
2 +
3 +const moment = require('moment');
4 +const process = require('process');
5 +const async = require('async');
6 +
7 +const express = require('express');
8 +
9 +const AWS = require('aws-sdk');
10 +const s3 = new AWS.S3({
11 + region: 'us-east-1',
12 + accessKeyId: 'ASIA265JP6JAKK4AAZFL',
13 + secretAccessKey: 'CuomIr3gEgtwPcOWSN94mC54iIMMWfXTVSFJXDUf',
14 + sessionToken: 'FwoGZXIvYXdzEMX//////////wEaDLD1Yk1xhWixp9ZSByK/AbDcW6LYR1EpPLNIqCteTtZtXCoIIFr7b2olxXkKyQUVQGUnf4YJVcmk8PD1/1T9O/MaJIuO0c0tAO2ir31Oa5nsc1QomKEFpAy/girMM3JML5azImFhjMKDGYahUiZWTfiP8oksDWoeEM+HjwEvWzSa5nBBoTlKxa33Gjo/15LL/oHDgN75K/fiHWAJ6Uvey0I1Lu26CjohLbEE9tQ61ymtq4GiO96DSjgSTW4gyrp5R+tn0oLH1A51oLNBfFxsKOvfxu8FMi2RufVY3HSu2JsFVyXMXkMrgDhVA5lZngj2ZW7SQx8No0vfb9zPKuHXxGKjkQY='
15 + });
16 +var BUCKET = 'oss-project-image-storage';
17 +var S3UPparam = {
18 + Bucket:BUCKET,
19 + Key:null,
20 + ACL:'public-read',
21 + Body:null
22 +};
23 +var S3DOWNparam = {
24 + Bucket:BUCKET,
25 + Prefix:null
26 +};
27 +
28 +const multer = require('multer');
29 +
30 +// tensorflow의 data folder에 저장할 때 multer 설정
31 +var storage_data = multer.diskStorage({
32 + destination: function (req, file, cb) {
33 + var dir = req.params.directoryName;
34 + cb(null, dataFolder + dir + '/');
35 + },
36 + filename: function (req, file, cb) {
37 + cb(null, new Date().valueOf() + "_" + file.originalname);
38 + }
39 +});
40 +var upload_data = multer({
41 + storage: storage_data
42 +});
43 +
44 +// tensorflow의 test folder에 저장할 때 multer 설정
45 +var storage_test = multer.diskStorage({
46 + destination: function (req, file, cb) {
47 + var dir = req.params.directoryName;
48 + cb(null, testFolder);
49 + },
50 + filename: function (req, file, cb) {
51 + cb(null, "test.jpg");
52 + }
53 +});
54 +var upload_test = multer({
55 + storage: storage_test
56 +});
57 +
58 +const bodyParser = require('body-parser');
59 +const fs = require('fs');
60 +const path = require('path');
61 +const pyShell = require('python-shell');
62 +
63 +const PORT = 8080;
64 +const HOST = '0.0.0.0';
65 +
66 +const app = express();
67 +
68 +const dataFolder = './tensorflow/data/';
69 +const testFolder = './tensorflow/test/';
70 +
71 +
72 +app.set('view engine', 'pug');
73 +app.set('views', './views');
74 +app.locals.pretty = true
75 +
76 +app.use(bodyParser.urlencoded({extended:false}));
77 +
78 +
79 +// tensorflow 학습을 완료한 시간
80 +var LearnTime = undefined;
81 +
82 +
83 +// Redirect Root to Home
84 +app.get('/', (req, res) => {
85 + res.redirect('./home/');
86 +});
87 +
88 +
89 +// Main Page
90 +app.get('/home/', (req, res) => {
91 + // data 폴더 목록을 읽어서 home 화면에 넘겨줌
92 + fs.readdir(dataFolder, function(error, filelist){
93 + if(error)
94 + console.log(error);
95 + res.render('home', {fileList:filelist, learntime:LearnTime});
96 + });
97 +});
98 +
99 +
100 +// Directory existence checking
101 +app.post('/directory_check', (req, res) => {
102 +
103 + var dir = req.body.directoryName; // 입력받은 새로운 directory name
104 +
105 + // Directory exists
106 + if(fs.existsSync(dataFolder + dir))
107 + {
108 + // Go back page
109 + res.render('error_directoryAdd');
110 + }
111 + // Directory doesn't exist
112 + else
113 + {
114 + // Make directory
115 + fs.mkdirSync(dataFolder + dir);
116 + console.log('Directory Create: ' + dir);
117 + res.redirect('/home/' + dir + '/');
118 + }
119 +});
120 +
121 +
122 +// Basic Directory Page
123 +app.get('/home/:directoryName/', (req, res) => {
124 +
125 + // 임시로 이미지 파일명 목록을 보여주는 코드
126 + var directoryName = req.params.directoryName; // 접속한 directory name
127 + var filelist = new Array();
128 + var imagelist = new Array();
129 +
130 + // read directory's file list
131 + fs.readdirSync(dataFolder + directoryName).forEach(function(file, index){
132 + // 확장자 추출 및 이미지 파일인지 체크
133 + var fileType = path.extname(file);
134 + if(fileType == ".jpg" || fileType == ".jpeg") {
135 + filelist.push(file);
136 + }
137 + });
138 + S3DOWNparam.Prefix = directoryName + '/';
139 + s3.listObjects(S3DOWNparam, function (err, data) {
140 + if (err)
141 + console.log(err);
142 + else {
143 + data.Contents.forEach(function(image) {
144 + imagelist.push('https://' + BUCKET + '.s3.amazonaws.com/' + image.Key.replace(' ', '+'));
145 + });
146 + }
147 + res.render('directory', {directoryName:directoryName, fileList:filelist, imageList:imagelist});
148 + });
149 +});
150 +
151 +
152 +// Image Upload Directory Page
153 +app.post('/home/:directoryName/upload/', upload_data.array('userImage'), (req, res) => {
154 + var directoryName = req.params.directoryName;
155 +
156 + req.files.forEach(function(file) {
157 + S3UPparam.Key = directoryName + '/' + new Date().valueOf() + "_" + file.originalname;
158 + S3UPparam.Body = fs.createReadStream(file.path);
159 + s3.upload(S3UPparam, function (err, result) {
160 + if (err)
161 + console.log(err);
162 + });
163 + });
164 +
165 + res.redirect('/home/' + directoryName + '/');
166 +});
167 +
168 +
169 +// Modify Directory name
170 +app.get('/home/:directoryName/modify/', (req, res) => {
171 + var directoryName = req.params.directoryName; // 본래 directory 이름
172 + var newName = req.query.newName; // 입력받은 수정할 이름
173 +
174 + // exist query.newName
175 + if (req.query.newName) {
176 + // modify Directory name
177 + var Path = dataFolder + directoryName;
178 + fs.rename(Path, dataFolder + newName, function (err) {
179 + if (err) {
180 + console.log("Directory Rename error: " + err);
181 + } else {
182 + console.log("Directory Rename: " + directoryName + " -> " + newName);
183 + }
184 + });
185 + s3.listObjects({Bucket:BUCKET, Prefix: directoryName + '/'}, function(err, data) {
186 + if (data.Contents.length) {
187 + async.each(data.Contents, function(file, cb) {
188 + s3.copyObject({
189 + Bucket: BUCKET,
190 + CopySource: BUCKET + '/' + file.Key,
191 + Key: file.Key.replace(directoryName, newName)
192 + })
193 + .promise()
194 + .then(() =>
195 + s3.deleteObject({
196 + Bucket: BUCKET,
197 + Key: file.Key
198 + }).promise()
199 + ).catch ((e) => console.error(e));
200 + });
201 + }
202 + s3.deleteObject({
203 + Bucket: BUCKET,
204 + Key: directoryName
205 + }, function(err, data) {
206 + if (err) console.log(err);
207 + });
208 + });
209 + res.redirect('/');
210 + }
211 + else {
212 + res.render('directoryModifyCheck', {directoryName:JSON.stringify(directoryName)});
213 + }
214 +});
215 +
216 +
217 +// Delete Directory
218 +app.get('/home/:directoryName/delete/', (req, res) => {
219 + var directoryName = req.params.directoryName;
220 + // exist query.real
221 + if (req.query.real) {
222 + // Remove Directory and Files
223 + var path = dataFolder + directoryName;
224 + fs.readdirSync(path).forEach(function(file,index){
225 + var curPath = path + "/" + file;
226 + fs.unlinkSync(curPath);
227 + });
228 + fs.rmdirSync(path);
229 + // Remove S3 Directory and Files
230 + s3.listObjects({Bucket:BUCKET, Prefix: directoryName + '/'}, function(err, data) {
231 + if (data.Contents.length) {
232 + async.each(data.Contents, function(file, cb) {
233 + s3.deleteObject({
234 + Bucket: BUCKET,
235 + Key: file.Key
236 + }, function(err, data) {
237 + if (err) console.log(err);
238 + });
239 + });
240 + }
241 + });
242 +
243 + console.log('Directory Delete: ' + directoryName);
244 + res.redirect('/');
245 + }
246 + else {
247 + res.render('directoryDeleteCheck', {directoryName:JSON.stringify(directoryName)});
248 + }
249 +});
250 +
251 +
252 +// Image Test Page
253 +app.post('/test', upload_test.single('TestImage'), (req, res) => {
254 + var results = new Array();
255 +
256 + console.log("Test Start");
257 + process.chdir('./tensorflow/'); // move working directory
258 +
259 + // retrain_run_inference.py로 test
260 + pyShell.PythonShell.run('retrain_run_inference.py', null, function (err, result) {
261 + if (err) {
262 + console.log('Test error: '+ err);
263 + }
264 + else {
265 + var strArr = result.toString().split('\n'); // result를 줄바꿈 기준으로 자름
266 + // 결과만 results에 저장
267 + strArr.forEach(function(str) {
268 + if (str.indexOf('score') > -1) {
269 + str = str.split('\\n').join('');
270 + results = str.split(',');
271 + for(var i = 0; i < results.length; i++){
272 + results[i] = results[i].substring(1);
273 + }
274 + }
275 + });
276 + }
277 + process.chdir('../'); // move working directory
278 + console.log(results);
279 + console.log("Test Complete");
280 + res.render('testResult', {result:results});
281 + });
282 +});
283 +
284 +
285 +// Image Learning
286 +app.get('/imageLearning', (req, res) => {
287 + var results = new Array();
288 + var tmp = LearnTime;
289 +
290 + res.redirect('/home/');
291 +
292 + console.log("Learning Start");
293 + process.chdir('./tensorflow/'); // move working directory
294 +
295 + // retrain.py로 학습
296 + LearnTime = "학습 중...";
297 + pyShell.PythonShell.run('retrain.py', null, function (err, result) {
298 + if (err) {
299 + console.log('Learning error: '+ err);
300 + LearnTime = tmp + ', error: 다시 학습 버튼을 눌러주세요';
301 + }
302 + else {
303 + LearnTime = moment().format('YYYY-MM-DD HH:mm:ss'); // 학습 완료한 시간 저장
304 + console.log("Learning Complete");
305 + }
306 + });
307 + process.chdir('../'); // move working directory
308 +});
309 +
310 +
311 +app.listen(PORT, HOST);
312 +console.log('Running on http://${HOST}:${POST}');
...\ No newline at end of file ...\ No newline at end of file
1 +# Copyright 2015 The TensorFlow Authors. All Rights Reserved.
2 +#
3 +# Licensed under the Apache License, Version 2.0 (the "License");
4 +# you may not use this file except in compliance with the License.
5 +# You may obtain a copy of the License at
6 +#
7 +# http://www.apache.org/licenses/LICENSE-2.0
8 +#
9 +# Unless required by applicable law or agreed to in writing, software
10 +# distributed under the License is distributed on an "AS IS" BASIS,
11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 +# See the License for the specific language governing permissions and
13 +# limitations under the License.
14 +# ==============================================================================
15 +"""Simple transfer learning with an Inception v3 architecture model which
16 +displays summaries in TensorBoard.
17 +
18 +This example shows how to take a Inception v3 architecture model trained on
19 +ImageNet images, and train a new top layer that can recognize other classes of
20 +images.
21 +
22 +The top layer receives as input a 2048-dimensional vector for each image. We
23 +train a softmax layer on top of this representation. Assuming the softmax layer
24 +contains N labels, this corresponds to learning N + 2048*N model parameters
25 +corresponding to the learned biases and weights.
26 +
27 +Here's an example, which assumes you have a folder containing class-named
28 +subfolders, each full of images for each label. The example folder flower_photos
29 +should have a structure like this:
30 +
31 +~/flower_photos/daisy/photo1.jpg
32 +~/flower_photos/daisy/photo2.jpg
33 +...
34 +~/flower_photos/rose/anotherphoto77.jpg
35 +...
36 +~/flower_photos/sunflower/somepicture.jpg
37 +
38 +The subfolder names are important, since they define what label is applied to
39 +each image, but the filenames themselves don't matter. Once your images are
40 +prepared, you can run the training with a command like this:
41 +
42 +bazel build tensorflow/examples/image_retraining:retrain && \
43 +bazel-bin/tensorflow/examples/image_retraining/retrain \
44 +--image_dir ~/flower_photos
45 +
46 +You can replace the image_dir argument with any folder containing subfolders of
47 +images. The label for each image is taken from the name of the subfolder it's
48 +in.
49 +
50 +This produces a new model file that can be loaded and run by any TensorFlow
51 +program, for example the label_image sample code.
52 +
53 +
54 +To use with TensorBoard:
55 +
56 +By default, this script will log summaries to /tmp/retrain_logs directory
57 +
58 +Visualize the summaries with this command:
59 +
60 +tensorboard --logdir /tmp/retrain_logs
61 +
62 +"""
63 +from __future__ import absolute_import
64 +from __future__ import division
65 +from __future__ import print_function
66 +
67 +import argparse
68 +from datetime import datetime
69 +import hashlib
70 +import os.path
71 +import random
72 +import re
73 +import struct
74 +import sys
75 +import tarfile
76 +
77 +import numpy as np
78 +from six.moves import urllib
79 +import tensorflow as tf
80 +
81 +from tensorflow.python.framework import graph_util
82 +from tensorflow.python.framework import tensor_shape
83 +from tensorflow.python.platform import gfile
84 +from tensorflow.python.util import compat
85 +
86 +FLAGS = None
87 +
88 +# These are all parameters that are tied to the particular model architecture
89 +# we're using for Inception v3. These include things like tensor names and their
90 +# sizes. If you want to adapt this script to work with another model, you will
91 +# need to update these to reflect the values in the network you're using.
92 +# pylint: disable=line-too-long
93 +DATA_URL = 'http://download.tensorflow.org/models/image/imagenet/inception-2015-12-05.tgz'
94 +# pylint: enable=line-too-long
95 +BOTTLENECK_TENSOR_NAME = 'pool_3/_reshape:0'
96 +BOTTLENECK_TENSOR_SIZE = 2048
97 +MODEL_INPUT_WIDTH = 299
98 +MODEL_INPUT_HEIGHT = 299
99 +MODEL_INPUT_DEPTH = 3
100 +JPEG_DATA_TENSOR_NAME = 'DecodeJpeg/contents:0'
101 +RESIZED_INPUT_TENSOR_NAME = 'ResizeBilinear:0'
102 +MAX_NUM_IMAGES_PER_CLASS = 2 ** 27 - 1 # ~134M
103 +
104 +
105 +def create_image_lists(image_dir, testing_percentage, validation_percentage):
106 + """Builds a list of training images from the file system.
107 +
108 + Analyzes the sub folders in the image directory, splits them into stable
109 + training, testing, and validation sets, and returns a data structure
110 + describing the lists of images for each label and their paths.
111 +
112 + Args:
113 + image_dir: String path to a folder containing subfolders of images.
114 + testing_percentage: Integer percentage of the images to reserve for tests.
115 + validation_percentage: Integer percentage of images reserved for validation.
116 +
117 + Returns:
118 + A dictionary containing an entry for each label subfolder, with images split
119 + into training, testing, and validation sets within each label.
120 + """
121 + if not gfile.Exists(image_dir):
122 + print("Image directory '" + image_dir + "' not found.")
123 + return None
124 + result = {}
125 + sub_dirs = [x[0] for x in gfile.Walk(image_dir)]
126 + # The root directory comes first, so skip it.
127 + is_root_dir = True
128 + for sub_dir in sub_dirs:
129 + if is_root_dir:
130 + is_root_dir = False
131 + continue
132 + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG']
133 + file_list = []
134 + dir_name = os.path.basename(sub_dir)
135 + if dir_name == image_dir:
136 + continue
137 + print("Looking for images in '" + dir_name + "'")
138 + for extension in extensions:
139 + file_glob = os.path.join(image_dir, dir_name, '*.' + extension)
140 + file_list.extend(gfile.Glob(file_glob))
141 + if not file_list:
142 + print('No files found')
143 + continue
144 + if len(file_list) < 20:
145 + print('WARNING: Folder has less than 20 images, which may cause issues.')
146 + elif len(file_list) > MAX_NUM_IMAGES_PER_CLASS:
147 + print('WARNING: Folder {} has more than {} images. Some images will '
148 + 'never be selected.'.format(dir_name, MAX_NUM_IMAGES_PER_CLASS))
149 + label_name = re.sub(r'[^a-z0-9]+', ' ', dir_name.lower())
150 + training_images = []
151 + testing_images = []
152 + validation_images = []
153 + for file_name in file_list:
154 + base_name = os.path.basename(file_name)
155 + # We want to ignore anything after '_nohash_' in the file name when
156 + # deciding which set to put an image in, the data set creator has a way of
157 + # grouping photos that are close variations of each other. For example
158 + # this is used in the plant disease data set to group multiple pictures of
159 + # the same leaf.
160 + hash_name = re.sub(r'_nohash_.*$', '', file_name)
161 + # This looks a bit magical, but we need to decide whether this file should
162 + # go into the training, testing, or validation sets, and we want to keep
163 + # existing files in the same set even if more files are subsequently
164 + # added.
165 + # To do that, we need a stable way of deciding based on just the file name
166 + # itself, so we do a hash of that and then use that to generate a
167 + # probability value that we use to assign it.
168 + hash_name_hashed = hashlib.sha1(compat.as_bytes(hash_name)).hexdigest()
169 + percentage_hash = ((int(hash_name_hashed, 16) %
170 + (MAX_NUM_IMAGES_PER_CLASS + 1)) *
171 + (100.0 / MAX_NUM_IMAGES_PER_CLASS))
172 + if percentage_hash < validation_percentage:
173 + validation_images.append(base_name)
174 + elif percentage_hash < (testing_percentage + validation_percentage):
175 + testing_images.append(base_name)
176 + else:
177 + training_images.append(base_name)
178 + result[label_name] = {
179 + 'dir': dir_name,
180 + 'training': training_images,
181 + 'testing': testing_images,
182 + 'validation': validation_images,
183 + }
184 + return result
185 +
186 +
187 +def get_image_path(image_lists, label_name, index, image_dir, category):
188 + """"Returns a path to an image for a label at the given index.
189 +
190 + Args:
191 + image_lists: Dictionary of training images for each label.
192 + label_name: Label string we want to get an image for.
193 + index: Int offset of the image we want. This will be moduloed by the
194 + available number of images for the label, so it can be arbitrarily large.
195 + image_dir: Root folder string of the subfolders containing the training
196 + images.
197 + category: Name string of set to pull images from - training, testing, or
198 + validation.
199 +
200 + Returns:
201 + File system path string to an image that meets the requested parameters.
202 +
203 + """
204 + if label_name not in image_lists:
205 + tf.logging.fatal('Label does not exist %s.', label_name)
206 + label_lists = image_lists[label_name]
207 + if category not in label_lists:
208 + tf.logging.fatal('Category does not exist %s.', category)
209 + category_list = label_lists[category]
210 + if not category_list:
211 + tf.logging.fatal('Label %s has no images in the category %s.',
212 + label_name, category)
213 + mod_index = index % len(category_list)
214 + base_name = category_list[mod_index]
215 + sub_dir = label_lists['dir']
216 + full_path = os.path.join(image_dir, sub_dir, base_name)
217 + return full_path
218 +
219 +
220 +def get_bottleneck_path(image_lists, label_name, index, bottleneck_dir,
221 + category):
222 + """"Returns a path to a bottleneck file for a label at the given index.
223 +
224 + Args:
225 + image_lists: Dictionary of training images for each label.
226 + label_name: Label string we want to get an image for.
227 + index: Integer offset of the image we want. This will be moduloed by the
228 + available number of images for the label, so it can be arbitrarily large.
229 + bottleneck_dir: Folder string holding cached files of bottleneck values.
230 + category: Name string of set to pull images from - training, testing, or
231 + validation.
232 +
233 + Returns:
234 + File system path string to an image that meets the requested parameters.
235 + """
236 + return get_image_path(image_lists, label_name, index, bottleneck_dir,
237 + category) + '.txt'
238 +
239 +
240 +def create_inception_graph():
241 + """"Creates a graph from saved GraphDef file and returns a Graph object.
242 +
243 + Returns:
244 + Graph holding the trained Inception network, and various tensors we'll be
245 + manipulating.
246 + """
247 + with tf.Session() as sess:
248 + model_filename = os.path.join(
249 + FLAGS.model_dir, 'classify_image_graph_def.pb')
250 + with gfile.FastGFile(model_filename, 'rb') as f:
251 + graph_def = tf.GraphDef()
252 + graph_def.ParseFromString(f.read())
253 + bottleneck_tensor, jpeg_data_tensor, resized_input_tensor = (
254 + tf.import_graph_def(graph_def, name='', return_elements=[
255 + BOTTLENECK_TENSOR_NAME, JPEG_DATA_TENSOR_NAME,
256 + RESIZED_INPUT_TENSOR_NAME]))
257 + return sess.graph, bottleneck_tensor, jpeg_data_tensor, resized_input_tensor
258 +
259 +
260 +def run_bottleneck_on_image(sess, image_data, image_data_tensor,
261 + bottleneck_tensor):
262 + """Runs inference on an image to extract the 'bottleneck' summary layer.
263 +
264 + Args:
265 + sess: Current active TensorFlow Session.
266 + image_data: String of raw JPEG data.
267 + image_data_tensor: Input data layer in the graph.
268 + bottleneck_tensor: Layer before the final softmax.
269 +
270 + Returns:
271 + Numpy array of bottleneck values.
272 + """
273 + bottleneck_values = sess.run(
274 + bottleneck_tensor,
275 + {image_data_tensor: image_data})
276 + bottleneck_values = np.squeeze(bottleneck_values)
277 + return bottleneck_values
278 +
279 +
280 +def maybe_download_and_extract():
281 + """Download and extract model tar file.
282 +
283 + If the pretrained model we're using doesn't already exist, this function
284 + downloads it from the TensorFlow.org website and unpacks it into a directory.
285 + """
286 + dest_directory = FLAGS.model_dir
287 + if not os.path.exists(dest_directory):
288 + os.makedirs(dest_directory)
289 + filename = DATA_URL.split('/')[-1]
290 + filepath = os.path.join(dest_directory, filename)
291 + if not os.path.exists(filepath):
292 +
293 + def _progress(count, block_size, total_size):
294 + sys.stdout.write('\r>> Downloading %s %.1f%%' %
295 + (filename,
296 + float(count * block_size) / float(total_size) * 100.0))
297 + sys.stdout.flush()
298 +
299 + filepath, _ = urllib.request.urlretrieve(DATA_URL,
300 + filepath,
301 + _progress)
302 + print()
303 + statinfo = os.stat(filepath)
304 + print('Successfully downloaded', filename, statinfo.st_size, 'bytes.')
305 + tarfile.open(filepath, 'r:gz').extractall(dest_directory)
306 +
307 +
308 +def ensure_dir_exists(dir_name):
309 + """Makes sure the folder exists on disk.
310 +
311 + Args:
312 + dir_name: Path string to the folder we want to create.
313 + """
314 + if not os.path.exists(dir_name):
315 + os.makedirs(dir_name)
316 +
317 +
318 +def write_list_of_floats_to_file(list_of_floats , file_path):
319 + """Writes a given list of floats to a binary file.
320 +
321 + Args:
322 + list_of_floats: List of floats we want to write to a file.
323 + file_path: Path to a file where list of floats will be stored.
324 +
325 + """
326 +
327 + s = struct.pack('d' * BOTTLENECK_TENSOR_SIZE, *list_of_floats)
328 + with open(file_path, 'wb') as f:
329 + f.write(s)
330 +
331 +
332 +def read_list_of_floats_from_file(file_path):
333 + """Reads list of floats from a given file.
334 +
335 + Args:
336 + file_path: Path to a file where list of floats was stored.
337 + Returns:
338 + Array of bottleneck values (list of floats).
339 +
340 + """
341 +
342 + with open(file_path, 'rb') as f:
343 + s = struct.unpack('d' * BOTTLENECK_TENSOR_SIZE, f.read())
344 + return list(s)
345 +
346 +
347 +bottleneck_path_2_bottleneck_values = {}
348 +
349 +def create_bottleneck_file(bottleneck_path, image_lists, label_name, index,
350 + image_dir, category, sess, jpeg_data_tensor, bottleneck_tensor):
351 + print('Creating bottleneck at ' + bottleneck_path)
352 + image_path = get_image_path(image_lists, label_name, index, image_dir, category)
353 + if not gfile.Exists(image_path):
354 + tf.logging.fatal('File does not exist %s', image_path)
355 + image_data = gfile.FastGFile(image_path, 'rb').read()
356 + bottleneck_values = run_bottleneck_on_image(sess, image_data, jpeg_data_tensor, bottleneck_tensor)
357 + bottleneck_string = ','.join(str(x) for x in bottleneck_values)
358 + with open(bottleneck_path, 'w') as bottleneck_file:
359 + bottleneck_file.write(bottleneck_string)
360 +
361 +def get_or_create_bottleneck(sess, image_lists, label_name, index, image_dir,
362 + category, bottleneck_dir, jpeg_data_tensor,
363 + bottleneck_tensor):
364 + """Retrieves or calculates bottleneck values for an image.
365 +
366 + If a cached version of the bottleneck data exists on-disk, return that,
367 + otherwise calculate the data and save it to disk for future use.
368 +
369 + Args:
370 + sess: The current active TensorFlow Session.
371 + image_lists: Dictionary of training images for each label.
372 + label_name: Label string we want to get an image for.
373 + index: Integer offset of the image we want. This will be modulo-ed by the
374 + available number of images for the label, so it can be arbitrarily large.
375 + image_dir: Root folder string of the subfolders containing the training
376 + images.
377 + category: Name string of which set to pull images from - training, testing,
378 + or validation.
379 + bottleneck_dir: Folder string holding cached files of bottleneck values.
380 + jpeg_data_tensor: The tensor to feed loaded jpeg data into.
381 + bottleneck_tensor: The output tensor for the bottleneck values.
382 +
383 + Returns:
384 + Numpy array of values produced by the bottleneck layer for the image.
385 + """
386 + label_lists = image_lists[label_name]
387 + sub_dir = label_lists['dir']
388 + sub_dir_path = os.path.join(bottleneck_dir, sub_dir)
389 + ensure_dir_exists(sub_dir_path)
390 + bottleneck_path = get_bottleneck_path(image_lists, label_name, index, bottleneck_dir, category)
391 + if not os.path.exists(bottleneck_path):
392 + create_bottleneck_file(bottleneck_path, image_lists, label_name, index, image_dir, category, sess, jpeg_data_tensor, bottleneck_tensor)
393 + with open(bottleneck_path, 'r') as bottleneck_file:
394 + bottleneck_string = bottleneck_file.read()
395 + did_hit_error = False
396 + try:
397 + bottleneck_values = [float(x) for x in bottleneck_string.split(',')]
398 + except:
399 + print("Invalid float found, recreating bottleneck")
400 + did_hit_error = True
401 + if did_hit_error:
402 + create_bottleneck_file(bottleneck_path, image_lists, label_name, index, image_dir, category, sess, jpeg_data_tensor, bottleneck_tensor)
403 + with open(bottleneck_path, 'r') as bottleneck_file:
404 + bottleneck_string = bottleneck_file.read()
405 + # Allow exceptions to propagate here, since they shouldn't happen after a fresh creation
406 + bottleneck_values = [float(x) for x in bottleneck_string.split(',')]
407 + return bottleneck_values
408 +
409 +def cache_bottlenecks(sess, image_lists, image_dir, bottleneck_dir,
410 + jpeg_data_tensor, bottleneck_tensor):
411 + """Ensures all the training, testing, and validation bottlenecks are cached.
412 +
413 + Because we're likely to read the same image multiple times (if there are no
414 + distortions applied during training) it can speed things up a lot if we
415 + calculate the bottleneck layer values once for each image during
416 + preprocessing, and then just read those cached values repeatedly during
417 + training. Here we go through all the images we've found, calculate those
418 + values, and save them off.
419 +
420 + Args:
421 + sess: The current active TensorFlow Session.
422 + image_lists: Dictionary of training images for each label.
423 + image_dir: Root folder string of the subfolders containing the training
424 + images.
425 + bottleneck_dir: Folder string holding cached files of bottleneck values.
426 + jpeg_data_tensor: Input tensor for jpeg data from file.
427 + bottleneck_tensor: The penultimate output layer of the graph.
428 +
429 + Returns:
430 + Nothing.
431 + """
432 + how_many_bottlenecks = 0
433 + ensure_dir_exists(bottleneck_dir)
434 + for label_name, label_lists in image_lists.items():
435 + for category in ['training', 'testing', 'validation']:
436 + category_list = label_lists[category]
437 + for index, unused_base_name in enumerate(category_list):
438 + get_or_create_bottleneck(sess, image_lists, label_name, index,
439 + image_dir, category, bottleneck_dir,
440 + jpeg_data_tensor, bottleneck_tensor)
441 +
442 + how_many_bottlenecks += 1
443 + if how_many_bottlenecks % 100 == 0:
444 + print(str(how_many_bottlenecks) + ' bottleneck files created.')
445 +
446 +
447 +def get_random_cached_bottlenecks(sess, image_lists, how_many, category,
448 + bottleneck_dir, image_dir, jpeg_data_tensor,
449 + bottleneck_tensor):
450 + """Retrieves bottleneck values for cached images.
451 +
452 + If no distortions are being applied, this function can retrieve the cached
453 + bottleneck values directly from disk for images. It picks a random set of
454 + images from the specified category.
455 +
456 + Args:
457 + sess: Current TensorFlow Session.
458 + image_lists: Dictionary of training images for each label.
459 + how_many: If positive, a random sample of this size will be chosen.
460 + If negative, all bottlenecks will be retrieved.
461 + category: Name string of which set to pull from - training, testing, or
462 + validation.
463 + bottleneck_dir: Folder string holding cached files of bottleneck values.
464 + image_dir: Root folder string of the subfolders containing the training
465 + images.
466 + jpeg_data_tensor: The layer to feed jpeg image data into.
467 + bottleneck_tensor: The bottleneck output layer of the CNN graph.
468 +
469 + Returns:
470 + List of bottleneck arrays, their corresponding ground truths, and the
471 + relevant filenames.
472 + """
473 + class_count = len(image_lists.keys())
474 + bottlenecks = []
475 + ground_truths = []
476 + filenames = []
477 + if how_many >= 0:
478 + # Retrieve a random sample of bottlenecks.
479 + for unused_i in range(how_many):
480 + label_index = random.randrange(class_count)
481 + label_name = list(image_lists.keys())[label_index]
482 + image_index = random.randrange(MAX_NUM_IMAGES_PER_CLASS + 1)
483 + image_name = get_image_path(image_lists, label_name, image_index,
484 + image_dir, category)
485 + bottleneck = get_or_create_bottleneck(sess, image_lists, label_name,
486 + image_index, image_dir, category,
487 + bottleneck_dir, jpeg_data_tensor,
488 + bottleneck_tensor)
489 + ground_truth = np.zeros(class_count, dtype=np.float32)
490 + ground_truth[label_index] = 1.0
491 + bottlenecks.append(bottleneck)
492 + ground_truths.append(ground_truth)
493 + filenames.append(image_name)
494 + else:
495 + # Retrieve all bottlenecks.
496 + for label_index, label_name in enumerate(image_lists.keys()):
497 + for image_index, image_name in enumerate(
498 + image_lists[label_name][category]):
499 + image_name = get_image_path(image_lists, label_name, image_index,
500 + image_dir, category)
501 + bottleneck = get_or_create_bottleneck(sess, image_lists, label_name,
502 + image_index, image_dir, category,
503 + bottleneck_dir, jpeg_data_tensor,
504 + bottleneck_tensor)
505 + ground_truth = np.zeros(class_count, dtype=np.float32)
506 + ground_truth[label_index] = 1.0
507 + bottlenecks.append(bottleneck)
508 + ground_truths.append(ground_truth)
509 + filenames.append(image_name)
510 + return bottlenecks, ground_truths, filenames
511 +
512 +
513 +def get_random_distorted_bottlenecks(
514 + sess, image_lists, how_many, category, image_dir, input_jpeg_tensor,
515 + distorted_image, resized_input_tensor, bottleneck_tensor):
516 + """Retrieves bottleneck values for training images, after distortions.
517 +
518 + If we're training with distortions like crops, scales, or flips, we have to
519 + recalculate the full model for every image, and so we can't use cached
520 + bottleneck values. Instead we find random images for the requested category,
521 + run them through the distortion graph, and then the full graph to get the
522 + bottleneck results for each.
523 +
524 + Args:
525 + sess: Current TensorFlow Session.
526 + image_lists: Dictionary of training images for each label.
527 + how_many: The integer number of bottleneck values to return.
528 + category: Name string of which set of images to fetch - training, testing,
529 + or validation.
530 + image_dir: Root folder string of the subfolders containing the training
531 + images.
532 + input_jpeg_tensor: The input layer we feed the image data to.
533 + distorted_image: The output node of the distortion graph.
534 + resized_input_tensor: The input node of the recognition graph.
535 + bottleneck_tensor: The bottleneck output layer of the CNN graph.
536 +
537 + Returns:
538 + List of bottleneck arrays and their corresponding ground truths.
539 + """
540 + class_count = len(image_lists.keys())
541 + bottlenecks = []
542 + ground_truths = []
543 + for unused_i in range(how_many):
544 + label_index = random.randrange(class_count)
545 + label_name = list(image_lists.keys())[label_index]
546 + image_index = random.randrange(MAX_NUM_IMAGES_PER_CLASS + 1)
547 + image_path = get_image_path(image_lists, label_name, image_index, image_dir,
548 + category)
549 + if not gfile.Exists(image_path):
550 + tf.logging.fatal('File does not exist %s', image_path)
551 + jpeg_data = gfile.FastGFile(image_path, 'rb').read()
552 + # Note that we materialize the distorted_image_data as a numpy array before
553 + # sending running inference on the image. This involves 2 memory copies and
554 + # might be optimized in other implementations.
555 + distorted_image_data = sess.run(distorted_image,
556 + {input_jpeg_tensor: jpeg_data})
557 + bottleneck = run_bottleneck_on_image(sess, distorted_image_data,
558 + resized_input_tensor,
559 + bottleneck_tensor)
560 + ground_truth = np.zeros(class_count, dtype=np.float32)
561 + ground_truth[label_index] = 1.0
562 + bottlenecks.append(bottleneck)
563 + ground_truths.append(ground_truth)
564 + return bottlenecks, ground_truths
565 +
566 +
567 +def should_distort_images(flip_left_right, random_crop, random_scale,
568 + random_brightness):
569 + """Whether any distortions are enabled, from the input flags.
570 +
571 + Args:
572 + flip_left_right: Boolean whether to randomly mirror images horizontally.
573 + random_crop: Integer percentage setting the total margin used around the
574 + crop box.
575 + random_scale: Integer percentage of how much to vary the scale by.
576 + random_brightness: Integer range to randomly multiply the pixel values by.
577 +
578 + Returns:
579 + Boolean value indicating whether any distortions should be applied.
580 + """
581 + return (flip_left_right or (random_crop != 0) or (random_scale != 0) or
582 + (random_brightness != 0))
583 +
584 +
585 +def add_input_distortions(flip_left_right, random_crop, random_scale,
586 + random_brightness):
587 + """Creates the operations to apply the specified distortions.
588 +
589 + During training it can help to improve the results if we run the images
590 + through simple distortions like crops, scales, and flips. These reflect the
591 + kind of variations we expect in the real world, and so can help train the
592 + model to cope with natural data more effectively. Here we take the supplied
593 + parameters and construct a network of operations to apply them to an image.
594 +
595 + Cropping
596 + ~~~~~~~~
597 +
598 + Cropping is done by placing a bounding box at a random position in the full
599 + image. The cropping parameter controls the size of that box relative to the
600 + input image. If it's zero, then the box is the same size as the input and no
601 + cropping is performed. If the value is 50%, then the crop box will be half the
602 + width and height of the input. In a diagram it looks like this:
603 +
604 + < width >
605 + +---------------------+
606 + | |
607 + | width - crop% |
608 + | < > |
609 + | +------+ |
610 + | | | |
611 + | | | |
612 + | | | |
613 + | +------+ |
614 + | |
615 + | |
616 + +---------------------+
617 +
618 + Scaling
619 + ~~~~~~~
620 +
621 + Scaling is a lot like cropping, except that the bounding box is always
622 + centered and its size varies randomly within the given range. For example if
623 + the scale percentage is zero, then the bounding box is the same size as the
624 + input and no scaling is applied. If it's 50%, then the bounding box will be in
625 + a random range between half the width and height and full size.
626 +
627 + Args:
628 + flip_left_right: Boolean whether to randomly mirror images horizontally.
629 + random_crop: Integer percentage setting the total margin used around the
630 + crop box.
631 + random_scale: Integer percentage of how much to vary the scale by.
632 + random_brightness: Integer range to randomly multiply the pixel values by.
633 + graph.
634 +
635 + Returns:
636 + The jpeg input layer and the distorted result tensor.
637 + """
638 +
639 + jpeg_data = tf.placeholder(tf.string, name='DistortJPGInput')
640 + decoded_image = tf.image.decode_jpeg(jpeg_data, channels=MODEL_INPUT_DEPTH)
641 + decoded_image_as_float = tf.cast(decoded_image, dtype=tf.float32)
642 + decoded_image_4d = tf.expand_dims(decoded_image_as_float, 0)
643 + margin_scale = 1.0 + (random_crop / 100.0)
644 + resize_scale = 1.0 + (random_scale / 100.0)
645 + margin_scale_value = tf.constant(margin_scale)
646 + resize_scale_value = tf.random_uniform(tensor_shape.scalar(),
647 + minval=1.0,
648 + maxval=resize_scale)
649 + scale_value = tf.multiply(margin_scale_value, resize_scale_value)
650 + precrop_width = tf.multiply(scale_value, MODEL_INPUT_WIDTH)
651 + precrop_height = tf.multiply(scale_value, MODEL_INPUT_HEIGHT)
652 + precrop_shape = tf.stack([precrop_height, precrop_width])
653 + precrop_shape_as_int = tf.cast(precrop_shape, dtype=tf.int32)
654 + precropped_image = tf.image.resize_bilinear(decoded_image_4d,
655 + precrop_shape_as_int)
656 + precropped_image_3d = tf.squeeze(precropped_image, squeeze_dims=[0])
657 + cropped_image = tf.random_crop(precropped_image_3d,
658 + [MODEL_INPUT_HEIGHT, MODEL_INPUT_WIDTH,
659 + MODEL_INPUT_DEPTH])
660 + if flip_left_right:
661 + flipped_image = tf.image.random_flip_left_right(cropped_image)
662 + else:
663 + flipped_image = cropped_image
664 + brightness_min = 1.0 - (random_brightness / 100.0)
665 + brightness_max = 1.0 + (random_brightness / 100.0)
666 + brightness_value = tf.random_uniform(tensor_shape.scalar(),
667 + minval=brightness_min,
668 + maxval=brightness_max)
669 + brightened_image = tf.multiply(flipped_image, brightness_value)
670 + distort_result = tf.expand_dims(brightened_image, 0, name='DistortResult')
671 + return jpeg_data, distort_result
672 +
673 +
674 +def variable_summaries(var):
675 + """Attach a lot of summaries to a Tensor (for TensorBoard visualization)."""
676 + with tf.name_scope('summaries'):
677 + mean = tf.reduce_mean(var)
678 + tf.summary.scalar('mean', mean)
679 + with tf.name_scope('stddev'):
680 + stddev = tf.sqrt(tf.reduce_mean(tf.square(var - mean)))
681 + tf.summary.scalar('stddev', stddev)
682 + tf.summary.scalar('max', tf.reduce_max(var))
683 + tf.summary.scalar('min', tf.reduce_min(var))
684 + tf.summary.histogram('histogram', var)
685 +
686 +
687 +def add_final_training_ops(class_count, final_tensor_name, bottleneck_tensor):
688 + """Adds a new softmax and fully-connected layer for training.
689 +
690 + We need to retrain the top layer to identify our new classes, so this function
691 + adds the right operations to the graph, along with some variables to hold the
692 + weights, and then sets up all the gradients for the backward pass.
693 +
694 + The set up for the softmax and fully-connected layers is based on:
695 + https://tensorflow.org/versions/master/tutorials/mnist/beginners/index.html
696 +
697 + Args:
698 + class_count: Integer of how many categories of things we're trying to
699 + recognize.
700 + final_tensor_name: Name string for the new final node that produces results.
701 + bottleneck_tensor: The output of the main CNN graph.
702 +
703 + Returns:
704 + The tensors for the training and cross entropy results, and tensors for the
705 + bottleneck input and ground truth input.
706 + """
707 + with tf.name_scope('input'):
708 + bottleneck_input = tf.placeholder_with_default(
709 + bottleneck_tensor, shape=[None, BOTTLENECK_TENSOR_SIZE],
710 + name='BottleneckInputPlaceholder')
711 +
712 + ground_truth_input = tf.placeholder(tf.float32,
713 + [None, class_count],
714 + name='GroundTruthInput')
715 +
716 + # Organizing the following ops as `final_training_ops` so they're easier
717 + # to see in TensorBoard
718 + layer_name = 'final_training_ops'
719 + with tf.name_scope(layer_name):
720 + with tf.name_scope('weights'):
721 + layer_weights = tf.Variable(tf.truncated_normal([BOTTLENECK_TENSOR_SIZE, class_count], stddev=0.001), name='final_weights')
722 + variable_summaries(layer_weights)
723 + with tf.name_scope('biases'):
724 + layer_biases = tf.Variable(tf.zeros([class_count]), name='final_biases')
725 + variable_summaries(layer_biases)
726 + with tf.name_scope('Wx_plus_b'):
727 + logits = tf.matmul(bottleneck_input, layer_weights) + layer_biases
728 + tf.summary.histogram('pre_activations', logits)
729 +
730 + final_tensor = tf.nn.softmax(logits, name=final_tensor_name)
731 + tf.summary.histogram('activations', final_tensor)
732 +
733 + with tf.name_scope('cross_entropy'):
734 + cross_entropy = tf.nn.softmax_cross_entropy_with_logits(
735 + labels=ground_truth_input, logits=logits)
736 + with tf.name_scope('total'):
737 + cross_entropy_mean = tf.reduce_mean(cross_entropy)
738 + tf.summary.scalar('cross_entropy', cross_entropy_mean)
739 +
740 + with tf.name_scope('train'):
741 + train_step = tf.train.GradientDescentOptimizer(FLAGS.learning_rate).minimize(
742 + cross_entropy_mean)
743 +
744 + return (train_step, cross_entropy_mean, bottleneck_input, ground_truth_input,
745 + final_tensor)
746 +
747 +
748 +def add_evaluation_step(result_tensor, ground_truth_tensor):
749 + """Inserts the operations we need to evaluate the accuracy of our results.
750 +
751 + Args:
752 + result_tensor: The new final node that produces results.
753 + ground_truth_tensor: The node we feed ground truth data
754 + into.
755 +
756 + Returns:
757 + Tuple of (evaluation step, prediction).
758 + """
759 + with tf.name_scope('accuracy'):
760 + with tf.name_scope('correct_prediction'):
761 + prediction = tf.argmax(result_tensor, 1)
762 + correct_prediction = tf.equal(
763 + prediction, tf.argmax(ground_truth_tensor, 1))
764 + with tf.name_scope('accuracy'):
765 + evaluation_step = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
766 + tf.summary.scalar('accuracy', evaluation_step)
767 + return evaluation_step, prediction
768 +
769 +
770 +def main(_):
771 + # Setup the directory we'll write summaries to for TensorBoard
772 + if tf.gfile.Exists(FLAGS.summaries_dir):
773 + tf.gfile.DeleteRecursively(FLAGS.summaries_dir)
774 + tf.gfile.MakeDirs(FLAGS.summaries_dir)
775 +
776 + # Set up the pre-trained graph.
777 + maybe_download_and_extract()
778 + graph, bottleneck_tensor, jpeg_data_tensor, resized_image_tensor = (
779 + create_inception_graph())
780 +
781 + # Look at the folder structure, and create lists of all the images.
782 + image_lists = create_image_lists(FLAGS.image_dir, FLAGS.testing_percentage,
783 + FLAGS.validation_percentage)
784 + class_count = len(image_lists.keys())
785 + if class_count == 0:
786 + print('No valid folders of images found at ' + FLAGS.image_dir)
787 + return -1
788 + if class_count == 1:
789 + print('Only one valid folder of images found at ' + FLAGS.image_dir +
790 + ' - multiple classes are needed for classification.')
791 + return -1
792 +
793 + # See if the command-line flags mean we're applying any distortions.
794 + do_distort_images = should_distort_images(
795 + FLAGS.flip_left_right, FLAGS.random_crop, FLAGS.random_scale,
796 + FLAGS.random_brightness)
797 + sess = tf.Session()
798 +
799 + if do_distort_images:
800 + # We will be applying distortions, so setup the operations we'll need.
801 + distorted_jpeg_data_tensor, distorted_image_tensor = add_input_distortions(
802 + FLAGS.flip_left_right, FLAGS.random_crop, FLAGS.random_scale,
803 + FLAGS.random_brightness)
804 + else:
805 + # We'll make sure we've calculated the 'bottleneck' image summaries and
806 + # cached them on disk.
807 + cache_bottlenecks(sess, image_lists, FLAGS.image_dir, FLAGS.bottleneck_dir,
808 + jpeg_data_tensor, bottleneck_tensor)
809 +
810 + # Add the new layer that we'll be training.
811 + (train_step, cross_entropy, bottleneck_input, ground_truth_input,
812 + final_tensor) = add_final_training_ops(len(image_lists.keys()),
813 + FLAGS.final_tensor_name,
814 + bottleneck_tensor)
815 +
816 + # Create the operations we need to evaluate the accuracy of our new layer.
817 + evaluation_step, prediction = add_evaluation_step(
818 + final_tensor, ground_truth_input)
819 +
820 + # Merge all the summaries and write them out to /tmp/retrain_logs (by default)
821 + merged = tf.summary.merge_all()
822 + train_writer = tf.summary.FileWriter(FLAGS.summaries_dir + '/train',
823 + sess.graph)
824 + validation_writer = tf.summary.FileWriter(FLAGS.summaries_dir + '/validation')
825 +
826 + # Set up all our weights to their initial default values.
827 + init = tf.global_variables_initializer()
828 + sess.run(init)
829 +
830 + # Run the training for as many cycles as requested on the command line.
831 + for i in range(FLAGS.how_many_training_steps):
832 + # Get a batch of input bottleneck values, either calculated fresh every time
833 + # with distortions applied, or from the cache stored on disk.
834 + if do_distort_images:
835 + train_bottlenecks, train_ground_truth = get_random_distorted_bottlenecks(
836 + sess, image_lists, FLAGS.train_batch_size, 'training',
837 + FLAGS.image_dir, distorted_jpeg_data_tensor,
838 + distorted_image_tensor, resized_image_tensor, bottleneck_tensor)
839 + else:
840 + train_bottlenecks, train_ground_truth, _ = get_random_cached_bottlenecks(
841 + sess, image_lists, FLAGS.train_batch_size, 'training',
842 + FLAGS.bottleneck_dir, FLAGS.image_dir, jpeg_data_tensor,
843 + bottleneck_tensor)
844 + # Feed the bottlenecks and ground truth into the graph, and run a training
845 + # step. Capture training summaries for TensorBoard with the `merged` op.
846 + train_summary, _ = sess.run([merged, train_step],
847 + feed_dict={bottleneck_input: train_bottlenecks,
848 + ground_truth_input: train_ground_truth})
849 + train_writer.add_summary(train_summary, i)
850 +
851 + # Every so often, print out how well the graph is training.
852 + is_last_step = (i + 1 == FLAGS.how_many_training_steps)
853 + if (i % FLAGS.eval_step_interval) == 0 or is_last_step:
854 + train_accuracy, cross_entropy_value = sess.run(
855 + [evaluation_step, cross_entropy],
856 + feed_dict={bottleneck_input: train_bottlenecks,
857 + ground_truth_input: train_ground_truth})
858 + print('%s: Step %d: Train accuracy = %.1f%%' % (datetime.now(), i,
859 + train_accuracy * 100))
860 + print('%s: Step %d: Cross entropy = %f' % (datetime.now(), i,
861 + cross_entropy_value))
862 + validation_bottlenecks, validation_ground_truth, _ = (
863 + get_random_cached_bottlenecks(
864 + sess, image_lists, FLAGS.validation_batch_size, 'validation',
865 + FLAGS.bottleneck_dir, FLAGS.image_dir, jpeg_data_tensor,
866 + bottleneck_tensor))
867 + # Run a validation step and capture training summaries for TensorBoard
868 + # with the `merged` op.
869 + validation_summary, validation_accuracy = sess.run(
870 + [merged, evaluation_step],
871 + feed_dict={bottleneck_input: validation_bottlenecks,
872 + ground_truth_input: validation_ground_truth})
873 + validation_writer.add_summary(validation_summary, i)
874 + print('%s: Step %d: Validation accuracy = %.1f%% (N=%d)' %
875 + (datetime.now(), i, validation_accuracy * 100,
876 + len(validation_bottlenecks)))
877 +
878 + # We've completed all our training, so run a final test evaluation on
879 + # some new images we haven't used before.
880 + test_bottlenecks, test_ground_truth, test_filenames = (
881 + get_random_cached_bottlenecks(sess, image_lists, FLAGS.test_batch_size,
882 + 'testing', FLAGS.bottleneck_dir,
883 + FLAGS.image_dir, jpeg_data_tensor,
884 + bottleneck_tensor))
885 + test_accuracy, predictions = sess.run(
886 + [evaluation_step, prediction],
887 + feed_dict={bottleneck_input: test_bottlenecks,
888 + ground_truth_input: test_ground_truth})
889 + print('Final test accuracy = %.1f%% (N=%d)' % (
890 + test_accuracy * 100, len(test_bottlenecks)))
891 +
892 + if FLAGS.print_misclassified_test_images:
893 + print('=== MISCLASSIFIED TEST IMAGES ===')
894 + for i, test_filename in enumerate(test_filenames):
895 + if predictions[i] != test_ground_truth[i].argmax():
896 + print('%70s %s' % (test_filename,
897 + list(image_lists.keys())[predictions[i]]))
898 +
899 + # Write out the trained graph and labels with the weights stored as constants.
900 + output_graph_def = graph_util.convert_variables_to_constants(
901 + sess, graph.as_graph_def(), [FLAGS.final_tensor_name])
902 + with gfile.FastGFile(FLAGS.output_graph, 'wb') as f:
903 + f.write(output_graph_def.SerializeToString())
904 + with gfile.FastGFile(FLAGS.output_labels, 'w') as f:
905 + f.write('\n'.join(image_lists.keys()) + '\n')
906 +
907 +
908 +if __name__ == '__main__':
909 + parser = argparse.ArgumentParser()
910 + parser.add_argument(
911 + '--image_dir',
912 + type=str,
913 + default='./data/',
914 + help='Path to folders of labeled images.'
915 + )
916 + parser.add_argument(
917 + '--output_graph',
918 + type=str,
919 + default='./test/output_graph.pb',
920 + help='Where to save the trained graph.'
921 + )
922 + parser.add_argument(
923 + '--output_labels',
924 + type=str,
925 + default='./test/output_labels.txt',
926 + help='Where to save the trained graph\'s labels.'
927 + )
928 + parser.add_argument(
929 + '--summaries_dir',
930 + type=str,
931 + default='./test/retrain_logs',
932 + help='Where to save summary logs for TensorBoard.'
933 + )
934 + parser.add_argument(
935 + '--how_many_training_steps',
936 + type=int,
937 + default=1000,
938 + help='How many training steps to run before ending.'
939 + )
940 + parser.add_argument(
941 + '--learning_rate',
942 + type=float,
943 + default=0.01,
944 + help='How large a learning rate to use when training.'
945 + )
946 + parser.add_argument(
947 + '--testing_percentage',
948 + type=int,
949 + default=10,
950 + help='What percentage of images to use as a test set.'
951 + )
952 + parser.add_argument(
953 + '--validation_percentage',
954 + type=int,
955 + default=10,
956 + help='What percentage of images to use as a validation set.'
957 + )
958 + parser.add_argument(
959 + '--eval_step_interval',
960 + type=int,
961 + default=10,
962 + help='How often to evaluate the training results.'
963 + )
964 + parser.add_argument(
965 + '--train_batch_size',
966 + type=int,
967 + default=100,
968 + help='How many images to train on at a time.'
969 + )
970 + parser.add_argument(
971 + '--test_batch_size',
972 + type=int,
973 + default=-1,
974 + help="""\
975 + How many images to test on. This test set is only used once, to evaluate
976 + the final accuracy of the model after training completes.
977 + A value of -1 causes the entire test set to be used, which leads to more
978 + stable results across runs.\
979 + """
980 + )
981 + parser.add_argument(
982 + '--validation_batch_size',
983 + type=int,
984 + default=100,
985 + help="""\
986 + How many images to use in an evaluation batch. This validation set is
987 + used much more often than the test set, and is an early indicator of how
988 + accurate the model is during training.
989 + A value of -1 causes the entire validation set to be used, which leads to
990 + more stable results across training iterations, but may be slower on large
991 + training sets.\
992 + """
993 + )
994 + parser.add_argument(
995 + '--print_misclassified_test_images',
996 + default=False,
997 + help="""\
998 + Whether to print out a list of all misclassified test images.\
999 + """,
1000 + action='store_true'
1001 + )
1002 + parser.add_argument(
1003 + '--model_dir',
1004 + type=str,
1005 + default='./test/imagenet',
1006 + help="""\
1007 + Path to classify_image_graph_def.pb,
1008 + imagenet_synset_to_human_label_map.txt, and
1009 + imagenet_2012_challenge_label_map_proto.pbtxt.\
1010 + """
1011 + )
1012 + parser.add_argument(
1013 + '--bottleneck_dir',
1014 + type=str,
1015 + default='./test/bottleneck',
1016 + help='Path to cache bottleneck layer values as files.'
1017 + )
1018 + parser.add_argument(
1019 + '--final_tensor_name',
1020 + type=str,
1021 + default='final_result',
1022 + help="""\
1023 + The name of the output classification layer in the retrained graph.\
1024 + """
1025 + )
1026 + parser.add_argument(
1027 + '--flip_left_right',
1028 + default=False,
1029 + help="""\
1030 + Whether to randomly flip half of the training images horizontally.\
1031 + """,
1032 + action='store_true'
1033 + )
1034 + parser.add_argument(
1035 + '--random_crop',
1036 + type=int,
1037 + default=0,
1038 + help="""\
1039 + A percentage determining how much of a margin to randomly crop off the
1040 + training images.\
1041 + """
1042 + )
1043 + parser.add_argument(
1044 + '--random_scale',
1045 + type=int,
1046 + default=0,
1047 + help="""\
1048 + A percentage determining how much to randomly scale up the size of the
1049 + training images by.\
1050 + """
1051 + )
1052 + parser.add_argument(
1053 + '--random_brightness',
1054 + type=int,
1055 + default=0,
1056 + help="""\
1057 + A percentage determining how much to randomly multiply the training image
1058 + input pixels up or down by.\
1059 + """
1060 + )
1061 + FLAGS, unparsed = parser.parse_known_args()
1062 + tf.app.run(main=main, argv=[sys.argv[0]] + unparsed)
1 +# -*- coding: utf-8 -*-
2 +
3 +"""Inception v3 architecture 모델을 retraining한 모델을 이용해서 이미지에 대한 추론(inference)을 진행하는 예제"""
4 +
5 +import sys
6 +import numpy as np
7 +import tensorflow as tf
8 +
9 +imagePath = ''
10 +modelFullPath = ''
11 +labelsFullPath = ''
12 +
13 +if (len(sys.argv) > 1):
14 + imagePath = sys.argv[1] + '/test/test.jpg'
15 + modelFullPath = sys.argv[1] + '/test/output_graph.pb'
16 + labelsFullPath = sys.argv[1] + '/test/output_labels.txt'
17 +else:
18 + imagePath = './test/test.jpg' # 추론을 진행할 이미지 경로
19 + modelFullPath = './test/output_graph.pb' # 읽어들일 graph 파일 경로
20 + labelsFullPath = './test/output_labels.txt' # 읽어들일 labels 파일 경로
21 +
22 +
23 +def create_graph():
24 + """저장된(saved) GraphDef 파일로부터 graph를 생성하고 saver를 반환한다."""
25 + # 저장된(saved) graph_def.pb로부터 graph를 생성한다.
26 + with tf.gfile.FastGFile(modelFullPath, 'rb') as f:
27 + graph_def = tf.GraphDef()
28 + graph_def.ParseFromString(f.read())
29 + _ = tf.import_graph_def(graph_def, name='')
30 +
31 +
32 +def run_inference_on_image():
33 + answer = None
34 +
35 + if not tf.gfile.Exists(imagePath):
36 + tf.logging.fatal('File does not exist %s', imagePath)
37 + answer = 'File does not exist ' + imagePath
38 + return answer
39 +
40 + image_data = tf.gfile.FastGFile(imagePath, 'rb').read()
41 +
42 + # 저장된(saved) GraphDef 파일로부터 graph를 생성한다.
43 + create_graph()
44 +
45 + with tf.Session() as sess:
46 +
47 + softmax_tensor = sess.graph.get_tensor_by_name('final_result:0')
48 + predictions = sess.run(softmax_tensor,
49 + {'DecodeJpeg/contents:0': image_data})
50 + predictions = np.squeeze(predictions)
51 +
52 + top_k = predictions.argsort()[-5:][::-1] # 가장 높은 확률을 가진 5개(top 5)의 예측값(predictions)을 얻는다.
53 + f = open(labelsFullPath, 'rb')
54 + lines = f.readlines()
55 + labels = [str(w).replace("\n", "") for w in lines]
56 + for node_id in top_k:
57 + human_string = labels[node_id]
58 + score = predictions[node_id]
59 + print('%s (score = %.5f)' % (human_string, score))
60 +
61 + answer = labels[top_k[0]]
62 + return answer
63 +
64 +
65 +if __name__ == '__main__':
66 + run_inference_on_image()
...\ No newline at end of file ...\ No newline at end of file
1 +doctype html
2 +html
3 + head
4 + meta(charset='utf-8')
5 + title 파일 업로드
6 +
7 + style
8 + img
9 + | display="block"
10 + | max-width="200px"
11 + | max-height="200px"
12 + | width="auto"
13 + | height="auto"
14 +
15 +
16 + body
17 + - var DirectoryName=directoryName;
18 + h1=DirectoryName
19 + br
20 + h2 파일 업로드
21 + form(action="./upload/" method="POST" enctype="multipart/form-data")
22 + input(type="file", name="userImage", multiple="multiple", accept=".jpg, .jpeg")
23 + input(type="submit", value="업로드")
24 + br
25 + br
26 + ul
27 + - var ImageList=imageList
28 + - var filelist=fileList
29 + - var iter=0
30 + each Image in ImageList
31 + div(style="margin-right:10px;")
32 + img(src=Image)
33 + li=filelist[iter]
34 + - iter=iter+1
35 + br
36 + br
37 +
38 +
...\ No newline at end of file ...\ No newline at end of file
1 +script.
2 + var directoryName= !{directoryName};
3 + confirm('모든 이미지가 삭제됩니다.\n정말 ' + directoryName + ' 분류를 삭제하시겠습니까?')
4 + ? location.href ='.?real=true' : history.back();
...\ No newline at end of file ...\ No newline at end of file
1 +script.
2 + var directoryName= !{directoryName};
3 + var result = prompt('새 분류명을 입력하세요. (기존: ' + directoryName + ')');
4 +
5 + if (result) {
6 + location.href = '.?newName=' + result;
7 + } else {
8 + alert('분류명을 수정하지 않습니다.');
9 + history.back();
10 + }
...\ No newline at end of file ...\ No newline at end of file
1 +script.
2 + var msg = '이미 존재하는 분류입니다.'
3 + alert(msg);
4 + history.back();
...\ No newline at end of file ...\ No newline at end of file
1 +doctype html
2 +html
3 + head
4 + meta(charset='utf-8')
5 + title 분류 리스트
6 +
7 +
8 +
9 + body
10 + form(action="../directory_check" method="post")
11 + p 새로 만들 분류명:
12 + input(name="directoryName", type="text")
13 + input(type="submit", value="생성")
14 + br
15 + br
16 +
17 + form(action="../test" method="post" enctype="multipart/form-data")
18 + p 테스트할 이미지:
19 + input(name="TestImage", type="file", accept=".jpg, .jpeg")
20 + input(type="submit", value="테스트")
21 + br
22 + br
23 + br
24 +
25 + div(style="margin-right:10px; float:left;")
26 + form(action="../imageLearning" method="get")
27 + input(type="submit", value="이미지 학습시키기" style="font-size:24px; font-weight:bold")
28 +
29 + - var learnTime=learntime
30 + div(style="margin-right:30px;")
31 + p="(최근 학습 시간: " + learnTime + ")"
32 +
33 + br
34 +
35 + ul
36 + - var folderList=fileList
37 + each folder in folderList
38 + div(style="margin-right:30px; float:left;")
39 + li
40 + a(href="./"+folder+"/")=folder
41 +
42 + div(style="margin-right:5px; float:left;")
43 + form(action="./"+folder+"/modify/" method="get")
44 + input(type="submit", value="수정")
45 +
46 + div
47 + form(action="./"+folder+"/delete/" method="get")
48 + input(type="submit", value="삭제")
49 + br
...\ No newline at end of file ...\ No newline at end of file
1 +h1 결과
2 +
3 +ol
4 + - var Result=result
5 + for item in Result
6 + div(style="font-size:20px;")
7 + li=item
8 + div(style="font-size:10px;")
9 + br
...\ No newline at end of file ...\ No newline at end of file
...@@ -2,10 +2,533 @@ ...@@ -2,10 +2,533 @@
2 "requires": true, 2 "requires": true,
3 "lockfileVersion": 1, 3 "lockfileVersion": 1,
4 "dependencies": { 4 "dependencies": {
5 + "accepts": {
6 + "version": "1.3.7",
7 + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
8 + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
9 + "requires": {
10 + "mime-types": "~2.1.24",
11 + "negotiator": "0.6.2"
12 + }
13 + },
14 + "append-field": {
15 + "version": "1.0.0",
16 + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
17 + "integrity": "sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY="
18 + },
19 + "array-flatten": {
20 + "version": "1.1.1",
21 + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
22 + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
23 + },
24 + "body-parser": {
25 + "version": "1.19.0",
26 + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
27 + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
28 + "requires": {
29 + "bytes": "3.1.0",
30 + "content-type": "~1.0.4",
31 + "debug": "2.6.9",
32 + "depd": "~1.1.2",
33 + "http-errors": "1.7.2",
34 + "iconv-lite": "0.4.24",
35 + "on-finished": "~2.3.0",
36 + "qs": "6.7.0",
37 + "raw-body": "2.4.0",
38 + "type-is": "~1.6.17"
39 + }
40 + },
41 + "buffer-from": {
42 + "version": "1.1.1",
43 + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
44 + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
45 + },
46 + "busboy": {
47 + "version": "0.2.14",
48 + "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz",
49 + "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=",
50 + "requires": {
51 + "dicer": "0.2.5",
52 + "readable-stream": "1.1.x"
53 + }
54 + },
55 + "bytes": {
56 + "version": "3.1.0",
57 + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
58 + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
59 + },
60 + "concat-stream": {
61 + "version": "1.6.2",
62 + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
63 + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
64 + "requires": {
65 + "buffer-from": "^1.0.0",
66 + "inherits": "^2.0.3",
67 + "readable-stream": "^2.2.2",
68 + "typedarray": "^0.0.6"
69 + },
70 + "dependencies": {
71 + "isarray": {
72 + "version": "1.0.0",
73 + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
74 + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
75 + },
76 + "readable-stream": {
77 + "version": "2.3.7",
78 + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
79 + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
80 + "requires": {
81 + "core-util-is": "~1.0.0",
82 + "inherits": "~2.0.3",
83 + "isarray": "~1.0.0",
84 + "process-nextick-args": "~2.0.0",
85 + "safe-buffer": "~5.1.1",
86 + "string_decoder": "~1.1.1",
87 + "util-deprecate": "~1.0.1"
88 + }
89 + },
90 + "string_decoder": {
91 + "version": "1.1.1",
92 + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
93 + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
94 + "requires": {
95 + "safe-buffer": "~5.1.0"
96 + }
97 + }
98 + }
99 + },
100 + "content-disposition": {
101 + "version": "0.5.3",
102 + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
103 + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
104 + "requires": {
105 + "safe-buffer": "5.1.2"
106 + }
107 + },
108 + "content-type": {
109 + "version": "1.0.4",
110 + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
111 + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
112 + },
113 + "cookie": {
114 + "version": "0.4.0",
115 + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
116 + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
117 + },
118 + "cookie-signature": {
119 + "version": "1.0.6",
120 + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
121 + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
122 + },
123 + "core-util-is": {
124 + "version": "1.0.2",
125 + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
126 + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
127 + },
128 + "debug": {
129 + "version": "2.6.9",
130 + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
131 + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
132 + "requires": {
133 + "ms": "2.0.0"
134 + }
135 + },
136 + "depd": {
137 + "version": "1.1.2",
138 + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
139 + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
140 + },
141 + "destroy": {
142 + "version": "1.0.4",
143 + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
144 + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
145 + },
146 + "dicer": {
147 + "version": "0.2.5",
148 + "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz",
149 + "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=",
150 + "requires": {
151 + "readable-stream": "1.1.x",
152 + "streamsearch": "0.1.2"
153 + }
154 + },
155 + "ee-first": {
156 + "version": "1.1.1",
157 + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
158 + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
159 + },
160 + "encodeurl": {
161 + "version": "1.0.2",
162 + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
163 + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
164 + },
165 + "escape-html": {
166 + "version": "1.0.3",
167 + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
168 + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
169 + },
170 + "etag": {
171 + "version": "1.8.1",
172 + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
173 + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
174 + },
175 + "express": {
176 + "version": "4.17.1",
177 + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
178 + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
179 + "requires": {
180 + "accepts": "~1.3.7",
181 + "array-flatten": "1.1.1",
182 + "body-parser": "1.19.0",
183 + "content-disposition": "0.5.3",
184 + "content-type": "~1.0.4",
185 + "cookie": "0.4.0",
186 + "cookie-signature": "1.0.6",
187 + "debug": "2.6.9",
188 + "depd": "~1.1.2",
189 + "encodeurl": "~1.0.2",
190 + "escape-html": "~1.0.3",
191 + "etag": "~1.8.1",
192 + "finalhandler": "~1.1.2",
193 + "fresh": "0.5.2",
194 + "merge-descriptors": "1.0.1",
195 + "methods": "~1.1.2",
196 + "on-finished": "~2.3.0",
197 + "parseurl": "~1.3.3",
198 + "path-to-regexp": "0.1.7",
199 + "proxy-addr": "~2.0.5",
200 + "qs": "6.7.0",
201 + "range-parser": "~1.2.1",
202 + "safe-buffer": "5.1.2",
203 + "send": "0.17.1",
204 + "serve-static": "1.14.1",
205 + "setprototypeof": "1.1.1",
206 + "statuses": "~1.5.0",
207 + "type-is": "~1.6.18",
208 + "utils-merge": "1.0.1",
209 + "vary": "~1.1.2"
210 + }
211 + },
212 + "finalhandler": {
213 + "version": "1.1.2",
214 + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
215 + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
216 + "requires": {
217 + "debug": "2.6.9",
218 + "encodeurl": "~1.0.2",
219 + "escape-html": "~1.0.3",
220 + "on-finished": "~2.3.0",
221 + "parseurl": "~1.3.3",
222 + "statuses": "~1.5.0",
223 + "unpipe": "~1.0.0"
224 + }
225 + },
226 + "forwarded": {
227 + "version": "0.1.2",
228 + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
229 + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
230 + },
231 + "fresh": {
232 + "version": "0.5.2",
233 + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
234 + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
235 + },
236 + "http-errors": {
237 + "version": "1.7.2",
238 + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
239 + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
240 + "requires": {
241 + "depd": "~1.1.2",
242 + "inherits": "2.0.3",
243 + "setprototypeof": "1.1.1",
244 + "statuses": ">= 1.5.0 < 2",
245 + "toidentifier": "1.0.0"
246 + }
247 + },
248 + "iconv-lite": {
249 + "version": "0.4.24",
250 + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
251 + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
252 + "requires": {
253 + "safer-buffer": ">= 2.1.2 < 3"
254 + }
255 + },
256 + "inherits": {
257 + "version": "2.0.3",
258 + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
259 + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
260 + },
261 + "ipaddr.js": {
262 + "version": "1.9.1",
263 + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
264 + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
265 + },
266 + "isarray": {
267 + "version": "0.0.1",
268 + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
269 + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
270 + },
271 + "media-typer": {
272 + "version": "0.3.0",
273 + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
274 + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
275 + },
276 + "merge-descriptors": {
277 + "version": "1.0.1",
278 + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
279 + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
280 + },
281 + "methods": {
282 + "version": "1.1.2",
283 + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
284 + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
285 + },
286 + "mime": {
287 + "version": "1.6.0",
288 + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
289 + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
290 + },
291 + "mime-db": {
292 + "version": "1.44.0",
293 + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
294 + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg=="
295 + },
296 + "mime-types": {
297 + "version": "2.1.27",
298 + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
299 + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
300 + "requires": {
301 + "mime-db": "1.44.0"
302 + }
303 + },
304 + "minimist": {
305 + "version": "1.2.5",
306 + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
307 + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
308 + },
309 + "mkdirp": {
310 + "version": "0.5.5",
311 + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
312 + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
313 + "requires": {
314 + "minimist": "^1.2.5"
315 + }
316 + },
5 "moment": { 317 "moment": {
6 "version": "2.26.0", 318 "version": "2.26.0",
7 "resolved": "https://registry.npmjs.org/moment/-/moment-2.26.0.tgz", 319 "resolved": "https://registry.npmjs.org/moment/-/moment-2.26.0.tgz",
8 "integrity": "sha512-oIixUO+OamkUkwjhAVE18rAMfRJNsNe/Stid/gwHSOfHrOtw9EhAY2AHvdKZ/k/MggcYELFCJz/Sn2pL8b8JMw==" 320 "integrity": "sha512-oIixUO+OamkUkwjhAVE18rAMfRJNsNe/Stid/gwHSOfHrOtw9EhAY2AHvdKZ/k/MggcYELFCJz/Sn2pL8b8JMw=="
321 + },
322 + "ms": {
323 + "version": "2.0.0",
324 + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
325 + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
326 + },
327 + "multer": {
328 + "version": "1.4.2",
329 + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.2.tgz",
330 + "integrity": "sha512-xY8pX7V+ybyUpbYMxtjM9KAiD9ixtg5/JkeKUTD6xilfDv0vzzOFcCp4Ljb1UU3tSOM3VTZtKo63OmzOrGi3Cg==",
331 + "requires": {
332 + "append-field": "^1.0.0",
333 + "busboy": "^0.2.11",
334 + "concat-stream": "^1.5.2",
335 + "mkdirp": "^0.5.1",
336 + "object-assign": "^4.1.1",
337 + "on-finished": "^2.3.0",
338 + "type-is": "^1.6.4",
339 + "xtend": "^4.0.0"
340 + }
341 + },
342 + "negotiator": {
343 + "version": "0.6.2",
344 + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
345 + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
346 + },
347 + "object-assign": {
348 + "version": "4.1.1",
349 + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
350 + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
351 + },
352 + "on-finished": {
353 + "version": "2.3.0",
354 + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
355 + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
356 + "requires": {
357 + "ee-first": "1.1.1"
358 + }
359 + },
360 + "parseurl": {
361 + "version": "1.3.3",
362 + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
363 + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
364 + },
365 + "path-to-regexp": {
366 + "version": "0.1.7",
367 + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
368 + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
369 + },
370 + "process-nextick-args": {
371 + "version": "2.0.1",
372 + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
373 + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
374 + },
375 + "proxy-addr": {
376 + "version": "2.0.6",
377 + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
378 + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==",
379 + "requires": {
380 + "forwarded": "~0.1.2",
381 + "ipaddr.js": "1.9.1"
382 + }
383 + },
384 + "python-shell": {
385 + "version": "2.0.1",
386 + "resolved": "https://registry.npmjs.org/python-shell/-/python-shell-2.0.1.tgz",
387 + "integrity": "sha512-Ys+SiCinY9JrldIJxGWd2AMQSQZLU7PFzrCWY7HTawZ73tIthFdlLLU1Y6Y40Hwdutc+TmfMe5TXNU73s07Xyg=="
388 + },
389 + "qs": {
390 + "version": "6.7.0",
391 + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
392 + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
393 + },
394 + "range-parser": {
395 + "version": "1.2.1",
396 + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
397 + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
398 + },
399 + "raw-body": {
400 + "version": "2.4.0",
401 + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
402 + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
403 + "requires": {
404 + "bytes": "3.1.0",
405 + "http-errors": "1.7.2",
406 + "iconv-lite": "0.4.24",
407 + "unpipe": "1.0.0"
408 + }
409 + },
410 + "readable-stream": {
411 + "version": "1.1.14",
412 + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
413 + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
414 + "requires": {
415 + "core-util-is": "~1.0.0",
416 + "inherits": "~2.0.1",
417 + "isarray": "0.0.1",
418 + "string_decoder": "~0.10.x"
419 + }
420 + },
421 + "safe-buffer": {
422 + "version": "5.1.2",
423 + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
424 + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
425 + },
426 + "safer-buffer": {
427 + "version": "2.1.2",
428 + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
429 + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
430 + },
431 + "send": {
432 + "version": "0.17.1",
433 + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
434 + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
435 + "requires": {
436 + "debug": "2.6.9",
437 + "depd": "~1.1.2",
438 + "destroy": "~1.0.4",
439 + "encodeurl": "~1.0.2",
440 + "escape-html": "~1.0.3",
441 + "etag": "~1.8.1",
442 + "fresh": "0.5.2",
443 + "http-errors": "~1.7.2",
444 + "mime": "1.6.0",
445 + "ms": "2.1.1",
446 + "on-finished": "~2.3.0",
447 + "range-parser": "~1.2.1",
448 + "statuses": "~1.5.0"
449 + },
450 + "dependencies": {
451 + "ms": {
452 + "version": "2.1.1",
453 + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
454 + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
455 + }
456 + }
457 + },
458 + "serve-static": {
459 + "version": "1.14.1",
460 + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
461 + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
462 + "requires": {
463 + "encodeurl": "~1.0.2",
464 + "escape-html": "~1.0.3",
465 + "parseurl": "~1.3.3",
466 + "send": "0.17.1"
467 + }
468 + },
469 + "setprototypeof": {
470 + "version": "1.1.1",
471 + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
472 + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
473 + },
474 + "statuses": {
475 + "version": "1.5.0",
476 + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
477 + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
478 + },
479 + "streamsearch": {
480 + "version": "0.1.2",
481 + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
482 + "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
483 + },
484 + "string_decoder": {
485 + "version": "0.10.31",
486 + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
487 + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
488 + },
489 + "toidentifier": {
490 + "version": "1.0.0",
491 + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
492 + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
493 + },
494 + "type-is": {
495 + "version": "1.6.18",
496 + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
497 + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
498 + "requires": {
499 + "media-typer": "0.3.0",
500 + "mime-types": "~2.1.24"
501 + }
502 + },
503 + "typedarray": {
504 + "version": "0.0.6",
505 + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
506 + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
507 + },
508 + "unpipe": {
509 + "version": "1.0.0",
510 + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
511 + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
512 + },
513 + "util-deprecate": {
514 + "version": "1.0.2",
515 + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
516 + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
517 + },
518 + "utils-merge": {
519 + "version": "1.0.1",
520 + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
521 + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
522 + },
523 + "vary": {
524 + "version": "1.1.2",
525 + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
526 + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
527 + },
528 + "xtend": {
529 + "version": "4.0.2",
530 + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
531 + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
9 } 532 }
10 } 533 }
11 } 534 }
......