Spaces:
Runtime error
Runtime error
mdj1412
commited on
Commit
·
8d21d0b
1
Parent(s):
b476907
중간 수정(미완성)
Browse files- app.py +18 -61
- static/css/news.css +10 -1
- static/js/cal.js +114 -0
- static/js/chartIndex.js +3 -80
- static/js/index.js +354 -138
- static/js/news.js +3 -75
- static/js/utils.js +89 -0
- templates/chart.html +1 -49
- templates/index.html +164 -21
- templates/news_analysis.html +0 -88
app.py
CHANGED
@@ -29,38 +29,12 @@ demo_dic = get_list()
|
|
29 |
##### Home #####
|
30 |
@app.route('/')
|
31 |
def home_page():
|
32 |
-
|
33 |
-
return render_template('index.html', embed=
|
34 |
|
35 |
|
36 |
|
37 |
##### Data fetch #####
|
38 |
-
@app.route('/submit', methods=['GET', 'POST'])
|
39 |
-
def submit():
|
40 |
-
input_text = request.args.get('input_text')
|
41 |
-
return jsonify(result={"output":"My output is a summary of: "+input_text})
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
@app.route('/model', methods=['GET', 'POST'])
|
47 |
-
def model():
|
48 |
-
print("\t\t Start model !!!")
|
49 |
-
|
50 |
-
# Javascript 에서 받은 메시지
|
51 |
-
text_input = request.args.get('text_input')
|
52 |
-
|
53 |
-
print(f"Fetch from Javascript /inference, text_input : {text_input}")
|
54 |
-
|
55 |
-
# modules/reference.py 에서 모델 적용
|
56 |
-
output = Tk_instruct(text_input)
|
57 |
-
|
58 |
-
text_output = {"text_output": output}
|
59 |
-
print(f"Fetch from Javascript /inference, text_output : {text_output}")
|
60 |
-
return jsonify(result=text_output)
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
|
65 |
# Show Ticker's Table
|
66 |
@app.route('/stocks', methods=['GET', 'POST'])
|
@@ -72,10 +46,6 @@ def stocks():
|
|
72 |
|
73 |
|
74 |
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
################################################################################################
|
80 |
|
81 |
|
@@ -86,12 +56,12 @@ ticker_dic = dict.fromkeys(demo_dic.ticker, []) # ticker1: [{날짜1: [제목1,
|
|
86 |
|
87 |
dir = './news'
|
88 |
if not os.path.exists(dir):
|
89 |
-
raise NotImplementedError("Not exists News Data")# 오류 강제 발생
|
90 |
|
91 |
# News Data List 가져오기
|
92 |
for key in os.listdir(dir):
|
93 |
if key not in ticker_dic.keys():
|
94 |
-
raise NotImplementedError("Not exists Ticker")# 오류 강제 발생
|
95 |
|
96 |
dir2 = os.path.join(dir, key)
|
97 |
ticker_dic[key] = dict.fromkeys(os.listdir(dir2), []) # 날짜1: [제목1, 제목2, ...]
|
@@ -107,17 +77,6 @@ for key in os.listdir(dir):
|
|
107 |
ticker_dic[key].pop(date)
|
108 |
|
109 |
|
110 |
-
# from IPython import embed; embed()
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
# Show Ticker's Title
|
115 |
-
@app.route('/<ticker>', methods=['GET', 'POST'])
|
116 |
-
def ticker(ticker):
|
117 |
-
example_embed = "%s Chart" % (ticker)
|
118 |
-
|
119 |
-
return render_template('chart.html', embed=example_embed)
|
120 |
-
|
121 |
|
122 |
# Show Ticker's Data
|
123 |
@app.route('/chart', methods=['GET', 'POST'])
|
@@ -133,32 +92,28 @@ def chart():
|
|
133 |
# 날짜 형식 바꾸기
|
134 |
chart_data.index = [k.strftime("%Y-%m-%d") for k in chart_data.index]
|
135 |
|
136 |
-
|
137 |
-
return jsonify(result=result)
|
138 |
-
|
139 |
|
140 |
-
@app.route('/news', methods=['GET', 'POST'])
|
141 |
-
def news():
|
142 |
-
print("Start /news ")
|
143 |
|
144 |
-
|
145 |
-
ticker = request.args.get('ticker')
|
146 |
|
147 |
news_dir = os.path.join('./news', ticker)
|
148 |
|
149 |
# 해당 Ticker의 날짜별 뉴스 제목을 가져온다.
|
150 |
-
|
151 |
for key in os.listdir(news_dir):
|
152 |
title_list = os.listdir(os.path.join(news_dir, key))
|
153 |
if len(title_list) != 0:
|
154 |
-
|
155 |
|
156 |
# 최근 뉴스부터 보이게 (정렬)
|
157 |
-
|
158 |
-
for key, value in sorted(
|
159 |
-
|
|
|
|
|
|
|
160 |
|
161 |
-
return jsonify(result=sorted_result)
|
162 |
|
163 |
|
164 |
|
@@ -218,8 +173,10 @@ def ticker_title():
|
|
218 |
example_embed3 = "Title: %s" % (title)
|
219 |
example_embed4 = url
|
220 |
|
221 |
-
|
222 |
-
|
|
|
|
|
223 |
|
224 |
|
225 |
|
|
|
29 |
##### Home #####
|
30 |
@app.route('/')
|
31 |
def home_page():
|
32 |
+
website_description_box = 'This website analyzes stock market news and provides answers to questions related to news articles.'
|
33 |
+
return render_template('index.html', embed=website_description_box)# html을 불러올 때,
|
34 |
|
35 |
|
36 |
|
37 |
##### Data fetch #####
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
|
39 |
# Show Ticker's Table
|
40 |
@app.route('/stocks', methods=['GET', 'POST'])
|
|
|
46 |
|
47 |
|
48 |
|
|
|
|
|
|
|
|
|
49 |
################################################################################################
|
50 |
|
51 |
|
|
|
56 |
|
57 |
dir = './news'
|
58 |
if not os.path.exists(dir):
|
59 |
+
raise NotImplementedError("Not exists News Data") # 오류 강제 발생
|
60 |
|
61 |
# News Data List 가져오기
|
62 |
for key in os.listdir(dir):
|
63 |
if key not in ticker_dic.keys():
|
64 |
+
raise NotImplementedError("Not exists Ticker") # 오류 강제 발생
|
65 |
|
66 |
dir2 = os.path.join(dir, key)
|
67 |
ticker_dic[key] = dict.fromkeys(os.listdir(dir2), []) # 날짜1: [제목1, 제목2, ...]
|
|
|
77 |
ticker_dic[key].pop(date)
|
78 |
|
79 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
80 |
|
81 |
# Show Ticker's Data
|
82 |
@app.route('/chart', methods=['GET', 'POST'])
|
|
|
92 |
# 날짜 형식 바꾸기
|
93 |
chart_data.index = [k.strftime("%Y-%m-%d") for k in chart_data.index]
|
94 |
|
95 |
+
chart_data = chart_data.to_dict()
|
|
|
|
|
96 |
|
|
|
|
|
|
|
97 |
|
98 |
+
################
|
|
|
99 |
|
100 |
news_dir = os.path.join('./news', ticker)
|
101 |
|
102 |
# 해당 Ticker의 날짜별 뉴스 제목을 가져온다.
|
103 |
+
article_news_dict = {}
|
104 |
for key in os.listdir(news_dir):
|
105 |
title_list = os.listdir(os.path.join(news_dir, key))
|
106 |
if len(title_list) != 0:
|
107 |
+
article_news_dict[key] = os.listdir(os.path.join(news_dir, key))
|
108 |
|
109 |
# 최근 뉴스부터 보이게 (정렬)
|
110 |
+
news_articles = {}
|
111 |
+
for key, value in sorted(article_news_dict.items(), reverse=True):
|
112 |
+
news_articles[key] = value
|
113 |
+
|
114 |
+
|
115 |
+
return jsonify(chart_data=chart_data, news_articles=news_articles)
|
116 |
|
|
|
117 |
|
118 |
|
119 |
|
|
|
173 |
example_embed3 = "Title: %s" % (title)
|
174 |
example_embed4 = url
|
175 |
|
176 |
+
return '''
|
177 |
+
newsInit(example_embed1, example_embed2, example_embed3, example_embed4)
|
178 |
+
'''
|
179 |
+
# return render_template('news.html', embed1=example_embed1, embed2=example_embed2, embed3=example_embed3, embed4=example_embed4)
|
180 |
|
181 |
|
182 |
|
static/css/news.css
CHANGED
@@ -112,13 +112,22 @@
|
|
112 |
|
113 |
/* id : "#" */
|
114 |
#model {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
115 |
text-align: center;
|
116 |
}
|
117 |
|
118 |
/* id : "#" */
|
119 |
#text-input {
|
120 |
width: calc(100% / 2); /* 속성의 요소 너비 */
|
121 |
-
height: 78px;
|
122 |
word-break: break-all;
|
123 |
}
|
124 |
|
|
|
112 |
|
113 |
/* id : "#" */
|
114 |
#model {
|
115 |
+
/*
|
116 |
+
[ text-align 태그 ]
|
117 |
+
텍스트의 정렬 방향을 설정
|
118 |
+
|
119 |
+
left: 왼쪽 정렬
|
120 |
+
right: 오른쪽 정렬
|
121 |
+
center: 중앙 정렬
|
122 |
+
justify: 양쪽 정렬 (자동 줄바꿈시 오른쪽 경계선 부분 정리)
|
123 |
+
*/
|
124 |
text-align: center;
|
125 |
}
|
126 |
|
127 |
/* id : "#" */
|
128 |
#text-input {
|
129 |
width: calc(100% / 2); /* 속성의 요소 너비 */
|
130 |
+
height: 78px; /* 속성의 요소의 높이를 지정 */
|
131 |
word-break: break-all;
|
132 |
}
|
133 |
|
static/js/cal.js
ADDED
@@ -0,0 +1,114 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* 달력 렌더링 할 때 필요한 정보 목록
|
3 |
+
|
4 |
+
현재 월 (초기값 : 현재 시간)
|
5 |
+
금월 마지막일 날짜와 요일
|
6 |
+
전월 마지막일 날짜와 요일
|
7 |
+
*/
|
8 |
+
function calendarInit() {
|
9 |
+
|
10 |
+
// 날짜 정보 가져오기
|
11 |
+
var date = new Date(); // 현재 날짜(로컬 기준) 가져오기
|
12 |
+
var utc = date.getTime() + (date.getTimezoneOffset() * 60 * 1000); // utc 표준시 도출
|
13 |
+
var kstGap = 9 * 60 * 60 * 100; // 한국 kst 기준시간 더하기
|
14 |
+
var today = new Date(utc + kstGap); // 한국 시간으로 date 객체 만들기(오늘)
|
15 |
+
|
16 |
+
console.log("Today : ", today)
|
17 |
+
|
18 |
+
// 달력에서 표기하는 날짜 객체
|
19 |
+
var thisMonth = new Date(today.getFullYear(), today.getMonth(), today.getDate());
|
20 |
+
|
21 |
+
var currentYear = thisMonth.getFullYear(); // 달력에서 표기하는 연
|
22 |
+
var currentMonth = thisMonth.getMonth(); // 달력에서 표기하는 월
|
23 |
+
var currentDate = thisMonth.getDate(); // 달력에서 표기하는 일
|
24 |
+
|
25 |
+
// kst 기준 현재시간
|
26 |
+
console.log("thisMonth");
|
27 |
+
console.log(currentYear);
|
28 |
+
console.log(currentMonth); // monthIndex
|
29 |
+
console.log(currentDate);
|
30 |
+
console.log(thisMonth);
|
31 |
+
|
32 |
+
// 캘린더 랜더링
|
33 |
+
renderCalender(thisMonth);
|
34 |
+
|
35 |
+
|
36 |
+
////////////////////////////////////////////////////////////////
|
37 |
+
|
38 |
+
function renderCalender(thisMonth, help=0) {
|
39 |
+
|
40 |
+
// 랜더링을 위한 데이터 정리
|
41 |
+
currentYear = thisMonth.getFullYear();
|
42 |
+
currentMonth = thisMonth = thisMonth.getMonth();
|
43 |
+
if (help != 1) {
|
44 |
+
// currentDate = thisMonth.getDate(); // 1 - 31 : 1 - 31
|
45 |
+
currentDate = new Date(today.getFullYear(), today.getMonth(), today.getDate()).getDate();
|
46 |
+
}
|
47 |
+
|
48 |
+
// 이전 달의 마지막날 날짜와 요일 구하기
|
49 |
+
var startDay = new Date(currentYear, currentMonth, 0);
|
50 |
+
var prevDate = startDay.getDate(); // 1 - 31 : 1 - 31
|
51 |
+
var prevDay = startDay.getDay(); // Sunday - Saturday : 0 - 6
|
52 |
+
|
53 |
+
// 이번 달의 마지막날 날짜와 요일 구하기
|
54 |
+
var endDay = new Date(currentYear, currentMonth + 1 , 0);
|
55 |
+
var nextDate = endDay.getDate(); // 1 - 31 : 1 - 31
|
56 |
+
var nextDay = endDay.getDay(); // Sunday - Saturday : 0 - 6
|
57 |
+
|
58 |
+
// console.log(prevDate, prevDay, nextDate, nextDay, currentMonth);
|
59 |
+
|
60 |
+
// 현재 월 표기
|
61 |
+
$('.year-month').text(currentYear + '.' + (currentMonth + 1));
|
62 |
+
|
63 |
+
// 랜더링 html 요소 생성
|
64 |
+
calendar = document.querySelector('.dates')
|
65 |
+
calendar.innerHTML = '';
|
66 |
+
|
67 |
+
// 지난달
|
68 |
+
for (var i = prevDate - prevDay + 1; i <= prevDate; i++) {
|
69 |
+
calendar.innerHTML = calendar.innerHTML + '<div class="day prev disable">' + i + '</div>'
|
70 |
+
}
|
71 |
+
|
72 |
+
// 이번달
|
73 |
+
for (var i = 1; i <= nextDate; i++) {
|
74 |
+
calendar.innerHTML = calendar.innerHTML + '<div class="day current">' + i + '</div>'
|
75 |
+
}
|
76 |
+
|
77 |
+
// 다음달
|
78 |
+
for (var i = 1; i <= (7 - nextDay == 7 ? 0 : 7 - nextDay); i++) {
|
79 |
+
calendar.innerHTML = calendar.innerHTML + '<div class="day next disable">' + i + '</div>'
|
80 |
+
}
|
81 |
+
|
82 |
+
// 오늘 날짜 표기
|
83 |
+
if (today.getMonth() == currentMonth) {
|
84 |
+
todayDate = today.getDate();
|
85 |
+
var currentMonthDate = document.querySelectorAll('.dates .current'); // 중간 띄어쓰기 주의
|
86 |
+
// var currentMonthDate = document.querySelectorAll('div.day.current'); // 같은 의미
|
87 |
+
|
88 |
+
// console.log(currentMonthDate)
|
89 |
+
currentMonthDate[todayDate-1].classList.add('today');
|
90 |
+
}
|
91 |
+
|
92 |
+
// 이전달로 이동
|
93 |
+
$('.go-prev').on('click', function() {
|
94 |
+
if (help == 0) {
|
95 |
+
thisMonth = new Date(currentYear, currentMonth - 1, 1);
|
96 |
+
renderCalender(thisMonth, 1);
|
97 |
+
}
|
98 |
+
else {
|
99 |
+
renderCalender(thisMonth, 1);
|
100 |
+
}
|
101 |
+
})
|
102 |
+
|
103 |
+
// 다음달로 이동
|
104 |
+
$('.go-next').on('click', function() {
|
105 |
+
if (help == 0) {
|
106 |
+
thisMonth = new Date(currentYear, currentMonth + 1, 1);
|
107 |
+
renderCalender(thisMonth, 1);
|
108 |
+
}
|
109 |
+
else {
|
110 |
+
renderCalender(thisMonth, 1);
|
111 |
+
}
|
112 |
+
})
|
113 |
+
}
|
114 |
+
}
|
static/js/chartIndex.js
CHANGED
@@ -7,15 +7,6 @@ $(function() {
|
|
7 |
|
8 |
|
9 |
|
10 |
-
|
11 |
-
function handleReturn(output) {
|
12 |
-
return output;
|
13 |
-
}
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
function chartInit() {
|
20 |
// Ticker 이름 가져오기
|
21 |
// 해당 class의 text 가져오기
|
@@ -26,7 +17,7 @@ function chartInit() {
|
|
26 |
|
27 |
|
28 |
// Javascript -> Flask (Python) -> Javascript
|
29 |
-
chart_data =
|
30 |
console.log(chart_data);
|
31 |
console.log(Object.keys(chart_data.Close));
|
32 |
|
@@ -44,8 +35,6 @@ function chartInit() {
|
|
44 |
console.log("data : ", data);
|
45 |
|
46 |
|
47 |
-
|
48 |
-
|
49 |
|
50 |
|
51 |
// Javascript chart.js candlestick
|
@@ -90,7 +79,7 @@ function chartInit() {
|
|
90 |
|
91 |
|
92 |
// Javascript -> Flask (Python) -> Javascript
|
93 |
-
news =
|
94 |
|
95 |
news_table = document.querySelector('.table .news-table');
|
96 |
// console.log(news_table.innerHTML);
|
@@ -177,70 +166,4 @@ function chartInit() {
|
|
177 |
|
178 |
news_table.innerHTML = news_table.innerHTML + html;
|
179 |
});
|
180 |
-
}
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
/**
|
198 |
-
*
|
199 |
-
* @param {string} url from javascript to flask(python) with route
|
200 |
-
* @param {dictionary} data from javascript to flask(python) with data
|
201 |
-
* @param {function} handle 큰 의미 없음
|
202 |
-
*/
|
203 |
-
function sendAjax(url, data, handle) {
|
204 |
-
/*
|
205 |
-
jQuery.getJSON(url, [, data], [, success])
|
206 |
-
|
207 |
-
Load JSON-encoded data from the server using a GET HTTP request.
|
208 |
-
*/
|
209 |
-
|
210 |
-
$.getJSON(url, data,
|
211 |
-
function(response) {
|
212 |
-
handle(response.result);
|
213 |
-
});
|
214 |
-
}
|
215 |
-
|
216 |
-
|
217 |
-
/**
|
218 |
-
*
|
219 |
-
* @param {string} url from javascript to flask(python) with route
|
220 |
-
* @param {dictionary} data from javascript to flask(python) with data
|
221 |
-
* @param {string} dataType The type of data that you're expecting back from the server. (ex. "json")
|
222 |
-
* @param {function} handle 큰 의미 없음
|
223 |
-
* @returns from flask(python) to javascript with data
|
224 |
-
*/
|
225 |
-
function sendAjax_async(url, data, dataType, handle) {
|
226 |
-
/*
|
227 |
-
jQuery.ajax(url, [, settings])
|
228 |
-
|
229 |
-
jQuery.getJSON => Asynchronous (비동기식)
|
230 |
-
|
231 |
-
Synchronous => 동기식 : 코드 순서대로 진행
|
232 |
-
*/
|
233 |
-
|
234 |
-
var search_var;
|
235 |
-
console.log("Internal : sendAjax async");
|
236 |
-
|
237 |
-
$.ajax(url=url, settings={data: data, dataType: dataType, async: false,
|
238 |
-
success: function(response) {
|
239 |
-
console.log("Success : ", typeof response);
|
240 |
-
search_var = handle(response.result); // handle, 큰 의미 없음
|
241 |
-
}
|
242 |
-
});
|
243 |
-
|
244 |
-
return search_var
|
245 |
-
}
|
246 |
-
|
|
|
7 |
|
8 |
|
9 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
function chartInit() {
|
11 |
// Ticker 이름 가져오기
|
12 |
// 해당 class의 text 가져오기
|
|
|
17 |
|
18 |
|
19 |
// Javascript -> Flask (Python) -> Javascript
|
20 |
+
chart_data = sendAjax_sync("/chart", {"ticker": ticker}, "json", handle_one_return);
|
21 |
console.log(chart_data);
|
22 |
console.log(Object.keys(chart_data.Close));
|
23 |
|
|
|
35 |
console.log("data : ", data);
|
36 |
|
37 |
|
|
|
|
|
38 |
|
39 |
|
40 |
// Javascript chart.js candlestick
|
|
|
79 |
|
80 |
|
81 |
// Javascript -> Flask (Python) -> Javascript
|
82 |
+
news = sendAjax_sync(url="/news", data={"ticker": ticker}, dataType="json", handle=handle_one_return);
|
83 |
|
84 |
news_table = document.querySelector('.table .news-table');
|
85 |
// console.log(news_table.innerHTML);
|
|
|
166 |
|
167 |
news_table.innerHTML = news_table.innerHTML + html;
|
168 |
});
|
169 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static/js/index.js
CHANGED
@@ -13,7 +13,6 @@
|
|
13 |
|
14 |
|
15 |
|
16 |
-
|
17 |
/*
|
18 |
".ready()"는 DOM(Document Object Model)이 완전히 불러와지면 실행되는 Event 이다.
|
19 |
|
@@ -28,34 +27,61 @@
|
|
28 |
( 근데 여기서는 실행 문제 잘됨 )
|
29 |
*/
|
30 |
|
|
|
|
|
|
|
|
|
|
|
31 |
// $(document).ready(function() { });
|
32 |
$(function() {
|
33 |
-
|
|
|
|
|
|
|
|
|
34 |
|
35 |
-
|
36 |
-
//
|
|
|
|
|
|
|
|
|
|
|
|
|
37 |
});
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
-
function handleReturn(output) {
|
44 |
-
return output;
|
45 |
-
}
|
46 |
|
47 |
|
48 |
|
49 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
50 |
// Javascript -> Flask (Python) -> Javascript
|
51 |
-
output =
|
52 |
|
53 |
-
console.log("stocksInit() Output : ", output);
|
54 |
-
console.log(typeof output);
|
55 |
|
56 |
// Ticker 길이 확인해보기
|
57 |
var object_length = Object.keys(output.ticker).length;
|
58 |
-
console.log(object_length);
|
59 |
|
60 |
|
61 |
// 랜더링 HTML 요소 생성
|
@@ -76,10 +102,10 @@ function stocksInit() {
|
|
76 |
stocks.innerHTML = stocks.innerHTML + '<div class="stock industry">' + output.industry[i] + '</div>';
|
77 |
|
78 |
// Add ticker's chart link
|
79 |
-
|
80 |
stock = document.querySelectorAll('.stock.ticker')[i];
|
81 |
stock.innerHTML = '';
|
82 |
-
stock.innerHTML = stock.innerHTML + '<a href='.concat(
|
83 |
}
|
84 |
}
|
85 |
|
@@ -88,172 +114,362 @@ function stocksInit() {
|
|
88 |
|
89 |
|
90 |
|
91 |
-
/**
|
92 |
-
* 달력 렌더링 할 때 필요한 정보 목록
|
93 |
|
94 |
-
|
95 |
-
|
96 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
*/
|
98 |
-
function
|
|
|
|
|
|
|
|
|
99 |
|
100 |
-
//
|
101 |
-
|
102 |
-
var utc = date.getTime() + (date.getTimezoneOffset() * 60 * 1000); // utc 표준시 도출
|
103 |
-
var kstGap = 9 * 60 * 60 * 100; // 한국 kst 기준시간 더하기
|
104 |
-
var today = new Date(utc + kstGap); // 한국 시간으로 date 객체 만들기(오늘)
|
105 |
|
106 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
107 |
|
108 |
-
// 달력에서 표기하는 날짜 객체
|
109 |
-
var thisMonth = new Date(today.getFullYear(), today.getMonth(), today.getDate());
|
110 |
|
111 |
-
var currentYear = thisMonth.getFullYear(); // 달력에서 표기하는 연
|
112 |
-
var currentMonth = thisMonth.getMonth(); // 달력에서 표기하는 월
|
113 |
-
var currentDate = thisMonth.getDate(); // 달력에서 표기하는 일
|
114 |
|
115 |
-
// kst 기준 현재시간
|
116 |
-
console.log("thisMonth");
|
117 |
-
console.log(currentYear);
|
118 |
-
console.log(currentMonth); // monthIndex
|
119 |
-
console.log(currentDate);
|
120 |
-
console.log(thisMonth);
|
121 |
|
122 |
-
//
|
123 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
124 |
|
125 |
|
126 |
-
////////////////////////////////////////////////////////////////
|
127 |
|
128 |
-
function renderCalender(thisMonth, help=0) {
|
129 |
|
130 |
-
// 랜더링을 위한 데이터 정리
|
131 |
-
currentYear = thisMonth.getFullYear();
|
132 |
-
currentMonth = thisMonth = thisMonth.getMonth();
|
133 |
-
if (help != 1) {
|
134 |
-
// currentDate = thisMonth.getDate(); // 1 - 31 : 1 - 31
|
135 |
-
currentDate = new Date(today.getFullYear(), today.getMonth(), today.getDate()).getDate();
|
136 |
-
}
|
137 |
|
138 |
-
|
139 |
-
var startDay = new Date(currentYear, currentMonth, 0);
|
140 |
-
var prevDate = startDay.getDate(); // 1 - 31 : 1 - 31
|
141 |
-
var prevDay = startDay.getDay(); // Sunday - Saturday : 0 - 6
|
142 |
|
143 |
-
|
144 |
-
var endDay = new Date(currentYear, currentMonth + 1 , 0);
|
145 |
-
var nextDate = endDay.getDate(); // 1 - 31 : 1 - 31
|
146 |
-
var nextDay = endDay.getDay(); // Sunday - Saturday : 0 - 6
|
147 |
|
148 |
-
|
|
|
|
|
|
|
149 |
|
150 |
-
|
151 |
-
$('.year-month').text(currentYear + '.' + (currentMonth + 1));
|
152 |
|
153 |
-
// 랜더링 html 요소 생성
|
154 |
-
calendar = document.querySelector('.dates')
|
155 |
-
calendar.innerHTML = '';
|
156 |
|
157 |
-
// 지난달
|
158 |
-
for (var i = prevDate - prevDay + 1; i <= prevDate; i++) {
|
159 |
-
calendar.innerHTML = calendar.innerHTML + '<div class="day prev disable">' + i + '</div>'
|
160 |
-
}
|
161 |
|
162 |
-
// 이번달
|
163 |
-
for (var i = 1; i <= nextDate; i++) {
|
164 |
-
calendar.innerHTML = calendar.innerHTML + '<div class="day current">' + i + '</div>'
|
165 |
-
}
|
166 |
|
167 |
-
// 다음달
|
168 |
-
for (var i = 1; i <= (7 - nextDay == 7 ? 0 : 7 - nextDay); i++) {
|
169 |
-
calendar.innerHTML = calendar.innerHTML + '<div class="day next disable">' + i + '</div>'
|
170 |
-
}
|
171 |
|
172 |
-
|
173 |
-
if (today.getMonth() == currentMonth) {
|
174 |
-
todayDate = today.getDate();
|
175 |
-
var currentMonthDate = document.querySelectorAll('.dates .current'); // 중간 띄어쓰기 주의
|
176 |
-
// var currentMonthDate = document.querySelectorAll('div.day.current'); // 같은 의미
|
177 |
|
178 |
-
|
179 |
-
|
180 |
-
|
|
|
181 |
|
182 |
-
// 이전달로 이동
|
183 |
-
$('.go-prev').on('click', function() {
|
184 |
-
if (help == 0) {
|
185 |
-
thisMonth = new Date(currentYear, currentMonth - 1, 1);
|
186 |
-
renderCalender(thisMonth, 1);
|
187 |
-
}
|
188 |
-
else {
|
189 |
-
renderCalender(thisMonth, 1);
|
190 |
-
}
|
191 |
-
})
|
192 |
|
193 |
-
// 다음달로 이동
|
194 |
-
$('.go-next').on('click', function() {
|
195 |
-
if (help == 0) {
|
196 |
-
thisMonth = new Date(currentYear, currentMonth + 1, 1);
|
197 |
-
renderCalender(thisMonth, 1);
|
198 |
-
}
|
199 |
-
else {
|
200 |
-
renderCalender(thisMonth, 1);
|
201 |
-
}
|
202 |
-
})
|
203 |
-
}
|
204 |
-
}
|
205 |
|
|
|
|
|
206 |
|
207 |
|
|
|
|
|
|
|
208 |
|
209 |
|
210 |
|
211 |
-
/**
|
212 |
-
*
|
213 |
-
* @param {string} url from javascript to flask(python) with route
|
214 |
-
* @param {dictionary} data from javascript to flask(python) with data
|
215 |
-
* @param {function} handle 큰 의미 없음
|
216 |
-
*/
|
217 |
-
function sendAjax(url, data, handle) {
|
218 |
-
/*
|
219 |
-
jQuery.getJSON(url, [, data], [, success])
|
220 |
|
221 |
-
|
|
|
|
|
|
|
|
|
222 |
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
223 |
|
224 |
-
|
225 |
-
|
226 |
-
handle(response.result);
|
227 |
-
});
|
228 |
}
|
229 |
|
230 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
231 |
/**
|
232 |
*
|
233 |
-
*
|
234 |
-
*
|
235 |
-
*
|
236 |
-
*
|
237 |
-
*
|
|
|
|
|
|
|
|
|
238 |
*/
|
239 |
-
function
|
240 |
-
|
241 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
242 |
|
243 |
-
jQuery.getJSON => Asynchronous (비동기식)
|
244 |
-
|
245 |
-
Synchronous => 동기식 : 코드 순서대로 진행
|
246 |
-
*/
|
247 |
|
248 |
-
|
249 |
-
|
|
|
|
|
250 |
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
255 |
}
|
256 |
});
|
257 |
-
|
258 |
-
return search_var
|
259 |
}
|
|
|
|
13 |
|
14 |
|
15 |
|
|
|
16 |
/*
|
17 |
".ready()"는 DOM(Document Object Model)이 완전히 불러와지면 실행되는 Event 이다.
|
18 |
|
|
|
27 |
( 근데 여기서는 실행 문제 잘됨 )
|
28 |
*/
|
29 |
|
30 |
+
|
31 |
+
|
32 |
+
|
33 |
+
|
34 |
+
|
35 |
// $(document).ready(function() { });
|
36 |
$(function() {
|
37 |
+
var nasdaq_table_container_element = document.getElementById("nasdaq-table-container");
|
38 |
+
var chart_container_element = document.getElementById("chart-container");
|
39 |
+
var news_container_element = document.getElementById("news-container");
|
40 |
+
console.log(nasdaq_table_container_element, chart_container_element, news_container_element);
|
41 |
+
|
42 |
|
43 |
+
// nasdaq_table_container_element.style.display = "block";
|
44 |
+
// chart_container_element.style.display = "none";
|
45 |
+
// news_container_element.style.display = "none";
|
46 |
+
// $("#news-container").hide();
|
47 |
+
// $("#news-container").show();
|
48 |
+
|
49 |
+
|
50 |
+
nasdaq_table_init();
|
51 |
});
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
|
|
|
|
|
|
57 |
|
58 |
|
59 |
|
60 |
+
|
61 |
+
|
62 |
+
|
63 |
+
|
64 |
+
|
65 |
+
/**
|
66 |
+
*
|
67 |
+
*
|
68 |
+
*
|
69 |
+
*
|
70 |
+
*/
|
71 |
+
function nasdaq_table_init() {
|
72 |
+
// HTML 수정
|
73 |
+
$("#chart-container").hide();
|
74 |
+
$("#news-container").hide();
|
75 |
+
|
76 |
// Javascript -> Flask (Python) -> Javascript
|
77 |
+
output = sendAjax_sync("/stocks", {}, "json", handle_one_return);
|
78 |
|
79 |
+
// console.log("stocksInit() Output : ", output);
|
80 |
+
// console.log(typeof output);
|
81 |
|
82 |
// Ticker 길이 확인해보기
|
83 |
var object_length = Object.keys(output.ticker).length;
|
84 |
+
// console.log(object_length);
|
85 |
|
86 |
|
87 |
// 랜더링 HTML 요소 생성
|
|
|
102 |
stocks.innerHTML = stocks.innerHTML + '<div class="stock industry">' + output.industry[i] + '</div>';
|
103 |
|
104 |
// Add ticker's chart link
|
105 |
+
execution_function = String('"javascript:chartInit(\''.concat(output.ticker[i], '\');"'));
|
106 |
stock = document.querySelectorAll('.stock.ticker')[i];
|
107 |
stock.innerHTML = '';
|
108 |
+
stock.innerHTML = stock.innerHTML + '<a href='.concat(execution_function, '>') + output.ticker[i] + '</a>';
|
109 |
}
|
110 |
}
|
111 |
|
|
|
114 |
|
115 |
|
116 |
|
|
|
|
|
117 |
|
118 |
+
|
119 |
+
/**
|
120 |
+
*
|
121 |
+
*
|
122 |
+
*
|
123 |
+
*
|
124 |
+
*
|
125 |
+
*
|
126 |
+
*
|
127 |
+
*
|
128 |
*/
|
129 |
+
function chartInit(ticker) {
|
130 |
+
// HTML 수정
|
131 |
+
$("#nasdaq-table-container").hide();
|
132 |
+
$("#chart-container").show();
|
133 |
+
$("#news-container").hide();
|
134 |
|
135 |
+
// ticker 이름 설정 (부제목 설정)
|
136 |
+
$('#chart-container .goticker .tickerName').text(ticker.concat(' Chart'));
|
|
|
|
|
|
|
137 |
|
138 |
+
// Javascript -> Flask (Python) -> Javascript
|
139 |
+
let [chart_data, news_articles] = sendAjax_sync_about_chartData_and_newsArticles("/chart", {"ticker": ticker}, "json", handle_two_return);
|
140 |
+
// console.log(chart_data, news_articles);
|
141 |
+
// console.log(chart_data);
|
142 |
+
// console.log(Object.keys(chart_data.Close));
|
143 |
+
|
144 |
+
|
145 |
+
// x축과 data 설정
|
146 |
+
// data: [{'x': date, 'o': open, 'h': high, 'l': low, 'c': close}, { }, { }, ... ]
|
147 |
+
data = [];
|
148 |
+
key_list = Object.keys(chart_data.Close);
|
149 |
+
for (var i=key_list.length-15; i<key_list.length; i++) {
|
150 |
+
key = key_list[i];
|
151 |
+
const [year, month, day] = key.split("-");
|
152 |
+
const x = new Date(parseInt(year), parseInt(month), parseInt(day), 9, 0, 0, 0).getTime();
|
153 |
+
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)})
|
154 |
+
}
|
155 |
+
// console.log("data : ", data);
|
156 |
|
|
|
|
|
157 |
|
|
|
|
|
|
|
158 |
|
|
|
|
|
|
|
|
|
|
|
|
|
159 |
|
160 |
+
// Javascript chart.js candlestick
|
161 |
+
let mychart = document.getElementById('myChart');
|
162 |
+
new Chart(mychart, {
|
163 |
+
type: 'candlestick',
|
164 |
+
data: {
|
165 |
+
datasets: [{
|
166 |
+
label: 'CHRT - '.concat(ticker),
|
167 |
+
data: data
|
168 |
+
}]
|
169 |
+
}
|
170 |
+
});
|
171 |
|
172 |
|
|
|
173 |
|
|
|
174 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
175 |
|
176 |
+
//////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
177 |
|
178 |
+
// Javascript를 이용해 HTML에 동적으로 태그 추가
|
|
|
|
|
|
|
179 |
|
180 |
+
// a 태그 onclick 적용
|
181 |
+
execution_function = String('javascript:chartInit(\''.concat(ticker, '\');'));
|
182 |
+
const goTicker = document.querySelector('.goticker');
|
183 |
+
goTicker.setAttribute('href', execution_function);
|
184 |
|
185 |
+
//////////////////////////////////////////////////////////////////
|
|
|
186 |
|
|
|
|
|
|
|
187 |
|
|
|
|
|
|
|
|
|
188 |
|
|
|
|
|
|
|
|
|
189 |
|
|
|
|
|
|
|
|
|
190 |
|
191 |
+
//////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
192 |
|
193 |
+
// table title 표시
|
194 |
+
// 해당 class의 text 집어넣기
|
195 |
+
const table_title = document.querySelector('.table-title');
|
196 |
+
$('.table .table-title').text(ticker.concat(' News'));
|
197 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
198 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
199 |
|
200 |
+
news_table = document.querySelector('.table .news-table');
|
201 |
+
// console.log(news_table.innerHTML);
|
202 |
|
203 |
|
204 |
+
// console.log(news);
|
205 |
+
// console.log(Object.keys(news)); // key 배열 만들기
|
206 |
+
// console.log(typeof Object.keys(news));
|
207 |
|
208 |
|
209 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
210 |
|
211 |
+
/*
|
212 |
+
[ 날짜 정렬 ]
|
213 |
+
"news"에서 index에 대해서 정렬을 하고 reduce() 함수를 적용.
|
214 |
+
|
215 |
+
reduce() : 배열의 각 요소에 대해 주어진 reducer 함수를 실행하고, 하나의 결과값을 반환
|
216 |
*/
|
217 |
+
sorted_news = {}
|
218 |
+
sorted_news = Object.keys(news_articles).sort(function (a, b) {
|
219 |
+
if (a < b) { return 1; }
|
220 |
+
else if (a > b) { return -1; }
|
221 |
+
else { return 0; }
|
222 |
+
}).reduce((sorted_news, key) => {
|
223 |
+
sorted_news[key] = news_articles[key];
|
224 |
+
return sorted_news;
|
225 |
+
}, {});
|
226 |
+
// console.log(sorted_news);
|
227 |
+
|
228 |
+
var key_list = Object.keys(chart_data.Open);
|
229 |
+
var open_list = Object.values(chart_data.Open);
|
230 |
+
var close_list = Object.values(chart_data.Close);
|
231 |
+
|
232 |
+
for (var i=0; i<key_list.length; i++) {
|
233 |
+
const [year, month, day] = key_list[i].split("-");
|
234 |
+
key_list[i] = year + '.' + month + '.' + day;
|
235 |
+
}
|
236 |
+
// console.log(key_list);
|
237 |
+
|
238 |
+
// List 안의 value를 뽑을 때, (Python) => for item in list:
|
239 |
+
Object.keys(sorted_news).forEach(key => {
|
240 |
+
var idx = key_list.indexOf(String(key));
|
241 |
+
|
242 |
+
if (idx != -1) { var diff = ((open_list[idx]-close_list[idx-1])/(open_list[idx]) * 100.0).toFixed(2); }
|
243 |
+
else { var diff = '.'; }
|
244 |
+
|
245 |
+
if (diff == '.') {
|
246 |
+
var diff_html = '<th class="news diff">' + diff + '</th>';
|
247 |
+
}
|
248 |
+
else if (diff > 0) {
|
249 |
+
var diff_html = '<th class="news diff up">+' + diff + ' %</th>';
|
250 |
+
}
|
251 |
+
else {
|
252 |
+
var diff_html = '<th class="news diff down">' + diff + ' %</th>';
|
253 |
+
}
|
254 |
+
var html = '<tr align="center" bgcolor="white"><th>+</th><th>' + key + '</th>' + diff_html + '<td style="text-align: left;">';
|
255 |
+
|
256 |
+
for (var i = 0; i < sorted_news[key].length; i++) {
|
257 |
+
var title = sorted_news[key][i].substring(0, sorted_news[key][i].length-4);
|
258 |
+
var sendTitle = title; // Javascript -> Python 보내기 위한 title
|
259 |
+
console.log("title : ", title);
|
260 |
+
|
261 |
+
|
262 |
+
// title에서 & 표시가 있을 수 있음.
|
263 |
+
// Title 에서 '&'로 표시되어 있는데 따로 구별해야 된다.
|
264 |
+
// andSymbolInTitle 에서 가져온 '&' 위치 index를 title과 합쳐준다.
|
265 |
+
andSymbolInTitle = [];
|
266 |
+
let idx = 0;
|
267 |
+
// title = "asdf&asdf&AS&DF&&";
|
268 |
+
// sendTitle = title;
|
269 |
+
|
270 |
+
while (true) {
|
271 |
+
idx = sendTitle.indexOf('&', idx);
|
272 |
+
if (idx == -1) { break; }
|
273 |
+
sendTitle = sendTitle.substring(0, idx) + sendTitle.substring(idx+1, sendTitle.length);
|
274 |
+
// console.log(sendTitle);
|
275 |
+
andSymbolInTitle.push(idx + andSymbolInTitle.length);
|
276 |
+
}
|
277 |
+
// console.log("title : ", title);
|
278 |
+
// console.log("sendTitle : ", sendTitle);
|
279 |
+
// console.log("andSymbolInTitle : ", andSymbolInTitle);
|
280 |
+
|
281 |
+
var link = String('"/info?ticker='.concat(ticker, '&date=', key, '&title=', sendTitle, '&andSymbolInTitle=', andSymbolInTitle, '"'));
|
282 |
+
// console.log(link);
|
283 |
+
|
284 |
+
var execution_function = String(`javascript:newsInit(\'${ticker}\',\'${key}\',\'${sendTitle}\',\'${andSymbolInTitle}\');`);
|
285 |
+
// console.log("execution_function : ", execution_function);
|
286 |
+
html = html + '<a href=' + link + '>' + title + '</a><br>';
|
287 |
+
}
|
288 |
+
html = html + '</td>';
|
289 |
|
290 |
+
news_table.innerHTML = news_table.innerHTML + html;
|
291 |
+
});
|
|
|
|
|
292 |
}
|
293 |
|
294 |
|
295 |
+
|
296 |
+
|
297 |
+
|
298 |
+
|
299 |
+
|
300 |
+
|
301 |
+
|
302 |
/**
|
303 |
*
|
304 |
+
*
|
305 |
+
*
|
306 |
+
*
|
307 |
+
*
|
308 |
+
*
|
309 |
+
*
|
310 |
+
*
|
311 |
+
*
|
312 |
+
*
|
313 |
*/
|
314 |
+
function newsInit(ticker1, date1, title1, andSymbolInTitle1) {
|
315 |
+
console.log("newsInit start");
|
316 |
+
// HTML 수정
|
317 |
+
$("#nasdaq-table-container").hide();
|
318 |
+
$("#chart-container").hide();
|
319 |
+
$("#news-container").show();
|
320 |
+
|
321 |
+
spaceIndex_inTitle = andSymbolInTitle1.split(',');
|
322 |
+
var list_length = spaceIndex_inTitle.length;
|
323 |
+
for (var i=0; i<list_length; i++) {
|
324 |
+
title1 = title1.substring(0, i) + ' ' + title1.substring(i, title1.length);
|
325 |
+
}
|
326 |
+
|
327 |
+
console.log(ticker1);
|
328 |
+
console.log(date1);
|
329 |
+
console.log(title1);
|
330 |
+
console.log(andSymbolInTitle1);
|
331 |
+
|
332 |
+
|
333 |
+
|
334 |
+
//////////////////////////////////////////////////////////////////////
|
335 |
+
|
336 |
+
// Javascript를 이용해 HTML에 동적으로 태그 추가
|
337 |
+
|
338 |
|
|
|
|
|
|
|
|
|
339 |
|
340 |
+
// a 태그 onclick 적용
|
341 |
+
execution_function = String('javascript:chartInit(\''.concat(ticker, '\');'));
|
342 |
+
const goTicker = document.querySelector('.goticker');
|
343 |
+
goTicker.setAttribute('href', execution_function);
|
344 |
|
345 |
+
|
346 |
+
// a 태그에 URL 적용
|
347 |
+
const addURL = document.querySelector('.NewsURL .input-News-URL');
|
348 |
+
addURL.setAttribute('href', url);
|
349 |
+
|
350 |
+
|
351 |
+
// 모델에서 질문 예시 Ticker에 알맞게 작성하기
|
352 |
+
const example_value = document.querySelector('#model .text-form #text-input');
|
353 |
+
example = "Why did " + ticker + "'s stock go down?";
|
354 |
+
example_value.setAttribute('value', example);
|
355 |
+
|
356 |
+
|
357 |
+
//////////////////////////////////////////////////////////////////////
|
358 |
+
// NER 관련
|
359 |
+
|
360 |
+
ents = sendAjax_sync('/ner', {'ticker': ticker, 'date': date, 'title': title}, dataType="json", handle=handle_one_return);
|
361 |
+
// ents = {'text': [], 'start_char': [], 'end_char': [], 'label_': [], 'news': []}
|
362 |
+
console.log(ents);
|
363 |
+
|
364 |
+
let news = ents['news'];
|
365 |
+
let numOfNER = ents['text'].length;
|
366 |
+
|
367 |
+
|
368 |
+
// 랜더링 html 요소 생성
|
369 |
+
news_ner = document.querySelector('.entities');
|
370 |
+
news_ner.innerHTML = '';
|
371 |
+
|
372 |
+
for (i=0; i<numOfNER-1; i++) {
|
373 |
+
start_idx = (i == 0) ? 0 : ents['end_char'][i-1];
|
374 |
+
end_idx = ents['start_char'][i];
|
375 |
+
last_idx = ents['end_char'][i];
|
376 |
+
|
377 |
+
label = ents['label_'][i];
|
378 |
+
if (label == 'ORG') { class_name = "entity_org"; }
|
379 |
+
else if (label == 'PERSON') { class_name = "entity_person"; }
|
380 |
+
else if (label == 'FAC') { class_name = "entity_fac"; }
|
381 |
+
else if (label == 'GPE') { class_name = "entity_gpe"; }
|
382 |
+
else if (label == 'PRODUCT') { class_name = "entity_product"; }
|
383 |
+
else { console.log("[ Error !!! - New NER label_ ] : ", ents['label_'][i], ents['text'][i]); class_name = "none"; }
|
384 |
+
|
385 |
+
news_ner.innerHTML = news_ner.innerHTML + news.substring(start_idx, end_idx);
|
386 |
+
news_ner.innerHTML = news_ner.innerHTML + '<mark class=' + class_name
|
387 |
+
+ ' style="line-height: 1;">'
|
388 |
+
+ news.substring(end_idx, last_idx)
|
389 |
+
+ '<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">'
|
390 |
+
+ label + '</span></mark>';
|
391 |
+
}
|
392 |
+
news_ner.innerHTML = news_ner.innerHTML + news.substring(ents['end_char'][numOfNER-1]);
|
393 |
+
|
394 |
+
|
395 |
+
|
396 |
+
|
397 |
+
//////////////////////////////////////////////////////////////////////
|
398 |
+
// 모델 적용 내용 ( Submit )
|
399 |
+
|
400 |
+
var sendTitle = title; // Javascript -> Python 보내기 위한 title
|
401 |
+
|
402 |
+
|
403 |
+
// title에서 & 표시가 있을 수 있음.
|
404 |
+
// Title 에서 '&'로 표시되어 있는데 따로 구별해야 된다.
|
405 |
+
// andSymbolInTitle 에서 가져온 '&' 위치 index를 title과 합쳐준다.
|
406 |
+
andSymbolInTitle = [];
|
407 |
+
let idx = 0;
|
408 |
+
// title = "asdf&asdf&AS&DF&&";
|
409 |
+
// sendTitle = title;
|
410 |
+
|
411 |
+
while (true) {
|
412 |
+
idx = sendTitle.indexOf('&', idx);
|
413 |
+
if (idx == -1) { break; }
|
414 |
+
sendTitle = sendTitle.substring(0, idx) + sendTitle.substring(idx+1, sendTitle.length);
|
415 |
+
console.log(sendTitle);
|
416 |
+
andSymbolInTitle.push(idx + andSymbolInTitle.length);
|
417 |
+
}
|
418 |
+
|
419 |
+
console.log(andSymbolInTitle);
|
420 |
+
console.log("Last String", sendTitle);
|
421 |
+
|
422 |
+
|
423 |
+
|
424 |
+
// function 앞에 "async"를 붙이면 해당 함수는 항상 프라미스를 반환한다.
|
425 |
+
const translateText = async (text) => {
|
426 |
+
// 목적 : Flask에 input을 보내주고 output을 받아오는 과정
|
427 |
+
console.log("Start translateText async");
|
428 |
+
|
429 |
+
// "await"는 "async" 함수 안에서만 동작한다.
|
430 |
+
// "await" 키워드를 만나면 Promise가 처리될 때까지 기다린다.
|
431 |
+
// Promise가 처리되길 기다리는 동안엔 엔진이 다른일(다른 스크립트를 실행, 이벤트 처리 등)을 할 수 있기 때문에, CPU 리소스가 낭비되지 않는다.
|
432 |
+
const inferResponse = await fetch(`newsQuestions?ticker=${ticker}&date=${date}&title=${sendTitle}&andSymbolInTitle=${andSymbolInTitle}&questions=${text}`); // Javascript -> Flask(python)
|
433 |
+
|
434 |
+
// console.log("inferResponse : ", inferResponse);
|
435 |
+
|
436 |
+
const inferJson = await inferResponse.json(); // Flask(python) -> Javascript
|
437 |
+
|
438 |
+
// console.log(inferJson);
|
439 |
+
return inferJson.result['answer'];
|
440 |
+
};
|
441 |
+
|
442 |
+
|
443 |
+
/* 모델 Submit button 관련 내용 */
|
444 |
+
// form 태그의 class 이름
|
445 |
+
const textForm = document.querySelector('.text-form');
|
446 |
+
|
447 |
+
|
448 |
+
// addEventListener(type, listener)
|
449 |
+
// addEventListener(type, listener, options)
|
450 |
+
// addEventListener(type, listener, useCapture)
|
451 |
+
textForm.addEventListener('submit', async (event) => {
|
452 |
+
event.preventDefault();
|
453 |
+
// console.log(event);
|
454 |
+
|
455 |
+
// html -> javascript : input 받아와서 output 보내기
|
456 |
+
const textInput = document.getElementById('text-input');
|
457 |
+
const textParagraph = document.querySelector('.text-output');
|
458 |
+
|
459 |
+
console.log("textInput : ", textInput, textInput.value);
|
460 |
+
try {
|
461 |
+
// sendAjax("/inference", {"input_text" : textInput.value}, handleOutput);
|
462 |
+
|
463 |
+
// "await"는 "async" 함수 안에서만 동작한다.
|
464 |
+
// "await" 키워드를 만나면 Promise가 처리될 때까지 기다린다.
|
465 |
+
// Promise가 처리되길 기다리는 동안엔 엔진이 다른일(다른 스크립트를 실행, 이벤트 처리 등)을 할 수 있기 때문에, CPU 리소스가 낭비되지 않는다.
|
466 |
+
const answer = await translateText(textInput.value); // Flask에 input을 보내주고 output을 받아오는 과정
|
467 |
+
|
468 |
+
console.log("Answer : ", answer);
|
469 |
+
textParagraph.textContent = answer;
|
470 |
+
} catch (err) {
|
471 |
+
console.error(err);
|
472 |
}
|
473 |
});
|
|
|
|
|
474 |
}
|
475 |
+
|
static/js/news.js
CHANGED
@@ -54,7 +54,7 @@ function newsInit() {
|
|
54 |
//////////////////////////////////////////////////////////////////////
|
55 |
// NER 관련
|
56 |
|
57 |
-
ents =
|
58 |
// ents = {'text': [], 'start_char': [], 'end_char': [], 'label_': [], 'news': []}
|
59 |
console.log(ents);
|
60 |
|
@@ -81,7 +81,7 @@ function newsInit() {
|
|
81 |
|
82 |
news_ner.innerHTML = news_ner.innerHTML + news.substring(start_idx, end_idx);
|
83 |
news_ner.innerHTML = news_ner.innerHTML + '<mark class=' + class_name
|
84 |
-
+ ' style="
|
85 |
+ news.substring(end_idx, last_idx)
|
86 |
+ '<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">'
|
87 |
+ label + '</span></mark>';
|
@@ -159,6 +159,7 @@ function newsInit() {
|
|
159 |
|
160 |
// html -> javascript : input 받아와서 output 보내기
|
161 |
const textInput = document.getElementById('text-input');
|
|
|
162 |
const textParagraph = document.querySelector('.text-output');
|
163 |
|
164 |
console.log("textInput : ", textInput, textInput.value);
|
@@ -176,79 +177,6 @@ function newsInit() {
|
|
176 |
console.error(err);
|
177 |
}
|
178 |
});
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
}
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
/**
|
201 |
-
*
|
202 |
-
* @param {string} url from javascript to flask(python) with route
|
203 |
-
* @param {dictionary} data from javascript to flask(python) with data
|
204 |
-
* @param {function} handle 큰 의미 없음
|
205 |
-
*/
|
206 |
-
function sendAjax(url, data, handle) {
|
207 |
-
/*
|
208 |
-
jQuery.getJSON(url, [, data], [, success])
|
209 |
-
|
210 |
-
Load JSON-encoded data from the server using a GET HTTP request.
|
211 |
-
*/
|
212 |
-
|
213 |
-
$.getJSON(url, data,
|
214 |
-
function(response) {
|
215 |
-
handle(response.result);
|
216 |
-
});
|
217 |
}
|
218 |
|
219 |
|
220 |
-
/**
|
221 |
-
*
|
222 |
-
* @param {string} url from javascript to flask(python) with route
|
223 |
-
* @param {dictionary} data from javascript to flask(python) with data
|
224 |
-
* @param {string} dataType The type of data that you're expecting back from the server. (ex. "json")
|
225 |
-
* @param {function} handle 큰 의미 없음
|
226 |
-
* @returns from flask(python) to javascript with data
|
227 |
-
*/
|
228 |
-
function sendAjax_async(url, data, dataType, handle) {
|
229 |
-
/*
|
230 |
-
jQuery.ajax(url, [, settings])
|
231 |
-
|
232 |
-
jQuery.getJSON => Asynchronous (비동기식)
|
233 |
-
|
234 |
-
Synchronous => 동기식 : 코드 순서대로 진행
|
235 |
-
*/
|
236 |
-
|
237 |
-
var search_var;
|
238 |
-
console.log("Internal : sendAjax async");
|
239 |
-
|
240 |
-
$.ajax(url=url, settings={data: data, dataType: dataType, async: false,
|
241 |
-
success: function(response) {
|
242 |
-
console.log("Success : ", typeof response);
|
243 |
-
search_var = handle(response.result); // handle, 큰 의미 없음
|
244 |
-
}
|
245 |
-
});
|
246 |
-
|
247 |
-
return search_var
|
248 |
-
}
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
function handleReturn(output) {
|
253 |
-
return output;
|
254 |
-
}
|
|
|
54 |
//////////////////////////////////////////////////////////////////////
|
55 |
// NER 관련
|
56 |
|
57 |
+
ents = sendAjax_sync('/ner', {'ticker': ticker, 'date': date, 'title': title}, dataType="json", handle=handle_one_return);
|
58 |
// ents = {'text': [], 'start_char': [], 'end_char': [], 'label_': [], 'news': []}
|
59 |
console.log(ents);
|
60 |
|
|
|
81 |
|
82 |
news_ner.innerHTML = news_ner.innerHTML + news.substring(start_idx, end_idx);
|
83 |
news_ner.innerHTML = news_ner.innerHTML + '<mark class=' + class_name
|
84 |
+
+ ' style="line-height: 1;">'
|
85 |
+ news.substring(end_idx, last_idx)
|
86 |
+ '<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">'
|
87 |
+ label + '</span></mark>';
|
|
|
159 |
|
160 |
// html -> javascript : input 받아와서 output 보내기
|
161 |
const textInput = document.getElementById('text-input');
|
162 |
+
console.log("element : ", textInput);
|
163 |
const textParagraph = document.querySelector('.text-output');
|
164 |
|
165 |
console.log("textInput : ", textInput, textInput.value);
|
|
|
177 |
console.error(err);
|
178 |
}
|
179 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
180 |
}
|
181 |
|
182 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static/js/utils.js
ADDED
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* helper functions defined
|
3 |
+
*/
|
4 |
+
|
5 |
+
function handle_one_return(output) {
|
6 |
+
return output;
|
7 |
+
}
|
8 |
+
function handle_two_return(output1, output2) {
|
9 |
+
return [output1, output2];
|
10 |
+
}
|
11 |
+
|
12 |
+
|
13 |
+
|
14 |
+
/**
|
15 |
+
*
|
16 |
+
* @param {string} url from javascript to flask(python) with route
|
17 |
+
* @param {dictionary} data from javascript to flask(python) with data
|
18 |
+
* @param {function} handle 큰 의미 없음
|
19 |
+
*/
|
20 |
+
function sendAjax(url, data, handle) {
|
21 |
+
/*
|
22 |
+
jQuery.getJSON(url, [, data], [, success])
|
23 |
+
|
24 |
+
Load JSON-encoded data from the server using a GET HTTP request.
|
25 |
+
*/
|
26 |
+
|
27 |
+
$.getJSON(url, data,
|
28 |
+
function(response) {
|
29 |
+
handle(response.result);
|
30 |
+
}
|
31 |
+
);
|
32 |
+
}
|
33 |
+
|
34 |
+
|
35 |
+
/**
|
36 |
+
*
|
37 |
+
* @param {string} url from javascript to flask(python) with route
|
38 |
+
* @param {dictionary} data from javascript to flask(python) with data
|
39 |
+
* @param {string} dataType The type of data that you're expecting back from the server. (ex. "json")
|
40 |
+
* @param {function} handle 큰 의미 없음
|
41 |
+
* @returns from flask(python) to javascript with data
|
42 |
+
*/
|
43 |
+
function sendAjax_sync(url, data, dataType, handle) {
|
44 |
+
/*
|
45 |
+
jQuery.ajax(url, [, settings])
|
46 |
+
|
47 |
+
jQuery.getJSON => Asynchronous (비동기식)
|
48 |
+
|
49 |
+
Synchronous => 동기식 : 코드 순서대로 진행
|
50 |
+
*/
|
51 |
+
var search_var;
|
52 |
+
$.ajax(url=url, settings={data: data, dataType: dataType, async: false,
|
53 |
+
success: function(response) {
|
54 |
+
search_var = handle(response.result); // handle, 큰 의미 없음
|
55 |
+
}
|
56 |
+
});
|
57 |
+
|
58 |
+
return search_var
|
59 |
+
}
|
60 |
+
|
61 |
+
|
62 |
+
|
63 |
+
/**
|
64 |
+
*
|
65 |
+
* @param {string} url from javascript to flask(python) with route
|
66 |
+
* @param {dictionary} data from javascript to flask(python) with data
|
67 |
+
* @param {string} dataType The type of data that you're expecting back from the server. (ex. "json")
|
68 |
+
* @param {function} handle 큰 의미 없음
|
69 |
+
* @returns from flask(python) to javascript with data
|
70 |
+
*/
|
71 |
+
function sendAjax_sync_about_chartData_and_newsArticles(url, data, dataType, handle) {
|
72 |
+
/*
|
73 |
+
jQuery.ajax(url, [, settings])
|
74 |
+
|
75 |
+
jQuery.getJSON => Asynchronous (비동기식)
|
76 |
+
|
77 |
+
Synchronous => 동기식 : 코드 순서대로 진행
|
78 |
+
*/
|
79 |
+
var chart_data;
|
80 |
+
var news_articles;
|
81 |
+
$.ajax(url=url, settings={data: data, dataType: dataType, async: false,
|
82 |
+
success: function(response) {
|
83 |
+
[chart_data, news_articles] = handle(response.chart_data, response.news_articles); // handle, 큰 의미 없음
|
84 |
+
}
|
85 |
+
});
|
86 |
+
|
87 |
+
return [chart_data, news_articles];
|
88 |
+
}
|
89 |
+
|
templates/chart.html
CHANGED
@@ -13,66 +13,18 @@
|
|
13 |
<!-- jQuery -->
|
14 |
<script src='//cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js'></script>
|
15 |
<!-- script 태그 : 외부 js 파일을 연결하거나 javascript 코드를 입력할 때 사용 -->
|
|
|
16 |
<script type="text/javascript" src="static/js/chartIndex.js"></script>
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
-
|
23 |
-
|
24 |
-
<!-- Recharts -->
|
25 |
-
<!-- <script src="https://unpkg.com/react/umd/react.production.min.js"></script>
|
26 |
-
<script src="https://unpkg.com/react-dom/umd/react-dom.production.min.js"></script>
|
27 |
-
|
28 |
-
<script src="https://unpkg.com/prop-types/prop-types.min.js"></script>
|
29 |
-
<script src="https://unpkg.com/recharts/umd/Recharts.js"></script> -->
|
30 |
-
|
31 |
-
<!-- <script src="https://unpkg.com/recharts/umd/Recharts.min.js"></script> -->
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
|
39 |
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.js"></script>
|
40 |
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
|
41 |
<script src="static/js/chartjs-chart-financial.js" type="text/javascript"></script>
|
42 |
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
<!-- 보류 모르겠음 ... -->
|
47 |
-
|
48 |
-
<!-- ========================================================================================= -->
|
49 |
-
|
50 |
-
|
51 |
-
<!-- Include Chart.js from a CDN -->
|
52 |
-
|
53 |
-
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.2.1/chart.min.js"></script> -->
|
54 |
-
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.2.1/chart.js"></script> -->
|
55 |
-
<!-- <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> -->
|
56 |
-
|
57 |
-
|
58 |
-
<!-- <script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
|
59 |
-
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.js"></script>
|
60 |
-
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
|
61 |
-
|
62 |
-
|
63 |
-
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
|
64 |
-
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.js"></script>
|
65 |
-
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
|
66 |
-
|
67 |
-
<script src="https://www.chartjs.org/chartjs-chart-financial/chartjs-chart-financial.js"></script> -->
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
<!--
|
72 |
-
CDN : Content Delivery Network
|
73 |
-
지리적 제약 없이 전 세계 사용자에게 빠르고 안전하게 콘텐츠를 전송할 수 있는 '콘텐츠 전송 기술을 의미'
|
74 |
-
서버와 사용자 사이의 물리적인 거리를 줄여 콘텐츠 로딩에 소요되는 시간을 최소화한다.
|
75 |
-
-->
|
76 |
</head>
|
77 |
|
78 |
|
|
|
13 |
<!-- jQuery -->
|
14 |
<script src='//cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js'></script>
|
15 |
<!-- script 태그 : 외부 js 파일을 연결하거나 javascript 코드를 입력할 때 사용 -->
|
16 |
+
<script type="text/javascript" src="static/js/utils.js"></script>
|
17 |
<script type="text/javascript" src="static/js/chartIndex.js"></script>
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
|
24 |
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.js"></script>
|
25 |
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
|
26 |
<script src="static/js/chartjs-chart-financial.js" type="text/javascript"></script>
|
27 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
</head>
|
29 |
|
30 |
|
templates/index.html
CHANGED
@@ -12,43 +12,186 @@
|
|
12 |
<link rel="stylesheet" href="static/css/style.css" />
|
13 |
|
14 |
<!-- jQuery -->
|
15 |
-
<script src='//cdnjs.cloudflare.com/ajax/libs/jquery/3.6.
|
16 |
<!-- script 태그 : 외부 js 파일을 연결하거나 javascript 코드를 입력할 때 사용 -->
|
|
|
17 |
<script type="text/javascript" src="static/js/index.js"></script>
|
18 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
</head>
|
20 |
|
21 |
|
22 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
|
24 |
<!-- body 태그 : 본문에 해당하는 부분, 실제 보여지는 화면에 해당 -->
|
25 |
<body>
|
26 |
-
<h1><a class="gohome" href="" onclick="sendAjax('/', undefined, undefined);"> Stock News NER & Analysis </a></h1>
|
27 |
-
<p id='embed'>{{embed}}</p>
|
28 |
|
29 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
30 |
|
31 |
|
32 |
-
|
33 |
-
<!--
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
<div class="
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
<div class="column close">Close</div>
|
46 |
-
<div class="column sector">Sector</div>
|
47 |
-
<div class="column industry">Industry</div>
|
48 |
</div>
|
49 |
|
50 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
</div>
|
52 |
|
|
|
|
|
|
|
53 |
</body>
|
54 |
</html>
|
|
|
12 |
<link rel="stylesheet" href="static/css/style.css" />
|
13 |
|
14 |
<!-- jQuery -->
|
15 |
+
<script src='//cdnjs.cloudflare.com/ajax/libs/jquery/3.6.4/jquery.min.js'></script>
|
16 |
<!-- script 태그 : 외부 js 파일을 연결하거나 javascript 코드를 입력할 때 사용 -->
|
17 |
+
<script type="text/javascript" src="static/js/utils.js"></script>
|
18 |
<script type="text/javascript" src="static/js/index.js"></script>
|
19 |
|
20 |
+
|
21 |
+
|
22 |
+
<!-- Draw Chart Library -->
|
23 |
+
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
|
24 |
+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.js"></script>
|
25 |
+
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
|
26 |
+
<script src="static/js/chartjs-chart-financial.js" type="text/javascript"></script>
|
27 |
</head>
|
28 |
|
29 |
|
30 |
|
31 |
+
<!-- [ id class 차이 ] -->
|
32 |
+
<!-- id : 한 문서에 단 하나의 요소에만 적용(중복X) -->
|
33 |
+
<!-- id : 특정 요소에 이름을 붙이는데 사용 -->
|
34 |
+
<!-- class : 동일한 값을 갖는 요소 많음 -->
|
35 |
+
<!-- class : 스타일의 분류에 사용 -->
|
36 |
+
|
37 |
+
|
38 |
+
|
39 |
|
40 |
<!-- body 태그 : 본문에 해당하는 부분, 실제 보여지는 화면에 해당 -->
|
41 |
<body>
|
|
|
|
|
42 |
|
43 |
+
<!-- block = show, none = hide -->
|
44 |
+
<div id="nasdaq-table-container" style="display: block">
|
45 |
+
<h1><a class="gohome" style="text-decoration: none;" href="" onclick="sendAjax('/', undefined, undefined);"> Stock News NER & Analysis </a></h1>
|
46 |
+
<p id='embed'>{{embed}}</p>
|
47 |
+
|
48 |
+
<p id='mylog' />
|
49 |
+
|
50 |
+
<div class="stocks_wrap">
|
51 |
+
<div class="stocks_columns">
|
52 |
+
<div class="column ticker">Ticker</div>
|
53 |
+
<div class="column name">Name</div>
|
54 |
+
<div class="column dff">Diff</div>
|
55 |
+
<div class="column open">Open</div>
|
56 |
+
<div class="column close">Close</div>
|
57 |
+
<div class="column sector">Sector</div>
|
58 |
+
<div class="column industry">Industry</div>
|
59 |
+
</div>
|
60 |
+
|
61 |
+
<div class="stocks"></div>
|
62 |
+
</div>
|
63 |
+
</div>
|
64 |
|
65 |
|
66 |
+
|
67 |
+
<!-- block = show, none = hide -->
|
68 |
+
<div id="chart-container" style="display: block">
|
69 |
+
<h1><a class="gohome" style="text-decoration: none;" href="/">Stock News Summaries AI</a></h1>
|
70 |
+
<a class="goticker" style="text-decoration: none;"><h2 class="tickerName"></h2></a>
|
71 |
+
|
72 |
+
<div>
|
73 |
+
<div id="chart-container" width="974" height="486"></div>
|
74 |
+
|
75 |
+
<div class="myChart-container">
|
76 |
+
<canvas id="myChart"></canvas>
|
77 |
+
</div>
|
78 |
+
|
|
|
|
|
|
|
79 |
</div>
|
80 |
|
81 |
+
<!--
|
82 |
+
[ 속성 ]
|
83 |
+
|
84 |
+
align : 정렬을 지정한다. (left, center, right)
|
85 |
+
border : 테두리 선의 두께를 지정한다.
|
86 |
+
bgcolor : 배경색을 지정한다. (색은 "red", "black" 처럼 기존의 정의되어있는 색을 사용할 수도 있으며
|
87 |
+
rgb형식의 #000000 으로도 색을 지정할 수 있다.)
|
88 |
+
bordercolor : 테두리 선의 색을 지정한다. 색을 지정하는 방법은 bgcolor와 동일하다.
|
89 |
+
cellspacing : 셀간의 간격을 지정한다.
|
90 |
+
width : 가로 길이를 지정한다. (상수 값을 입력할 수도, % 단위로 입력할 수 있다.
|
91 |
+
%를 사용할 때는 웹브라우저 크기에 대한 % 이다.)
|
92 |
+
height : 세로 길이를 지정한다.
|
93 |
+
rawspan : 지정한 값만큼 행을 병합한다. (위아래로)
|
94 |
+
colspan : 지정한 값만큼 열을 병합한다. (좌우로)
|
95 |
+
-->
|
96 |
+
|
97 |
+
|
98 |
+
<!-- table 태그 : 테이블을 만든다. -->
|
99 |
+
<table class="table"
|
100 |
+
|
101 |
+
text-align="center"
|
102 |
+
align-items="center"
|
103 |
+
justify-content="center"
|
104 |
+
|
105 |
+
border="1"
|
106 |
+
width="90%"
|
107 |
+
height="200"
|
108 |
+
cellspacing="5">
|
109 |
+
|
110 |
+
|
111 |
+
<!-- caption 태그 : 테이블 이름 표시 -->
|
112 |
+
<caption class="table-title"></caption>
|
113 |
+
|
114 |
+
<!-- 테이블의 헤더 영역 지정 -->
|
115 |
+
<thread>
|
116 |
+
<!-- tr 태그 : 테이블읠 행(가로 한줄)을 만든다. -->
|
117 |
+
<tr align="center" bgcolor="white">
|
118 |
+
<!-- td 태그 : 테이블의 열을 만든다. -->
|
119 |
+
<td width="5%"></td>
|
120 |
+
|
121 |
+
<!-- th 태그 : 테이블(표)의 헤드 부분(자동으로 가운데 정렬, 굵게 적용) -->
|
122 |
+
<th width="10%">Date</th>
|
123 |
+
<th width="10%">Diff</th>
|
124 |
+
<th class="title-width">Articles</th>
|
125 |
+
</tr>
|
126 |
+
</thread>
|
127 |
+
|
128 |
+
<!-- tbody 태그 : -->
|
129 |
+
<tbody class="news-table">
|
130 |
+
<!-- News: Date, Diff, Title 추가 -->
|
131 |
+
</tbody>
|
132 |
+
|
133 |
+
</table>
|
134 |
+
</div>
|
135 |
+
|
136 |
+
|
137 |
+
|
138 |
+
<!-- block = show, none = hide -->
|
139 |
+
<div id="news-container" style="display: block">
|
140 |
+
<h1><a class="gohome" style="text-decoration: none;" href="/">Stock News Summaries AI</a></h1>
|
141 |
+
<a class="goticker" style="text-decoration: none;"><h2 class="tickerName">{{embed1}}</h2></a>
|
142 |
+
<h3 class="titleDate">{{embed2}}</h2>
|
143 |
+
<h3 class="titleName">{{embed3}}</h2>
|
144 |
+
<h3 class="NewsURL">URL: <a class="input-News-URL" target=”_blank”>{{embed4}}</a></h2>
|
145 |
+
|
146 |
+
<!-- named entity recognition (NER) -->
|
147 |
+
<figure style="margin-bottom: 6rem">
|
148 |
+
<div class="entities" style="line-height: 2.5; direction: ltr">
|
149 |
+
|
150 |
+
</div>
|
151 |
+
</figure>
|
152 |
+
|
153 |
+
|
154 |
+
<!-- section 태그 : HTML 문서에 포함된 독립적인 섹션을 정의할 때 사용 -->
|
155 |
+
<section id="model">
|
156 |
+
<h2>Questions about Stock's News</h2>
|
157 |
+
|
158 |
+
<!-- p 태그 : paragraph, 즉 문단의 약자로, 하나의 문단을 만들 때 사용 -->
|
159 |
+
<p>
|
160 |
+
Model :
|
161 |
+
|
162 |
+
<!-- target="_blank" : 기본속성 중 하나로 클릭시 계속해서 새로운 창이 열리게 된다. -->
|
163 |
+
<a
|
164 |
+
href="https://huggingface.co/allenai/tk-instruct-base-def-pos"
|
165 |
+
rel="noeferrer"
|
166 |
+
target="_blank">Tk-instruct Model</a
|
167 |
+
>
|
168 |
+
</p>
|
169 |
+
|
170 |
+
|
171 |
+
<!-- form 태그 : 데이터를 전송하기 위한 태그 -->
|
172 |
+
<!-- form 태그 : 데이터를 전송할 url (action 속성) -->
|
173 |
+
<!-- form 태그 : 데이터 전달 방식이 get인지 post인지 결정 (method 속성) -->
|
174 |
+
<form class="text-form">
|
175 |
+
|
176 |
+
<!-- label 태그는 for 속성을 사용해서 input 태그의 id 속성에 연계해서 사용 -->
|
177 |
+
<label for="text-input">[ Questions ]</label> <br>
|
178 |
+
<input
|
179 |
+
id="text-input"
|
180 |
+
type="text"
|
181 |
+
placeholder="Input Questions"
|
182 |
+
value="Why did Alphabet's stock go down?"
|
183 |
+
/>
|
184 |
+
|
185 |
+
<button id="text-submit">Submit</button>
|
186 |
+
<p> [ Answer ] </p>
|
187 |
+
<p class="text-output"></p>
|
188 |
+
</form>
|
189 |
+
|
190 |
+
</section>
|
191 |
</div>
|
192 |
|
193 |
+
|
194 |
+
|
195 |
+
|
196 |
</body>
|
197 |
</html>
|
templates/news_analysis.html
DELETED
@@ -1,88 +0,0 @@
|
|
1 |
-
<!-- html 태그 : HTML로 작성되어 있다는 것을 알려줌 -->
|
2 |
-
<!-- html 태그 : html 파일 전체를 감싸는 태그 -->
|
3 |
-
<html>
|
4 |
-
<!-- head 태그 : 머리말에 해당 -->
|
5 |
-
<!-- head 태그 : css나 javascript를 연결해줌 -->
|
6 |
-
<!-- head 태그 : 파비콘이나 문자열 인코딩과 같은 문서의 다양한 정보를 제공 -->
|
7 |
-
<head>
|
8 |
-
|
9 |
-
<!-- link 태그 : 주로 외부 css 파일을 연결할 때 사용 -->
|
10 |
-
<link rel="stylesheet" href="static/css/news.css" />
|
11 |
-
|
12 |
-
<!-- jQuery -->
|
13 |
-
<script src='//cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js'></script>
|
14 |
-
<!-- script 태그 : 외부 js 파일을 연결하거나 javascript 코드를 입력할 때 사용 -->
|
15 |
-
<script type="text/javascript" src="static/js/news.js"></script>
|
16 |
-
|
17 |
-
|
18 |
-
</head>
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
<!-- body 태그 : 본문에 해당하는 부분, 실제 보여지는 화면에 해당 -->
|
23 |
-
<body>
|
24 |
-
<h1><a class="gohome" href="/">Stock News Summaries AI</a></h1>
|
25 |
-
<a class="goticker"><h2 class="tickerName">{{embed1}}</h2></a>
|
26 |
-
<h3 class="titleDate">{{embed2}}</h2>
|
27 |
-
<h3 class="titleName">{{embed3}}</h2>
|
28 |
-
<h3 class="NewsURL">URL: <a class="input-News-URL" target=”_blank”>{{embed4}}</a></h2>
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
<!-- named entity recognition (NER) -->
|
33 |
-
<figure style="margin-bottom: 6rem">
|
34 |
-
<div class="entities" style="line-height: 2.5; direction: ltr">
|
35 |
-
|
36 |
-
</div>
|
37 |
-
</figure>
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
<!-- section 태그 : HTML 문서에 포함된 독립적인 섹션을 정의할 때 사용 -->
|
43 |
-
<section id="model">
|
44 |
-
<h2>Questions about Stock's News</h2>
|
45 |
-
|
46 |
-
<!-- p 태그 : paragraph, 즉 문단의 약자로, 하나의 문단을 만들 때 사용 -->
|
47 |
-
<p>
|
48 |
-
Model :
|
49 |
-
|
50 |
-
<!-- target="_blank" : 기본속성 중 하나로 클릭시 계속해서 새로운 창이 열리게 된다. -->
|
51 |
-
<a
|
52 |
-
href="https://huggingface.co/allenai/tk-instruct-base-def-pos"
|
53 |
-
rel="noeferrer"
|
54 |
-
target="_blank">Tk-instruct Model</a
|
55 |
-
>
|
56 |
-
</p>
|
57 |
-
|
58 |
-
|
59 |
-
<!-- form 태그 : 데이터를 전송하기 위한 태그 -->
|
60 |
-
<!-- form 태그 : 데이터를 전송할 url (action 속성) -->
|
61 |
-
<!-- form 태그 : 데이터 전달 방식이 get인지 post인지 결정 (method 속성) -->
|
62 |
-
<form class="text-form">
|
63 |
-
|
64 |
-
<!-- label 태그는 for 속성을 사용해서 input 태그의 id 속성에 연계해서 사용 -->
|
65 |
-
<label for="text-input">[ Questions ]</label> <br>
|
66 |
-
<input
|
67 |
-
id="text-input"
|
68 |
-
type="text"
|
69 |
-
placeholder="Input Questions"
|
70 |
-
value="Why did Alphabet's stock go down?"
|
71 |
-
/>
|
72 |
-
|
73 |
-
<button id="text-submit">Submit</button>
|
74 |
-
<p> [ Answer ] </p>
|
75 |
-
<p class="text-output"></p>
|
76 |
-
</form>
|
77 |
-
|
78 |
-
</section>
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
</body>
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
</html>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|