mdj1412
Code Refactoring: Removing duplicated code and optimizing performance.
a9c229f
/*
[ jQuery ]
์›น์‚ฌ์ดํŠธ์— ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‰ฝ๊ฒŒ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” ์˜คํ”ˆ์†Œ์Šค ๊ธฐ๋ฐ˜์˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
[ ์ตœ๊ทผ Trends + ๋น„์Šทํ•œ ์ข…๋ฅ˜ ]
1. Lodash
2. Moment
3. jQuery
4. date-fns
5. RxJS
*/
/*
".ready()"๋Š” DOM(Document Object Model)์ด ์™„์ „ํžˆ ๋ถˆ๋Ÿฌ์™€์ง€๋ฉด ์‹คํ–‰๋˜๋Š” Event ์ด๋‹ค.
์ผ๋ฐ˜์ ์œผ๋กœ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ HTML์„ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด์„œ๋Š”
๋จผ์ € ๋ฌธ์„œ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค๊ณ  ๋งŒ๋“ค์–ด์ง„ ๋ฌธ์„œ ๊ตฌ์กฐ ์œ„์— ๋””์ž์ธ์„ ์ž…ํžˆ๋Š” ํ˜•์‹์„ ์ทจํ•œ๋‹ค.
์ด ๊ณผ์ •์—์„œ ๋””์ž์ธ์ด ์ž…ํ˜€์ง€์ง€ ์•Š์€ ์ƒํƒœ๋กœ ๋ฌธ์„œ ๊ตฌ์กฐ๊ฐ€ ๋งŒ๋“ค์–ด์ง„ ์‹œ์ ์— ์‹œํ–‰๋˜๋Š” Event๊ฐ€ ".ready()" ์ด๋‹ค.
jQuery 3.0 ๋ฒ„์ „ ์ดํ›„๋ถ€ํ„ฐ๋Š” "$(handler)" ๊ตฌ๋ฌธ๋งŒ ๊ถŒ์žฅ
".read()" Event๋Š” 1.8 ๋ฒ„์ „์—์„œ๋Š” deprecated ๋˜์—ˆ์œผ๋ฉฐ 3.0์—์„œ๋Š” ์ง€์›ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ
( ๊ทผ๋ฐ ์—ฌ๊ธฐ์„œ๋Š” ์‹คํ–‰ ๋ฌธ์ œ ์ž˜๋จ )
*/
// $(document).ready(function() { });
$(function() {
var nasdaq_table_container_element = document.getElementById("nasdaq-table-container");
var chart_container_element = document.getElementById("chart-container");
var news_container_element = document.getElementById("news-container");
console.log(nasdaq_table_container_element, chart_container_element, news_container_element);
// nasdaq_table_container_element.style.display = "block";
// chart_container_element.style.display = "none";
// news_container_element.style.display = "none";
// $("#news-container").hide();
// $("#news-container").show();
nasdaq_table_init();
});
/**
*
*
*
*
*/
function nasdaq_table_init() {
// HTML ์ˆ˜์ •
$("#chart-container").hide();
$("#news-container").hide();
// Javascript -> Flask (Python) -> Javascript
output = sendAjax_sync("/stocks", {}, "json", handle_one_return);
// console.log("stocksInit() Output : ", output);
// console.log(typeof output);
// Ticker ๊ธธ์ด ํ™•์ธํ•ด๋ณด๊ธฐ
var object_length = Object.keys(output.ticker).length;
// console.log(object_length);
// ๋žœ๋”๋ง HTML ์š”์†Œ ์ƒ์„ฑ
stocks = document.querySelector('.stocks');
stocks.innerHTML = '';
// "HTML"์— ์š”์†Œ ์ถ”๊ฐ€
for (var i = 0; i < object_length; i++) {
stocks.innerHTML = stocks.innerHTML + '<div class="stock ticker"></div>';
stocks.innerHTML = stocks.innerHTML + '<div class="stock name">' + output.name[i] + '</div>';
if (output.diff[i] > 0) {
stocks.innerHTML = stocks.innerHTML + '<div class="stock diff up">' + '+' + output.diff[i] + ' %' + '</div>';
}
else { stocks.innerHTML = stocks.innerHTML + '<div class="stock diff down">' + output.diff[i] + ' %' + '</div>'; }
stocks.innerHTML = stocks.innerHTML + '<div class="stock open">' + output.open[i] + '</div>';
stocks.innerHTML = stocks.innerHTML + '<div class="stock close">' + output.close[i] + '</div>';
stocks.innerHTML = stocks.innerHTML + '<div class="stock sector">' + output.sector[i] + '</div>';
stocks.innerHTML = stocks.innerHTML + '<div class="stock industry">' + output.industry[i] + '</div>';
// Add ticker's chart link
execution_function = `javascript:chartInit('${ output.ticker[i] }')`;
stock = document.querySelectorAll('.stock.ticker')[i];
stock.innerHTML = '';
stock.innerHTML = stock.innerHTML + `<a href=${ execution_function }>${ output.ticker[i] }</a>`;
}
}
/**
*
*
*
*
*
*
*
*
*/
function chartInit(ticker, already=false) {
// HTML ์ˆ˜์ •
$("#nasdaq-table-container").hide();
$("#chart-container").show();
$("#news-container").hide();
// ticker ์ด๋ฆ„ ์„ค์ • (๋ถ€์ œ๋ชฉ ์„ค์ •)
$('#chart-container .goticker .tickerName').text(ticker.concat(' Chart'));
// Javascript -> Flask (Python) -> Javascript
let [chart_data, news_articles] = sendAjax_sync_about_chartData_and_newsArticles("/chart", {"ticker": ticker}, "json", handle_two_return);
if (!already) {
// x์ถ•๊ณผ data ์„ค์ •
// data: [{'x': date, 'o': open, 'h': high, 'l': low, 'c': close}, { }, { }, ... ]
data = [];
key_list = Object.keys(chart_data.Close);
for (var i=key_list.length-15; i<key_list.length; i++) {
key = key_list[i];
const [year, month, day] = key.split("-");
const x = new Date(parseInt(year), parseInt(month), parseInt(day), 9, 0, 0, 0).getTime();
data.push({'x': x, 'o': chart_data.Open[key].toFixed(2), 'h': chart_data.High[key].toFixed(2), 'l': chart_data.Low[key].toFixed(2), 'c': chart_data.Close[key].toFixed(2)})
}
// Javascript chart.js candlestick
let mychart = document.getElementById('myChart');
new Chart(mychart, {
type: 'candlestick',
data: {
datasets: [{
label: 'CHRT - '.concat(ticker),
data: data
}]
}
});
}
//////////////////////////////////////////////////////////////////
// Javascript๋ฅผ ์ด์šฉํ•ด HTML์— ๋™์ ์œผ๋กœ ํƒœ๊ทธ ์ถ”๊ฐ€
// a ํƒœ๊ทธ onclick ์ ์šฉ
var execution_function = `javascript:chartInit('${ticker}', true)`;
const goTicker = document.querySelector('#chart-container .goticker');
goTicker.setAttribute('href', execution_function);
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
// table title ํ‘œ์‹œ
// ํ•ด๋‹น class์˜ text ์ง‘์–ด๋„ฃ๊ธฐ
const table_title = document.querySelector('.table-title');
$('.table .table-title').text(ticker.concat(' News'));
news_table = document.querySelector('.table .news-table');
// console.log(news_table.innerHTML);
// console.log(news);
// console.log(Object.keys(news)); // key ๋ฐฐ์—ด ๋งŒ๋“ค๊ธฐ
// console.log(typeof Object.keys(news));
/*
[ ๋‚ ์งœ ์ •๋ ฌ ]
"news"์—์„œ index์— ๋Œ€ํ•ด์„œ ์ •๋ ฌ์„ ํ•˜๊ณ  reduce() ํ•จ์ˆ˜๋ฅผ ์ ์šฉ.
reduce() : ๋ฐฐ์—ด์˜ ๊ฐ ์š”์†Œ์— ๋Œ€ํ•ด ์ฃผ์–ด์ง„ reducer ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๊ณ , ํ•˜๋‚˜์˜ ๊ฒฐ๊ณผ๊ฐ’์„ ๋ฐ˜ํ™˜
*/
sorted_news = {}
sorted_news = Object.keys(news_articles).sort(function (a, b) {
if (a < b) { return 1; }
else if (a > b) { return -1; }
else { return 0; }
}).reduce((sorted_news, key) => {
sorted_news[key] = news_articles[key];
return sorted_news;
}, {});
// console.log(sorted_news);
var key_list = Object.keys(chart_data.Open);
var open_list = Object.values(chart_data.Open);
var close_list = Object.values(chart_data.Close);
for (var i=0; i<key_list.length; i++) {
const [year, month, day] = key_list[i].split("-");
key_list[i] = year + '.' + month + '.' + day;
}
// console.log(key_list);
var link_list_idx = 0;
// List ์•ˆ์˜ value๋ฅผ ๋ฝ‘์„ ๋•Œ, (Python) => for item in list:
Object.keys(sorted_news).forEach(key => {
var date_idx_in_key_list = key_list.indexOf(String(key));
// console.log(key, key_list, date_idx_in_key_list);
if (date_idx_in_key_list != -1) {
var diff = ((open_list[date_idx_in_key_list]-close_list[date_idx_in_key_list-1])/(open_list[date_idx_in_key_list]) * 100.0).toFixed(2);
}
else { var diff = 0; }
if (diff == 0) {
var diff_html = '<th class="news diff">0.0 %</th>';
}
else if (diff > 0) {
var diff_html = '<th class="news diff up">+' + diff + ' %</th>';
}
else {
var diff_html = '<th class="news diff down">' + diff + ' %</th>';
}
var html = `<tr align="center" bgcolor="white"><th>+</th><th>${ key }</th>${ diff_html }<td style="text-align: left;">`;
for (var i = 0; i < sorted_news[key].length; i++) {
var title = sorted_news[key][i].substring(0, sorted_news[key][i].length-4);
var sendTitle = title; // Javascript -> Python ๋ณด๋‚ด๊ธฐ ์œ„ํ•œ title
// title์—์„œ & ํ‘œ์‹œ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Œ.
// Title ์—์„œ '&'๋กœ ํ‘œ์‹œ๋˜์–ด ์žˆ๋Š”๋ฐ ๋”ฐ๋กœ ๊ตฌ๋ณ„ํ•ด์•ผ ๋œ๋‹ค.
// andSymbolInTitle ์—์„œ ๊ฐ€์ ธ์˜จ '&' ์œ„์น˜ index๋ฅผ title๊ณผ ํ•ฉ์ณ์ค€๋‹ค.
andSymbolInTitle = [];
let idx = 0;
// title = "asdf&asdf&AS&DF&&";
// sendTitle = title;
while (true) {
idx = sendTitle.indexOf('&', idx);
if (idx == -1) { break; }
sendTitle = sendTitle.substring(0, idx) + sendTitle.substring(idx+1, sendTitle.length);
// console.log(sendTitle);
andSymbolInTitle.push(idx + andSymbolInTitle.length);
}
var link = String(`/info_and_newsNER?ticker=${ ticker }&date=${ key }&title=${ sendTitle }&andSymbolInTitle=${ andSymbolInTitle }`);
linkList.push(link);
var execution_function = String(`javascript:getData(linkList[${ link_list_idx }], ${ diff });`);
html = html + `<a href="${ execution_function }">${ title }</a><br>`;
link_list_idx = link_list_idx + 1;
}
html = html + '</td>';
news_table.innerHTML = news_table.innerHTML + html;
});
}
linkList = [];
async function getData(link, diff) {
try {
console.log("link : ", link);
await $.getJSON(link, function(data)
{
// console.log("ticker : ", data.ticker);
// console.log("date : ", data.date);
// console.log("title : ", data.title);
// console.log("url : ", data.url);
// console.log("ents : ", data.ents);
console.log("diff : ", diff);
newsInit(data.ticker, data.date, data.title, data.url, data.ents, diff);
});
} catch (error) {
console.log("Error : ", error);
}
}
/**
*
*
*
*
*
*
*
*
*
*
*/
function newsInit(ticker, date, title, url, ents, diff) {
// HTML ์ˆ˜์ •
$("#nasdaq-table-container").hide();
$("#chart-container").hide();
$("#news-container").show();
// console.log(ticker);
// console.log(date);
// console.log(title);
//////////////////////////////////////////////////////////////////////
// Javascript๋ฅผ ์ด์šฉํ•ด HTML์— ๋™์ ์œผ๋กœ ํƒœ๊ทธ ์ถ”๊ฐ€
document.querySelector('#news-container .goticker .tickerName').textContent = ticker + " Chart";
document.querySelector('#news-container .titleDate').textContent = "Date : " + date;
document.querySelector('#news-container .titleName').textContent = "Article : " + title;
document.querySelector('#news-container .newsURL .input-News-URL').textContent = "URL : " + url;
// a ํƒœ๊ทธ onclick ์ ์šฉ
var execution_function = `javascript:chartInit('${ ticker }', true)`;
const goTicker = document.querySelector('#news-container .goticker');
goTicker.setAttribute('href', execution_function);
// a ํƒœ๊ทธ์— URL ์ ์šฉ
const addURL = document.querySelector('.newsURL .input-News-URL');
addURL.setAttribute('href', url);
// ๋ชจ๋ธ์—์„œ ์งˆ๋ฌธ ์˜ˆ์‹œ Ticker์— ์•Œ๋งž๊ฒŒ ์ž‘์„ฑํ•˜๊ธฐ
const model_input_example = document.querySelector('#model .text-form #text-input');
if (diff == 0) { example = "What is your outlook for the future direction of this stock?" }
else if (diff > 0) { example = "Why did " + ticker + "'s stock go up?"; }
else if (diff < 0) { example = "Why did " + ticker + "'s stock go down?"; }
else { throw new Error('Error : diff Error '); }
model_input_example.setAttribute('value', example);
//////////////////////////////////////////////////////////////////////
// NER ๊ด€๋ จ
console.log(ents);
let news = ents['news'];
let numOfNER = ents['text'].length;
// console.log("total news : ", news);
// ๋žœ๋”๋ง html ์š”์†Œ ์ƒ์„ฑ
news_ner = document.querySelector('.entities');
news_ner.innerHTML = '';
for (i=0; i<numOfNER; i++) {
start_idx = (i == 0) ? 0 : ents['end_char'][i-1];
end_idx = ents['start_char'][i];
last_idx = ents['end_char'][i];
label = ents['label_'][i];
if (label == 'ORG') { class_name = "entity_org"; }
else if (label == 'PERSON') { class_name = "entity_person"; }
else if (label == 'FAC') { class_name = "entity_fac"; }
else if (label == 'GPE') { class_name = "entity_gpe"; }
else if (label == 'PRODUCT') { class_name = "entity_product"; }
else { console.log("[ Error !!! - New NER label_ ] : ", ents['label_'][i], ents['text'][i]); class_name = "none"; }
add_html = news.substring(start_idx, end_idx);
add_html = add_html + '<mark class=' + class_name
+ ' style="line-height: 1;">'
+ news.substring(end_idx, last_idx)
+ '<span class="show-label" style="font-size: 0.8em; font-weight: bold; line-height: 1; border-radius: 0.35em; vertical-align: middle; margin-left: 0.5rem">'
+ label + '</span></mark>';
// console.log(add_html);
news_ner.innerHTML = news_ner.innerHTML + add_html;
}
// console.log("last html : ", news.substring(ents['end_char'][numOfNER-1]));
news_ner.innerHTML = news_ner.innerHTML + news.substring(ents['end_char'][numOfNER-1]);
//////////////////////////////////////////////////////////////////////
// ๋ชจ๋ธ ์ ์šฉ ๋‚ด์šฉ ( Submit )
var sendTitle = title; // Javascript -> Python ๋ณด๋‚ด๊ธฐ ์œ„ํ•œ title
// title์—์„œ & ํ‘œ์‹œ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Œ.
// Title ์—์„œ '&'๋กœ ํ‘œ์‹œ๋˜์–ด ์žˆ๋Š”๋ฐ ๋”ฐ๋กœ ๊ตฌ๋ณ„ํ•ด์•ผ ๋œ๋‹ค.
// andSymbolInTitle ์—์„œ ๊ฐ€์ ธ์˜จ '&' ์œ„์น˜ index๋ฅผ title๊ณผ ํ•ฉ์ณ์ค€๋‹ค.
andSymbolInTitle = [];
let idx = 0;
// title = "asdf&asdf&AS&DF&&";
// sendTitle = title;
while (true) {
idx = sendTitle.indexOf('&', idx);
if (idx == -1) { break; }
sendTitle = sendTitle.substring(0, idx) + sendTitle.substring(idx+1, sendTitle.length);
// console.log(sendTitle);
andSymbolInTitle.push(idx + andSymbolInTitle.length);
}
// console.log(andSymbolInTitle);
// console.log("Last String", sendTitle);
// function ์•ž์— "async"๋ฅผ ๋ถ™์ด๋ฉด ํ•ด๋‹น ํ•จ์ˆ˜๋Š” ํ•ญ์ƒ ํ”„๋ผ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
const translateText = async (text) => {
// ๋ชฉ์  : Flask์— input์„ ๋ณด๋‚ด์ฃผ๊ณ  output์„ ๋ฐ›์•„์˜ค๋Š” ๊ณผ์ •
console.log("Start translateText async");
// "await"๋Š” "async" ํ•จ์ˆ˜ ์•ˆ์—์„œ๋งŒ ๋™์ž‘ํ•œ๋‹ค.
// "await" ํ‚ค์›Œ๋“œ๋ฅผ ๋งŒ๋‚˜๋ฉด Promise๊ฐ€ ์ฒ˜๋ฆฌ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.
// Promise๊ฐ€ ์ฒ˜๋ฆฌ๋˜๊ธธ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋™์•ˆ์—” ์—”์ง„์ด ๋‹ค๋ฅธ์ผ(๋‹ค๋ฅธ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰, ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๋“ฑ)์„ ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, CPU ๋ฆฌ์†Œ์Šค๊ฐ€ ๋‚ญ๋น„๋˜์ง€ ์•Š๋Š”๋‹ค.
const inferResponse = await fetch(`newsQuestions?ticker=${ ticker }&date=${ date }&title=${ sendTitle }&andSymbolInTitle=${ andSymbolInTitle }&questions=${ text }`); // Javascript -> Flask(python)
// console.log("inferResponse : ", inferResponse);
const inferJson = await inferResponse.json(); // Flask(python) -> Javascript
// console.log(inferJson);
return inferJson.result['answer'];
};
/* ๋ชจ๋ธ Submit button ๊ด€๋ จ ๋‚ด์šฉ */
// form ํƒœ๊ทธ์˜ class ์ด๋ฆ„
const textForm = document.querySelector('.text-form');
// addEventListener(type, listener)
// addEventListener(type, listener, options)
// addEventListener(type, listener, useCapture)
textForm.addEventListener('submit', async (event) => {
event.preventDefault();
// console.log(event);
// html -> javascript : input ๋ฐ›์•„์™€์„œ output ๋ณด๋‚ด๊ธฐ
const textInput = document.getElementById('text-input');
const textParagraph = document.querySelector('.text-output');
console.log("textInput : ", textInput, textInput.value);
try {
// sendAjax("/inference", {"input_text" : textInput.value}, handleOutput);
// "await"๋Š” "async" ํ•จ์ˆ˜ ์•ˆ์—์„œ๋งŒ ๋™์ž‘ํ•œ๋‹ค.
// "await" ํ‚ค์›Œ๋“œ๋ฅผ ๋งŒ๋‚˜๋ฉด Promise๊ฐ€ ์ฒ˜๋ฆฌ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.
// Promise๊ฐ€ ์ฒ˜๋ฆฌ๋˜๊ธธ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋™์•ˆ์—” ์—”์ง„์ด ๋‹ค๋ฅธ์ผ(๋‹ค๋ฅธ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰, ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๋“ฑ)์„ ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, CPU ๋ฆฌ์†Œ์Šค๊ฐ€ ๋‚ญ๋น„๋˜์ง€ ์•Š๋Š”๋‹ค.
const answer = await translateText(textInput.value); // Flask์— input์„ ๋ณด๋‚ด์ฃผ๊ณ  output์„ ๋ฐ›์•„์˜ค๋Š” ๊ณผ์ •
console.log("Result : ", answer);
textParagraph.textContent = answer;
} catch (err) {
console.error(err);
}
});
}