├── __init__.py
├── alphaSandol
├── __init__.py
├── Pipfile
├── zappa_settings.json
├── Imoge.json
├── weather.py
├── test_constant.py
├── covid.py
├── announcement.py
├── settings.py
├── feedback.py
├── test_block.py
├── main.py
├── return_type_generator.py
├── subway.py
├── restaurant.py
└── Pipfile.lock
├── statistic
├── now.csv
└── sandol_200109-211018.csv
├── img
├── card1.png
├── card2.png
├── card3.png
├── logo1.png
├── logo2.png
├── logo3.png
├── 광고_미가.png
├── 광고_세미콘.png
├── diagram.jpg
├── meal_map.png
├── card_covid.png
├── card_food.png
├── card_miga.png
├── card_other.png
├── card_wells.png
├── 산돌이레포짓토리QR.jpg
├── 산돌이친구추가QR.jpeg
├── logo_profile1.png
├── logo_profile2.png
└── logo_profile3.png
├── Persona
├── 도움말_임시.png
├── Persona_logic.png
└── snadol_Persona.drawio
├── .gitignore
├── test_stored_data
├── feedback.txt
└── restaurant_menu.txt
├── return_type_img
├── Text Type.JPG
├── set_img.PNG
├── Carousel Type.JPG
├── List Card Type.JPG
├── Basic Card Field.JPG
├── Basic Card Test.JPG
├── Basic Card Type.JPG
├── Simple Text Test.JPG
├── Commerce Card Field.JPG
└── Commerce Card Type.JPG
├── commerce_img
├── commerce_test1.png
├── commerce_test2.png
├── commerce_test3.png
├── commerce_test4.png
├── commerce_test5.png
└── commerce_test6.png
├── betaSandol
├── Pipfile
├── zappa_settings.json
├── lambda_prototype.py
├── return_type_generator.py
├── Pipfile.lock
└── lambda_prototype_module.py
├── .github
├── ISSUE_TEMPLATE
│ └── bug_report.md
└── workflows
│ └── cd.yml
├── LICENSE
├── README.md
└── Return Type Generator.md
/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/alphaSandol/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/statistic/now.csv:
--------------------------------------------------------------------------------
1 | awd
2 |
--------------------------------------------------------------------------------
/img/card1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/img/card1.png
--------------------------------------------------------------------------------
/img/card2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/img/card2.png
--------------------------------------------------------------------------------
/img/card3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/img/card3.png
--------------------------------------------------------------------------------
/img/logo1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/img/logo1.png
--------------------------------------------------------------------------------
/img/logo2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/img/logo2.png
--------------------------------------------------------------------------------
/img/logo3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/img/logo3.png
--------------------------------------------------------------------------------
/img/광고_미가.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/img/광고_미가.png
--------------------------------------------------------------------------------
/img/광고_세미콘.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/img/광고_세미콘.png
--------------------------------------------------------------------------------
/img/diagram.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/img/diagram.jpg
--------------------------------------------------------------------------------
/img/meal_map.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/img/meal_map.png
--------------------------------------------------------------------------------
/Persona/도움말_임시.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/Persona/도움말_임시.png
--------------------------------------------------------------------------------
/img/card_covid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/img/card_covid.png
--------------------------------------------------------------------------------
/img/card_food.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/img/card_food.png
--------------------------------------------------------------------------------
/img/card_miga.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/img/card_miga.png
--------------------------------------------------------------------------------
/img/card_other.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/img/card_other.png
--------------------------------------------------------------------------------
/img/card_wells.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/img/card_wells.png
--------------------------------------------------------------------------------
/img/산돌이레포짓토리QR.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/img/산돌이레포짓토리QR.jpg
--------------------------------------------------------------------------------
/img/산돌이친구추가QR.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/img/산돌이친구추가QR.jpeg
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | **/.idea
2 | **/__pycache__
3 | .DS_Store
4 | ./venv
5 | ./alphaSandol/test_constant.py
6 |
--------------------------------------------------------------------------------
/img/logo_profile1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/img/logo_profile1.png
--------------------------------------------------------------------------------
/img/logo_profile2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/img/logo_profile2.png
--------------------------------------------------------------------------------
/img/logo_profile3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/img/logo_profile3.png
--------------------------------------------------------------------------------
/Persona/Persona_logic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/Persona/Persona_logic.png
--------------------------------------------------------------------------------
/test_stored_data/feedback.txt:
--------------------------------------------------------------------------------
1 | [2021-11-10 12:11:28.482798] : BYE!!
2 | [2021-11-10 12:11:53.859025] : BYE!!
3 |
--------------------------------------------------------------------------------
/return_type_img/Text Type.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/return_type_img/Text Type.JPG
--------------------------------------------------------------------------------
/return_type_img/set_img.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/return_type_img/set_img.PNG
--------------------------------------------------------------------------------
/commerce_img/commerce_test1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/commerce_img/commerce_test1.png
--------------------------------------------------------------------------------
/commerce_img/commerce_test2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/commerce_img/commerce_test2.png
--------------------------------------------------------------------------------
/commerce_img/commerce_test3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/commerce_img/commerce_test3.png
--------------------------------------------------------------------------------
/commerce_img/commerce_test4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/commerce_img/commerce_test4.png
--------------------------------------------------------------------------------
/commerce_img/commerce_test5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/commerce_img/commerce_test5.png
--------------------------------------------------------------------------------
/commerce_img/commerce_test6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/commerce_img/commerce_test6.png
--------------------------------------------------------------------------------
/return_type_img/Carousel Type.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/return_type_img/Carousel Type.JPG
--------------------------------------------------------------------------------
/return_type_img/List Card Type.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/return_type_img/List Card Type.JPG
--------------------------------------------------------------------------------
/return_type_img/Basic Card Field.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/return_type_img/Basic Card Field.JPG
--------------------------------------------------------------------------------
/return_type_img/Basic Card Test.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/return_type_img/Basic Card Test.JPG
--------------------------------------------------------------------------------
/return_type_img/Basic Card Type.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/return_type_img/Basic Card Type.JPG
--------------------------------------------------------------------------------
/return_type_img/Simple Text Test.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/return_type_img/Simple Text Test.JPG
--------------------------------------------------------------------------------
/return_type_img/Commerce Card Field.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/return_type_img/Commerce Card Field.JPG
--------------------------------------------------------------------------------
/return_type_img/Commerce Card Type.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/HEAD/return_type_img/Commerce Card Type.JPG
--------------------------------------------------------------------------------
/test_stored_data/restaurant_menu.txt:
--------------------------------------------------------------------------------
1 | 🐾미가식당
2 | '2001-09-03', 'ㅁ ㅁ ㅁ ㅁ', 'ㄹ ㄹ ㄹ ㄹ'
3 | 🐾세미콘식당
4 | '2021-09-03', '업데이트되지않았습니다', '업데이트되지않았습니다'
5 | 🐾푸드라운지
6 | '2021-09-03', '업데이트되지않았습니다', '업데이트되지않았습니다'
7 | 🐾웰스프레쉬
8 | '2021-09-03', '업데이트되지않았습니다', '업데이트되지않았습니다'
9 |
--------------------------------------------------------------------------------
/alphaSandol/Pipfile:
--------------------------------------------------------------------------------
1 | [[source]]
2 | url = "https://pypi.org/simple"
3 | verify_ssl = true
4 | name = "pypi"
5 |
6 | [packages]
7 | requests = "*"
8 | bs4 = "*"
9 | boto3 = "*"
10 | zappa = { git = "https://github.com/zappa/Zappa.git"}
11 |
12 | [dev-packages]
13 |
14 | [requires]
15 | python_version = "3.8"
16 |
--------------------------------------------------------------------------------
/betaSandol/Pipfile:
--------------------------------------------------------------------------------
1 | [[source]]
2 | url = "https://pypi.org/simple"
3 | verify_ssl = true
4 | name = "pypi"
5 |
6 | [packages]
7 | requests = "*"
8 | bs4 = "*"
9 | boto3 = "*"
10 | troposphere = { version = "<3.0", ignore = ["zappa"] }
11 | zappa = "*"
12 |
13 | [dev-packages]
14 |
15 | [requires]
16 | python_version = "3.8"
17 |
--------------------------------------------------------------------------------
/betaSandol/zappa_settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "dev": {
3 | "profile_name": null,
4 | "project_name": "betasandol",
5 | "runtime": "python3.8",
6 | "s3_bucket": "zappa-m9m800toh",
7 | "aws_region": "ap-northeast-2",
8 | "keep_warm": false,
9 | "lambda_handler": "lambda_prototype.lambda_handler"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/alphaSandol/zappa_settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "default": {
3 | "profile_name": null,
4 | "project_name": "Kakao-Sandol",
5 | "runtime": "python3.8",
6 | "s3_bucket": "aws-sandol-bucket",
7 | "aws_region": "ap-northeast-2",
8 | "keep_warm": false,
9 | "lambda_handler": "lambda_function.lambda_handler"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: 아프지마 산돌.
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | ### Describe the bug
11 | 어떤 버그인지 간략하게 설명해주세요.
12 |
13 | ### To Reproduce
14 | 어떤 식으로 발생했는지 간략하게 적어주세요.
15 |
16 | 1. 발화블럭명
17 | 2. 발화내용
18 | 3. ...
19 | 4. See error
20 |
21 | ### Expected behavior
22 | 예상 결과
23 |
24 | ### Environment
25 | - [x] Mobile
26 | - [ ] PC
27 | - [ ] Kakao i openbuilder
28 |
29 | ### Additional context
30 | 추가적 사항을 적어주세요.
31 |
--------------------------------------------------------------------------------
/alphaSandol/Imoge.json:
--------------------------------------------------------------------------------
1 | {
2 | "emotion": {
3 | "paw": "🐾",
4 | "smile": "😺",
5 | "happy": "😸",
6 | "sad": "😹",
7 | "love": "😻",
8 | "confident": "😼",
9 | "angry": "😾",
10 | "surprise": "🙀",
11 | "walk": "🐈",
12 | "nexpression": "🐱"
13 | },
14 | "weather": {
15 | "흐림": "☁",
16 | "구름많음": "⛅",
17 | "hvy_rain": "⛈",
18 | "비": "☔",
19 | "약간흐림": "🌤",
20 | "맑음": "☀",
21 | "sun_wth_rain": "🌦",
22 | "thunder": "🌩",
23 | "바람": "🌪",
24 | "안개": "🌫"
25 | }
26 | }
--------------------------------------------------------------------------------
/.github/workflows/cd.yml:
--------------------------------------------------------------------------------
1 | name: Deploy on AWS Lambda
2 | on:
3 | push:
4 | branches:
5 | - master
6 | - main
7 |
8 | jobs:
9 | build:
10 | runs-on: ubuntu-latest
11 |
12 | steps:
13 | - name: Checkout Code
14 | uses: actions/checkout@v1
15 |
16 | - name: Set up Python 3.8
17 | uses: actions/setup-python@v1
18 | with:
19 | python-version: 3.8
20 |
21 | - name: Install Dependencies and Deploy
22 | env:
23 | AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
24 | AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
25 | run: cd alphaSandol && pip install pipenv && pipenv install && pipenv run zappa update
26 |
--------------------------------------------------------------------------------
/alphaSandol/weather.py:
--------------------------------------------------------------------------------
1 | import settings
2 | from bs4 import BeautifulSoup
3 | import requests
4 | import datetime
5 |
6 |
7 | class Weather:
8 | def __init__(self):
9 | self.URL = r"https://weather.naver.com/today/02390132"
10 |
11 | def weather(self, location: str = "정왕") -> dict:
12 | soup = BeautifulSoup(requests.get(self.URL).text, 'html.parser')
13 | weather_box = soup.select('#content > div > div.section_center > div.card.card_today > div.today_weather > div.weather_area')[0]
14 | today = weather_box.find('p', {'class': 'summary'}).text.replace('\n', ' ').strip().split(' ') # 날씨, 어제와 비교
15 | today_date = weather_box.find('i', {'class': 'ico_animation _cnLazy'})['data-ymdt']
16 | dates = datetime.datetime.strptime(today_date, '%Y%m%d%H')
17 | result = f"{dates}기준 정왕 날씨입니다\n현재날씨는 {today[0]}이고, {today[1]}"
18 | return settings.GEN.set_text(result)
19 |
20 |
21 | if __name__ == "__main__":
22 | print(Weather().weather())
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 min HEO
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.
22 |
--------------------------------------------------------------------------------
/alphaSandol/test_constant.py:
--------------------------------------------------------------------------------
1 | import json
2 | PARAM = "perm_chk"
3 | PARAM_DATA = '공지'
4 |
5 | JSON_DATA = {
6 | 'body': {
7 | "intent": {
8 | "id": "ttc0v82yotpkittnmfpq9lcy",
9 | "name": "블록 이름"
10 | },
11 | "userRequest": {
12 | "timezone": "Asia/Seoul",
13 | "params": {
14 | "ignoreMe": "true"
15 | },
16 | "block": {
17 | "id": "ttc0v82yotpkittnmfpq9lcy",
18 | "name": "블록 이름"
19 | },
20 | "utterance": "발화 내용",
21 | "lang": 'null',
22 | "user": {
23 | "id": "616332",
24 | "type": "accountId",
25 | "properties": {}
26 | }
27 | },
28 | "bot": {
29 | "id": "5e0f180affa74800014bd33d",
30 | "name": "봇 이름"
31 | },
32 | "action": {
33 | "name": "o8fhv36eao",
34 | "clientExtra": 'null',
35 | "params": {
36 | PARAM : PARAM_DATA
37 | },
38 | "id": "koow1xlhycjsjacfcqy49w6w",
39 | "detailParams": {
40 | "weather": {
41 | "origin": "정왕 날씨 궁금해",
42 | "value": "정왕 날씨 궁금해",
43 | "groupName": ""
44 | }
45 | }
46 | }
47 | }
48 | }
49 | TEST_EVENT = json.dumps(JSON_DATA)
--------------------------------------------------------------------------------
/alphaSandol/covid.py:
--------------------------------------------------------------------------------
1 | import requests
2 | import json
3 | import settings
4 |
5 |
6 | class Covid:
7 | def __init__(self):
8 | self.return_string = ""
9 |
10 | def today_covid(self) -> dict:
11 | try:
12 | url = 'https://m.search.naver.com/p/csearch/content/nqapirender.nhn?where=nexearch&pkid=9005&key=diffV2API'
13 | html = requests.get(url).text
14 | data = json.loads(html)
15 | result = f"{data['result']['baseDate'].split(' ')[0][:-1]}일까지 코로나 발생현황이에요 {settings.IMOGE('emotion', 'walk')}\n" \
16 | f"{settings.IMOGE('emotion', 'paw')}지역발생은 {data['result']['data']['dailyCnt'][-1]}명\n이며," \
17 | f"전일대비 {int(data['result']['data']['dailyCnt'][-1].replace(',','')) - int(data['result']['data']['dailyCnt'][-2].replace(',',''))}명 이에요" \
18 | f" 건강에 유의하세요!{settings.IMOGE('emotion', 'nexpression')}"
19 | # 결과 컨텍스트
20 |
21 | self.return_string = settings.GEN.set_card(settings.SANDOL_COVID_IMG, is_title="코로나 확진자 수",
22 | is_description=result)
23 |
24 | except Exception as e:
25 | description = f"코로나 확진자 정보를 불러오는데 실패했어요{settings.IMOGE('emotion', 'sad')}\n"
26 | self.return_string = settings.GEN.set_card(settings.SANDOL_COVID_IMG, is_title=f"{e}",
27 | is_description=description)
28 |
29 | finally:
30 | return self.return_string
31 |
32 |
33 | if __name__ == "__main__":
34 | print(Covid().today_covid())
--------------------------------------------------------------------------------
/alphaSandol/announcement.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from bs4 import BeautifulSoup
3 | import settings
4 |
5 |
6 | class Announcement:
7 | def __init__(self):
8 | self.URL = "https://www.kpu.ac.kr/front/boardlist.do?bbsConfigFK=1&siteGubun=14&menuGubun=1"
9 | self.ORIGIN = "https://www.kpu.ac.kr"
10 | self.TITLE = "교내 최신 학사공지 내역입니다"
11 | self.MAX_ANNOUNCEMENT_CNT = 5 # 최대 가져올 공지 수
12 | self.WEB_LINK_URL = "https://www.kpu.ac.kr/contents/main/cor/noticehaksa.html"
13 |
14 | def announce(self) -> dict:
15 | try:
16 | req = requests.get(self.URL)
17 | soup = BeautifulSoup(req.text, 'html.parser')
18 | announce_list = soup.find('table').find('tbody').find_all('tr')
19 | result = [] # title, date, URl
20 |
21 | for i in range(self.MAX_ANNOUNCEMENT_CNT):
22 | result.append(settings.ParamOption('detail_list',
23 | title=announce_list[i].find_all("td")[1].find('a').text.strip(),
24 | description=announce_list[i].find_all("td")[4].text.strip(),
25 | link=self.ORIGIN + announce_list[i].find_all("td")[1].find("a")['href']
26 | )
27 | )
28 |
29 | button = [settings.ParamOption('button', label='바로가기', action='webLink', webLinkUrl=self.WEB_LINK_URL)]
30 | return settings.GEN.set_list(self.TITLE, button, *result)
31 |
32 | except Exception as e:
33 | return settings.GEN.set_text(f"{e}")
34 |
35 |
36 | if __name__ == "__main__":
37 | print(Announcement().announce())
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 한국공학대학교 카카오톡 챗봇 산돌이
2 | ## Index
3 | - [Overview](#overview)
4 | - [Getting Started](#getting-started)
5 | - [Authors](#authors)
6 | - [Honors](#honors)
7 | - [License](#license)
8 | - [Others](#others)
9 |
10 | ## About Repository
11 |
12 | 카카오톡 챗봇 산돌이는 학생들을 위한 편의를 제공하고자 개발되었으며, 누적 5500명의 학생이 산돌이를 이용하고 있습니다.
13 | 해당 프로젝트는 카카오 i 오픈빌더를 통해 제작되었습니다. AWS Lambda를 이용한 서버리스 아키텍쳐를 활용하고 있으며, CI/CD 배포 파이프라인을 구축하기 위해 해당 레포지토리가 생성되었습니다.
14 |
15 |
16 |
17 |
18 |
19 | ## Overview
20 |
21 | **산돌이 제공 기능**
22 | - 금일 학식/외부식당 메뉴 조회
23 | - 셔틀버스 시간표 조회
24 | - 인근 전철/버스 막차시간 조회
25 | - 지역별 날씨 조회
26 | - 교내 시설 조회
27 | - 교내 유선번호 조회
28 | - 산기대학로 먹거리/즐길거리 추천
29 | - 최신 교내공지 요약
30 | - 건의 및 후원
31 |
32 | ## Getting Started
33 | **[여기](https://pf.kakao.com/_pRxlZxb)를 클릭하세요. 바로 산돌이와 대화할 수 있습니다.**
34 |
35 | ## Installing
36 | 1. https://pf.kakao.com/_pRxlZxb 링크 접속
37 | 2. 우측 상단 플러스 친구 등록하기
38 | 3. 챗봇 채팅하기 누르기
39 |
40 | ## Authors
41 | - [koptimizer](https://github.com/koptimizer) - **고광종** -
42 | 산돌팀21 총괄 및 경영
43 | - [Cycrypto](https://github.com/Cycrypto) - **박준하** -
44 | 산돌이 스킬 및 로직파트 메인개발
45 | - [hhhminme](https://github.com/hhhminme) - **허민** -
46 | 경영지원 및 프론트엔드 개발
47 |
48 | ## Honors
49 | ### "우리 대학의 빛나는 주역들 (본교 학보 509호 5면)"
50 |
51 |
52 | ## License
53 |
54 | ```
55 | MIT License
56 |
57 | Copyright (c) 2020 always0ne
58 |
59 | Permission is hereby granted, free of charge, to any person obtaining a copy
60 | of this software and associated documentation files (the "Software"), to deal
61 | in the Software without restriction, including without limitation the rights
62 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
63 | copies of the Software, and to permit persons to whom the Software is
64 | furnished to do so, subject to the following conditions:
65 |
66 | The above copyright notice and this permission notice shall be included in all
67 | copies or substantial portions of the Software.
68 |
69 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
70 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
71 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
72 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
73 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
74 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
75 | SOFTWARE.
76 | ```
77 |
78 | ## Others
79 | - [산돌팀 체제 이전 초기 레포 바로가기](https://github.com/koptimizer/kakaotalk_chatbot_sandol)
80 |
--------------------------------------------------------------------------------
/Persona/snadol_Persona.drawio:
--------------------------------------------------------------------------------
1 | 7VzbkqM2EP0aqpKHuABxkR7B9mxSlWxtMpXK7lOKAdkmi40L48w4Xx9JSAYk2WOPjWEu3ocFIQmmW336dLfAAOPl06ciWi9+yxOcGbaZPBlgYti25UOT/EdbdlWL5zlVw7xIE96pbrhP/8O8kY+bb9MEb1odyzzPynTdbozz1QrHZastKor8sd1tlmftu66jOVYa7uMoU1v/SpNyUbVC16zbf8bpfCHubJn8yjISnXnDZhEl+WOjCUwNMC7yvKyOlk9jnFHhCblU4+4OXN0/WIFX5SkDvF/+mIR/e9svn1fl54dP8e9/mruffLua5t8o2/K/mD9tuRMimBf5ds274aLETzrBRw+iu6k+mLX/c8k6wfkSl8WOdOETiRG7tuYfG+IWQl00RO0g3hhxFc/3M9dSIAdcEGcIxXGeFwqRySrBdBbTAOHjIi3x/TqK6dVHYgmkbVEuyV0nFjnclEX+HY/zLC/YaPAAXcelA2dpljXaZzDGcbwfIVYcnSMns6cllRGgAw/qoyn3Iyo/qA0A2+pArqIOC2nUYZtuR+qwntcGXiUBNXZyFmfRZpNWMoyKUm1u6KWaBycKBLxQhA0ZuRoRibYCZ1GZ/tu+qU5s/A5f8pQ8zl5DXltBEI18gjr7nzTfJt8WMeZTNOFBmvXMaYls57hUpmUK3kvk5Tp3VZ1PxwYEBrSM6YQeoLGyCogplMcMb5WvsGRzvCnK0vmKrhKid0zaQ2pYKfECAb+wTJOE3kZr6W0smOWr8p4/lFi6VzRToR4VJR2tVXZklJ5GQRMDeQZEVFNEO9B51wqyoTeyVey8qZKEK5XMKLSN0DGmIVURhXIvo1p5KMjRnB798IXcbrzMH9IM/3jE81nPez7JvyURhrNY5xG9GOKHWZeOzZdpho5naGhGZyzDU90Y8URiZeZFucjn+SrKpnWrtJLrPr/m+ZqL/B9cljtOpKNtmbcVgp/S8mvj+BudauTys8kTn5md7MTJivy9X5snjVH0tB7GzsS4y9wrkQxzXcfWN+9YOaNnGZ26NM7zxIRLRLtGhzX1fpvDjhpILtWSGfpz/RGUVln1BFf1tEKGLYwIjZAguUkPgsAIIHO+DkV1egnRY9pCLjka+GDQcsc7oVBM5BOweTtwMjg8sYCqyHfNkzWM1oUX82RXjo8kfXZMjO0Pr3Gx13BP9BrWgeV78rq8zJ71MRDB09BkLC7kLC6EBmIHgWWgyVUBdubSf1qAZT/Ophvt1a9L4LWGBryuBmc/TPI8kzRPNUm3T5MEVh+a7l76/usARF/LVBmvNKaBEVoUCukBpBB5VRyczexYSzQT78FzvVsSTeD2jHe23yfe1Rj3rXHlzeKdf6HF6UmsZZkj0Pg5sO1S/duSWguqlv2uQxc5yCChi9NMxjvtCU+NXfzzpu06lDmQnSQs1me81jGgzyjvhDFdlvaHUJtwCCjiI5f2DkyWpyAHtgFd5iHIsPHbyTx4SCLArj1SE803dQnegCiw/Uo5sKg6P+sTGrsHbpjMdOWwywfSsukgOWlrar8fyckXQITZP0T0Eju9V4g4sOPm0p0HcoHC8UaWV//80wjExdBjt6BHfUxwtH9HUGVrOCxHHwE+Gnpjs1wegR8OSFPKWfg48hz1UNl4hlFL7wzBLKutQ08NevW7kDqCL1tXXVHUyzwSJ50m9UU28y6EmxKXU6makFlkMSdE2j9UTa4A3x2WqnXb/zSW3I4v9KrWxC3vWdWeOyyr9tQ9SrcgJYJf7E8Gwi9s1C+/2O/zFY7bQiPU+EHUCb+Qb+v4x/dpKI95E36BVFSi0HInqoAmpRbvrxwop8edvtPjQEcEbw8ynYPFyVWjauX2VrPTZRmFS6Z83BOZg+7sBluJi32d3SDPB1Gn5SNPAqvey0dur+Wjl5XLa9f8reWZ9X46iTaL/Urp3A5PTgqAq+QN1Wjbkbwh8kewWVzyT3La1/KTQMPeaXnAZVViEnaxzc92VTEGtJ3H31euGA/QVTpS+cfuv3AAdJuctNoK6bZ1CtkkfoYUrN+6tgAanrZ0b32w/RaVL6UBLyu9wZAe8yQHYk4Vce9KOHyoRl1nKe9mIh9A2hzoNr2MaeIBVakFVsGo8g1U6mNeC4XsKrJ070kNVNgDWN+afQhVcah6q4nIlZeb2pJ+HQK2B7CadUGsFu73Mma1veBCGb8CuFecc//acnSh05gpyaz32VG1jVkZdUJ3YCAkYqixWn0VAZfDX0OrFIymRsBoGPRYIvWdaXoAwOfo6uyKY7eFjQZVetuhaDhM7FNk3L81uSe8n7NZRGt6GG+LbBcWUfydRnTPSbEtcvXTAZpqwa2+JiDHhlo12Bo1AOiPuvqggKcJOpSUhG674QBy+C/eHXSbjYtKalw899lbFcFBd3ijRIKnC3ZYXbfGxKpm7zZ2EwHOXlDAvdz1fVqvG4t6Th56unCoyUQCSiUOS/uNfazF6l0f+oipJoQs7O/cJHp9P6N3HeiCKgJUd+J1GNcIxjxvdmmwOqDCBuhb7r4uPKo2p0LhF6DYkX4MlN5IWNO3PgBQWdwwC0u3LRCdXKi9uEB0mTl1952v+t0xv/nymHlUSYeqf3vCf4DhKyZ5d9cyvSFo+tD3UG4TJAApKgRAgoRTgwQlwwmlia60QQgA/QMfei5H2tEo9T93gxA5rT8TWXWvP7YJpv8D
--------------------------------------------------------------------------------
/alphaSandol/settings.py:
--------------------------------------------------------------------------------
1 | import os
2 | import json
3 |
4 | # 리턴 타입
5 | from return_type_generator import ReturnType, ParamOption
6 |
7 | GEN = ReturnType() # kakao-i type json generator
8 | ParamOption = ParamOption
9 |
10 | # Settings
11 | _PATH = os.path.abspath(os.path.dirname(__file__)) # 프로젝트 절대경로
12 | DEBUG = False # True 일때 디버그 모드 작동
13 |
14 | # BUCKET
15 | BUCKET_NAME: str = 'aws-sandol-bucket'
16 |
17 | RESTAURANT_MENU: str = "restaurant_menu.txt" # 학식이 저장된 파일 이름 (Bucket)
18 | LOCAL_RESTAURANT_MENU: str = "/tmp/" + RESTAURANT_MENU # 람다 서버의 해당 디렉토리에 불러옴
19 |
20 | FEEDBACK_FILE: str = "feedback.txt" # 피드백이 저장된 파일 이름
21 | LOCAL_FEEDBACK_FILE: str = "/tmp/" + FEEDBACK_FILE # 람다 서버 tmp 디렉토리에 불러와 실행
22 |
23 | # Access Token
24 | SANDOL_ACCESS_ID: dict = {'MANAGER': "d367f2ec55f41b4207156f4b8fce5ce885b05d8c3b238cf8861c55a9012f6f5895",
25 | 'CONT1': "339b0444bfabbffa0f13508ea7c45b61675b5720234cca8f73cd7421c22de9e546",
26 | 'CONT2': "04eabc8b965bf5ae6cccb122a18521969cc391162e3fd5f61b85efe8bb12e5e98a",
27 | 'CONT3': "def99464e022b38389697fe68d54bbba723d1da291094c19bbf5eaace7b059a997",
28 | 'MINJU': "1ddffbb02b29a6beb212d2f6fe2469523b9a90f260344b9d30677abcd977e1b56c",
29 | 'YURIM': "16b3777b75026553a1807d1f361773e080e6441d30c65ea6e89dd0b84c9b58f071",
30 | 'HAMIN': "c0657ad2b0ade045e546d8abb33f45d85f3c826ce797800e0bf25aac0652bf175c",
31 | 'JDONG' : "cbdb6ec7c1427fd603a9c87ee5a1f7d1cc948ca896a2d65f88c770aa742218cef0"
32 | }
33 | # 산돌팀만 접근할 수 있는 컨텐츠에 인증 수단으로 사용 (현재 아이디의 정확한 위치가 기억이 나지 않아.. KEY를 메니저와, CONTRIBUTOR로 명명함.)
34 |
35 | RESTAURANT_ACCESS_ID: dict = {'미가식당': "32d8a05a91242ffb4c64b5630ec55953121dffd83a121d985e26e06e2c457197e6",
36 | '세미콘식당': "380da59920b84d81eb8c444e684a53290021b38f544fe0029f4b38ab347bc44e08",
37 | '푸드라운지': "46f338132e6af63c32c07220c318f0e7c570e8eb6f375c9e8bb59ce33776f27c4c",
38 | '웰스프레쉬': "...",
39 | }
40 |
41 | # Urls
42 | SANDOL_CATEGORY_1: str = "https://github.com/hhhminme/kpu_sandol_team/blob/06916e07fe02d36d3384dfe96c8d2dc4cb300aa7/img/card1.png" # 인기 메뉴
43 | SANDOL_CATEGORY_2: str = "https://github.com/hhhminme/kpu_sandol_team/blob/06916e07fe02d36d3384dfe96c8d2dc4cb300aa7/img/card2.png" # 놀거리
44 | SANDOL_CATEGORY_3: str = "https://github.com/hhhminme/kpu_sandol_team/blob/06916e07fe02d36d3384dfe96c8d2dc4cb300aa7/img/card3.png" # 교내 정보
45 | SANDOL_CATEGORY_4: str = "https://github.com/hhhminme/kpu_sandol_team/blob/main/img/card_other.png" # 기타 기능
46 | SANDOL_COVID_IMG: str = "https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/main/img/card_covid.png" # 코로나
47 | SANDOL_RSTRNT_FOOD_IMG: str = "https://github.com/hhhminme/kpu_sandol_team/blob/main/img/card_food.png" # 푸드라운지
48 | SANDOL_RSTRNT_MIGA_IMG: str = "https://github.com/hhhminme/kpu_sandol_team/blob/main/img/card_miga.png" # 미가식당
49 | SANDOL_RSTRNT_MAP: str = "https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/main/img/meal_map.png" # 식당지도
50 | SANDOL_LOGO1: str = "https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/main/img/logo1.png" # 산돌이 로고 (필요시 사용)
51 | SANDOL_PROFILE1: str = "https://github.com/hhhminme/kpu_sandol_team/blob/main/img/logo_profile1.png" # 산돌이 프로필 (필요시 사용)
52 |
53 |
54 | # Others
55 | def IMOGE(category, key): # 이모지를 불러올
56 | with open(rf"{_PATH}/Imoge.json", encoding='UTF-8') as imo:
57 | data = json.load(imo)
58 | return data[category][key]
59 |
60 |
61 | def DEBUGGING(msgtype, sender, msg): # 디버깅시 사용할 함수
62 | if DEBUG is False:
63 | pass
64 |
65 | else:
66 | if msgtype == 'debug':
67 | return f"from {sender} : {msg}"
68 |
69 | elif msgtype == 'error':
70 | return f"error from {sender} : {msg}"
71 |
72 | else:
73 | return DEBUGGING("error", "init.DEBUGGING", "호출형식이 잘못되었습니다")
74 |
--------------------------------------------------------------------------------
/alphaSandol/feedback.py:
--------------------------------------------------------------------------------
1 | import boto3
2 | import settings
3 | import datetime
4 |
5 |
6 |
7 | class Feedback:
8 | def __init__(self):
9 | if not settings.DEBUG: # 디버그모드가 아닌경우 S3를 import함
10 | self.S3 = boto3.resource('s3')
11 | self.S3_client = boto3.client('s3')
12 | self.bucket = self.S3.Bucket(settings.BUCKET_NAME)
13 |
14 | self.data = ""
15 |
16 | def upload_feedback(self, data):
17 | self.data = f"[{str(datetime.datetime.today())}] : {data}\n"
18 | if not settings.DEBUG:
19 | try:
20 | self.bucket.download_file(settings.FEEDBACK_FILE, settings.LOCAL_FEEDBACK_FILE)
21 |
22 | except Exception as e:
23 | return settings.GEN.set_text(
24 | f"[File-Open-Error #101] 서버에서 피드백 파일을 불러오는 중 오류가 발생했어요{settings.IMOGE('emotion', 'sad')}\n{e}")
25 |
26 | try:
27 | with open(settings.LOCAL_FEEDBACK_FILE, "a", encoding="UTF-8") as f:
28 | f.writelines(self.data)
29 |
30 | except Exception as e:
31 | return settings.GEN.set_text(
32 | f"[File-Open-Error #102] 파일을 저장 중 오류가 발생했습니다{settings.IMOGE('emotion', 'sad')}\n{e}")
33 |
34 | try:
35 | self.S3_client.upload_file(settings.LOCAL_FEEDBACK_FILE, settings.BUCKET_NAME, settings.FEEDBACK_FILE)
36 |
37 | except Exception as e:
38 | return settings.GEN.set_text(
39 | f"[File-Open-Error #103] 파일을 서버에 업로드 하는 중 오류가 발생했습니다{settings.IMOGE('emotion', 'sad')}\n{e}")
40 |
41 | else: # 디버그 모드일때 발생하는 분기
42 | with open("../test_stored_data/feedback.txt", "a", encoding='UTF-8') as f:
43 | f.writelines(self.data)
44 |
45 | return settings.GEN.set_text(f"피드백 주셔서 감사해요! 빠른 시일내에 검토 후 적용해볼게요!{settings.IMOGE('emotion','love')}")
46 |
47 | def read_feedback(self, uid):
48 | if uid not in (settings.SANDOL_ACCESS_ID.values()):
49 | return settings.GEN.set_text("권한이 없습니다")
50 |
51 | if not settings.DEBUG:
52 | try:
53 | self.bucket.download_file(settings.FEEDBACK_FILE, settings.LOCAL_FEEDBACK_FILE)
54 |
55 | except Exception as e:
56 | settings.GEN.set_text(f"[File-Open-Error #111] 서버에서 피드백 파일을 불러오는 중 오류가 발생했어요\n{e}")
57 |
58 | try:
59 | with open(settings.LOCAL_FEEDBACK_FILE, 'r', encoding='UTF-8') as f:
60 | txt = ''.join(f.readlines())
61 |
62 | except Exception as e:
63 | return settings.GEN.set_text(f"[File-Open-Error #112] 파일을 읽는 중 오류가 발생했습니다\n{e}")
64 |
65 | return settings.GEN.set_text(txt)
66 |
67 | else: # 디버그 모드일때 발생하는 분기
68 | with open("../test_stored_data/feedback.txt", encoding='UTF-8') as f:
69 | txt = ''.join(f.readlines())
70 | return settings.GEN.set_text(txt)
71 |
72 | def delete_feedback(self, uid):
73 | if uid not in (settings.SANDOL_ACCESS_ID.values()):
74 | return settings.GEN.set_text("권한이 없습니다")
75 |
76 | basic_text = "#feedbacks\n"
77 | if not settings.DEBUG:
78 | try:
79 | self.bucket.download_file(settings.FEEDBACK_FILE, settings.LOCAL_FEEDBACK_FILE)
80 | except Exception as e:
81 | return settings.GEN.set_text(f"[File-Open-Error #113] 서버에서 피드백 파일을 불러오는 중 오류가 발생했어요\n{e}")
82 |
83 | try:
84 | with open(settings.LOCAL_FEEDBACK_FILE, 'w', encoding="UTF-8") as f:
85 | f.writelines(basic_text)
86 |
87 | except Exception as e:
88 | return settings.GEN.set_text(f"[File-Open-Error #114] 파일 데이터를 삭제 중 오류가 발생했습니다{e}")
89 |
90 | try:
91 | s3 = boto3.client('s3')
92 | s3.upload_file(settings.LOCAL_FEEDBACK_FILE, settings.BUCKET_NAME, settings.FEEDBACK_FILE)
93 |
94 | except Exception as e:
95 | return settings.GEN.set_text(f"[File-Open-Error #115] 파일을 서버에 업로드 하는 중 오류가 발생했습니다{e}")
96 |
97 | else: # 디버그 모드일때
98 | with open("../test_stored_data/feedback.txt", "w", encoding='UTF-8') as f:
99 | f.writelines(basic_text)
100 |
101 | return settings.GEN.set_text("성공적으로 파일 내용을 삭제했습니다")
102 |
--------------------------------------------------------------------------------
/betaSandol/lambda_prototype.py:
--------------------------------------------------------------------------------
1 | import json
2 | import lambda_prototype_module as Module
3 | import return_type_generator as Generator
4 | import base64
5 |
6 | def lambda_handler(event, context):
7 | return_string = None
8 | try:
9 | request_body = event['body']
10 | request_body = json.loads(base64.b64decode(request_body))
11 | param = request_body['action']['params']
12 | key = list(param.keys()) # 입력으로 들어오는 값을 여기서 처리함
13 | # 여러개 들어오는 경우 필수 파라미터 명이 key[0]에 들어감
14 | if key[0] == 'weather': #날씨 관련
15 | return_string = Module.CrawlingFunction.weather(Module.CrawlingFunction, param[key[0]])
16 |
17 | elif key[0] == 'covid':
18 | return_string = Module.CrawlingFunction.today_covid(Module.CrawlingFunction)
19 |
20 | elif key[0] == 'feedback_upload':
21 | return_string = Module.s3IOEvent.upload_feedback(Module.CrawlingFunction, params=str(param[key[0]]))
22 |
23 | elif key[0] == 'read_feedback':
24 | return_string = Module.s3IOEvent.read_feedback(Module.CrawlingFunction, params=str(param[key[0]]), bot_id=str(request_body['userRequest']['user']['properties']['botUserKey']))
25 |
26 | elif key[0] == 'perm_chk':
27 | return_string = request_body['userRequest']['user']['id']
28 |
29 | elif key[0] == 'store_name':
30 | return_string = Module.s3IOEvent.upload_meal(Module.s3IOEvent, param[key[0]],param[key[1]], param[key[2]],json.loads( param[key[3]])['date'], str(request_body['userRequest']['user']['properties']['botUserKey']))
31 |
32 | elif key[0] == 'read_meal':
33 | return_string = Module.s3IOEvent.read_meal(Module.s3IOEvent)
34 |
35 | elif key[0] == "reset_meal":
36 | return_string = Module.s3IOEvent.reset_meal(Module.s3IOEvent, str(request_body['userRequest']['user']['properties']['botUserKey']), json.loads(param[key[0]])['date'])
37 |
38 | elif key[0] == 'subway':
39 | gen = Generator.Return_Type()
40 | try:
41 | setting_time = str(json.loads(request_body['action']['detailParams']['date_time']['value'])['time'])
42 | return_string = "[4호선]\n" + Module.Test(time = setting_time).arrival_time() + "\n\n[수인분당선]\n"
43 | return_string += Module.Test(time = setting_time, station_no="11120").arrival_time()
44 | return_string = gen.set_text(return_string)
45 |
46 | except Exception as e:
47 | return_string = gen.set_text(str(e))
48 |
49 | elif key[0] == "ann":
50 | # return_string = Module.CrawlingFunction.subway(Module.CrawlingFunction)
51 | return_string = Module.CrawlingFunction.announcement(Module.CrawlingFunction)
52 |
53 | elif key[0] == 'last_subway':
54 | return_string = Module.CrawlingFunction.last_subway(Module.CrawlingFunction)
55 |
56 | elif key[0] == "param1":
57 | g = Generator.Return_Type()
58 | try:
59 | for i in range (1,3):
60 | g.set_text("str"+str(i), is_init=False)
61 | return_string = g.set_text("str3", is_init=False)
62 | except Exception as e:
63 | return_string = str(e)
64 |
65 |
66 |
67 |
68 | else:
69 | raise Exception("산돌이가 작업을 마무리하지 못했어요ㅠㅠ\n 피드백을 통해 어떤 기능에서 오류가 발생했는지 알려주시면 빠른 시일 내에 작동 하도록 할게요")
70 |
71 |
72 | except Exception as e:
73 | return_string = {
74 | "version": "2.0",
75 | "template": {
76 | "outputs": [
77 | {
78 | "simpleText": {
79 | "text": "[Main Function Error]"+str(e)
80 | }
81 | }
82 | ],
83 | "quickReplies" : [
84 | {
85 | "messageText" : "도움말",
86 | "action" : "message",
87 | "label" : "도움말"
88 | }
89 | ]
90 | }
91 | }
92 |
93 | return {
94 | 'statusCode': 200,
95 | 'body': json.dumps(return_string),
96 | 'headers': {
97 | 'Access-Control-Allow-Origin': '*',
98 | }
99 | }
100 |
101 |
--------------------------------------------------------------------------------
/Return Type Generator.md:
--------------------------------------------------------------------------------
1 | # return_type_generator.py
2 |
3 | ## OverView
4 |
5 | * 카카오 오픈빌더의 각 타입에 들어가는 인자 값을 함수의 파라미터로 받아 자동으로 리턴 값을 생성해주는 Python 코드
6 | * 총 6종류의 JSON 형식을 지원함
7 | * Simple Text : 간단한 텍스트 타입
8 | * Simple Image : 간단한 이미지 타입
9 | * Basic Card : 기본 카드형 타입
10 | * Commerce Card : 제품 소개등을 할 때 사용하는 카드형 타입
11 | * List Card : 표현하고자 하는 대상이 다수일 때 효과적으로 사용하는 카드형 타입
12 | * Carousel : 여러 장의 카드를 하나의 메시지에 일렬로 포함하는 타입
13 |
14 |
15 |
16 | ## Usage of Basic Type
17 |
18 | ### Simple Text
19 |
20 |
21 |
22 |
23 |
24 | ```Python
25 | def is_Text(self, text):
26 | ```
27 |
28 | **필수 파라미터**
29 |
30 | > text\ : 출력할 string을 입력으로 받음
31 |
32 |
33 |
34 | **사용 예시**
35 |
36 | ```python
37 | import return_type_generator as Generator
38 | gen = Generator()
39 | result = gen.is_Text("<날씨 스킬 파트 실행>")
40 | ```
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | ### Basic Card
49 |
50 |
51 |
52 |
53 |
54 | ```python
55 | def is_Card(self,thumb_img, Button(), is_title = None, is_description = None):
56 | ```
57 |
58 |
59 |
60 |
61 | **필수 파라미터**
62 |
63 | > thumb_img \ : img의 주소를 `string` 형태로 전달
64 |
65 |
66 |
67 | **선택 파라미터**
68 |
69 | > Button() \ : button 을 생성하는 dictionary(JSON) 형태로 전달.
70 | >
71 | > is_title \ : 카드의 제목을 문자열 형태로 전달
72 | >
73 | > is_description \ : 카드에 대한 설명을 문자열 형태로 전달
74 |
75 |
76 |
77 | **사용 예시**
78 |
79 | ```python
80 | import return_type_generator as Generator
81 | gen = Generator()
82 | result = gen.is_Card("https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/main/img/logo1.png", is_title="logo", is_description = "<코로나 스킬 파트 실행>")
83 | ```
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 | ### Commerce Card
92 |
93 | ```Python
94 | def is_commerce(self,thumbnail, description, price, currency, Button(), is_discount = None, is_discountRate = None, is_discountedPrice = None, profile = None):
95 | ```
96 |
97 |
98 |
99 | **필수 파라미터**
100 |
101 | > description \ : 판매 항목의 설명을 문자열 형태로 전달
102 | >
103 | > price \ : 제품의 가격을 문자열 형태로 전달
104 | >
105 | > currency \ : 제품 가격의 통화를 전달합니다 (`won`만 가능)
106 | >
107 | > thumbnail \ : 썸네일 이미지 URL을 전달합니다.
108 | >
109 | > Button() : 기본적으로 `구매하기` 버튼이 생성되며, 추가 버튼을 전달합니다 (최대 2개)
110 |
111 |
112 |
113 | **선택 파라미터**
114 |
115 | > is_discount \ : 제품의 할인한 금액을 전달합니다.
116 | >
117 | > is_discountRate \ : 제품의 가격에 대한 할인된 가격의 비율을 전달합니다.
118 | >
119 | > is_discountPrice\ : 제품의 가격에 대한 할인가(할인된 가격)을 전달합니다.
120 | >
121 | > profile : 제품을 판매하는 프로필 정보를 전달합니다.
122 |
123 |
124 | ### List Card
125 | ```Python
126 | def is_List(self, title, data, is_Button = None):
127 | ```
128 | **필수 파라미터**
129 |
130 | > title : 리스트 최 상단에 노출 될 제목
131 | > data : 리스트에 들어갈 값, [title, subtitle, link]의 형태를 가진 리스트가 들어가야함.
132 |
133 |
134 |
135 | **선택 파라미터**
136 |
137 | > is_Button : 버튼 타입 파라미터가 들어가야함.
138 |
139 |
140 |
141 |
142 | ## Usage of Parameter Type
143 |
144 | ### Button
145 |
146 | ```python
147 | def Button(self, **kwargs):
148 | ```
149 |
150 | * **Kwargs** 에 들어갈 내용
151 |
152 | > `'label'` : 버튼에 들어가는 내용 (필수)
153 | >
154 | > `'action'` : 버튼 클릭시 수행되는 작업 (필수)
155 | >
156 | > `'webLinkUrl'`
157 | >
158 | > `'messageText'`
159 | >
160 | > `'phoneNumber'`
161 | >
162 | > `'blockId'`
163 |
164 |
165 |
166 | * **action** 종류
167 |
168 | > - `webLink`: 웹 브라우저를 열고 webLinkUrl 의 주소로 이동합니다.
169 | > - `message`: 사용자의 발화로 messageText를 실행합니다. (바로가기 응답의 메세지 연결 기능과 동일)
170 | > - `phone`: phoneNumber에 있는 번호로 전화를 겁니다. `ex) 010-0000-1234`
171 | > - `block`: blockId를 갖는 블록을 호출합니다. (바로가기 응답의 블록 연결 기능과 동일)
172 | > - messageText가 있다면, 해당 messageText가 사용자의 발화로 나가게 됩니다.
173 | > - messageText가 없다면, button의 label이 사용자의 발화로 나가게 됩니다.
174 | >
175 | > - `share`: 말풍선을 다른 유저에게 공유합니다. share action은 특히 케로셀을 공유해야 하는 경우 유용합니다.
176 |
177 |
178 |
179 | **사용 예시**
180 |
181 | ```python
182 | try:
183 | a = gen.is_Card("https://avatars.githubusercontent.com/u/25563122?v=4",
184 | opt.button(label="Test", action="webLink", webLinkUrl="https://github.com/Cycrypto"),
185 | is_description="Button Test2")
186 | except Exception as e:
187 | a = gen.is_Card("https://avatars.githubusercontent.com/u/25563122?v=4", is_description=str(e))
188 |
189 | return a
190 | ```
191 |
192 |
193 |
194 |
--------------------------------------------------------------------------------
/alphaSandol/test_block.py:
--------------------------------------------------------------------------------
1 | from return_type_generator import (ReturnType, ParamOption)
2 |
3 |
4 | def text_test(): # set_text 예시
5 | Gen = ReturnType()
6 | text_list = ["안녕!", "내 이름은 산돌이!", "만나서 반가워"]
7 | for txt in text_list:
8 | Gen.set_text(txt, is_init=True)
9 | return Gen
10 |
11 |
12 | def commerce_test(): # set_commerce 예시
13 | import random
14 | # 1~5 산돌 분식, 6 산돌 카페
15 | commerce_image = [
16 | f'https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/main/commerce_img/commerce_test{x}.png'
17 | for x in range(1, 7)]
18 | choice = random.choice(commerce_image)
19 |
20 | Gen = ReturnType()
21 |
22 | return Gen.set_commerce(
23 | ParamOption('thumbnail', img_url=choice, link=ParamOption("link", url="https://naver.me/FMA7h2K7")),
24 | # thumbnail
25 | "산돌분식을 방문하여 해당 광고를 보여주시면 해당 메뉴의 할인이 적용됩니다.", # description
26 | 4000, # price
27 | ParamOption('button', label="네이버 플레이스 연결", action="webLink", webLinkUrl="https://naver.me/FMA7h2K7"),
28 | ParamOption('button', label="네이버 플레이스 연결", action="webLink", webLinkUrl="https://naver.me/FMA7h2K7"),
29 | ParamOption('button', label="전화하기", action="phone", webLinkUrl="010-4183-2998"),
30 | ParamOption('button', label="공유하기", action="share"), # buttons
31 | is_discount=500, # discount
32 | profile=ParamOption('profile', imageUrl=choice, nickname="산돌분식"), # profile
33 | )
34 |
35 |
36 | def card_test(): # set_card
37 | Gen = ReturnType()
38 | THUMBNAIL = r"https://github.com/teamSANDOL/kpu_sandol_team/blob/main/return_type_img/Basic%20Card%20Test.JPG?raw=true"
39 | buttons = [
40 | ParamOption('button', label='label1'),
41 | ParamOption('button', label='label2'),
42 | ParamOption('button', label='label3'),
43 | ]
44 | return Gen.set_card(THUMBNAIL, *buttons, is_title="테스트!", is_description="산돌이 카드 테스트")
45 |
46 |
47 | def image_test(): # set_image
48 | Gen = ReturnType()
49 | URL = r"https://github.com/hhhminme/kpu_sandol_team/blob/main/img/logo1.png?raw=true"
50 | return Gen.set_image(URL, text="산돌이 로고 이미지입니다!")
51 |
52 |
53 | def carousel_test():
54 | Gen = ReturnType()
55 | return Gen.set_carousel("basicCard",
56 | Gen.set_card("THUMB1", "THUMB_IMG",
57 | ParamOption('button', label="button1", action="messageText"),
58 | ParamOption('button', label="button2", action="messageText"),
59 | ParamOption('button', label="button3", action="messageText"),
60 | is_carousel=True
61 | ),
62 | Gen.set_card("THUMB2", "THUMB_IMG",
63 | ParamOption('button', label="button1", action="messageText"),
64 | ParamOption('button', label="button2", action="messageText"),
65 | ParamOption('button', label="button3", action="messageText"),
66 | is_carousel=True
67 | ),
68 | Gen.set_card("THUMB3", "THUMB_IMG",
69 | ParamOption('button', label="button1", action="messageText"),
70 | ParamOption('button', label="button2", action="messageText"),
71 | ParamOption('button', label="button3", action="messageText"),
72 | is_carousel=True
73 | )
74 | )
75 |
76 |
77 | def list_test():
78 | Gen = ReturnType()
79 | buttons = [
80 | ParamOption('button', label='button1', webLinkUrl='https://www.naver.com')
81 | ]
82 | return Gen.set_list("Header Title",
83 | buttons,
84 | ParamOption('detail_list', title='item title1', description='item description1',
85 | imageUrl='test.jpg'),
86 | ParamOption('detail_list', title='item title2', description='item description2',
87 | imageUrl='test.jpg'),
88 | ParamOption('detail_list', title='item title3', description='item description3',
89 | imageUrl='test.jpg'),
90 | ParamOption('detail_list', title='item title4', description='item description4',
91 | imageUrl='test.jpg'),
92 | ParamOption('detail_list', title='item title5', description='item description5',
93 | imageUrl='test.jpg'),
94 | )
95 |
96 |
97 | if __name__ == "__main__":
98 | import pprint
99 |
100 | print(list_test())
101 |
--------------------------------------------------------------------------------
/alphaSandol/main.py:
--------------------------------------------------------------------------------
1 | if __name__ == '__main__':
2 | # main 파일을 엔트리포인트로 사용할 경우, path에 폴더 경로를 추가해 절대 경로로 임포트가 가능하게 함
3 | from sys import path
4 | import os
5 |
6 | path.append(os.path.dirname(__file__))
7 |
8 | import json
9 | import base64
10 | import settings
11 | from settings import DEBUGGING as debugging
12 |
13 |
14 |
15 | def lambda_handler(event, context):
16 | try:
17 | if settings.DEBUG:
18 | req = "None" # request body
19 | func = "feedback_upload" # 테스트할 함수
20 | params = ["BYE!!"] # 파라미터
21 | params = {func: params[0]}
22 | access_id = 'd367f2ec55f41b4207156f4b8fce5ce885b05d8c3b238cf8861c55a9012f6f5895' # 접근 ID
23 |
24 | return_json = function_handler(func, req, params, access_id)
25 |
26 | else:
27 | request_body = event['body']
28 | request_body = json.loads(base64.b64decode(request_body)) # base64로 디코딩해야 제대로된 값을 받음
29 |
30 | param = request_body['action']['params'] # request json 접근용
31 | key = list(param.keys())
32 | func = key[0] # 함수 호출시 사용할 값
33 | ACCESS_ID = str(request_body['userRequest']['user']['id']) # 접근 권한을 가진 ID 확인용
34 | return_json = function_handler(func, request_body, param, ACCESS_ID)
35 |
36 |
37 | except Exception as e:
38 | return_json = {
39 | "version": "2.0",
40 | "template": {
41 | "outputs": [
42 | {
43 | "simpleText": {
44 | "text": f"{settings.DEBUGGING('debug', 'main.lambda_handler', e)}"
45 | }
46 | }
47 | ],
48 | "quickReplies": [
49 | {
50 | "messageText": "도움말",
51 | "action": "message",
52 | "label": "도움말"
53 | }
54 | ]
55 | }
56 | }
57 |
58 | return return_json
59 |
60 |
61 | def function_handler(func, req, param, access_id):
62 | vals = list(param.values()) # 함수에 파라미터에 사용할 값
63 | return_json = ''
64 | if func == 'weather': # 날씨 관련
65 | from weather import Weather
66 | return_json = Weather().weather()
67 |
68 | elif func == "covid": # 코로나 관련
69 | from covid import Covid
70 | return_json = Covid().today_covid()
71 |
72 | elif func == "feedback_upload" or func == "read_feedback": # 피드백 관련
73 | from feedback import Feedback
74 | feedback_class = Feedback()
75 |
76 | if func == "feedback_upload":
77 | return_json = feedback_class.upload_feedback(vals[0])
78 |
79 | elif func == "read_feedback":
80 | if str(vals[0]) == '2': # 삭제
81 | return_json = feedback_class.delete_feedback(access_id)
82 |
83 | else: # 접근
84 | return_json = feedback_class.read_feedback(access_id)
85 |
86 |
87 | elif func in ["store_name", "read_meal", "reset_meal", "time_meal", "payment_meal"]:
88 | import restaurant
89 | meal_class = restaurant.AboutMeal()
90 |
91 | if func == "store_name": # 학식 업로드
92 | upload_date = json.loads(vals[3])['date']
93 | return_json = meal_class.upload_meal(vals[0], vals[1], vals[2], upload_date, access_id)
94 |
95 | elif func == "read_meal": # 식단 읽기
96 | return_json = meal_class.read_meal(access_id)
97 |
98 | elif func == "reset_meal": # 학식 초기화
99 | upload_date = json.loads(vals[3])['date']
100 | return_json = meal_class.reset_meal(access_id, upload_date)
101 |
102 | elif func == "time_meal": # 영업시간
103 | return_json = restaurant.time_meal()
104 |
105 | else: # 결제 시스템 (사용에 어려울 수도 있음 => kakao pay 송금 제한)
106 | return_json = restaurant.payment_meal()
107 |
108 | elif func == "ann": # 공지사항
109 | from announcement import Announcement
110 | return_json = Announcement().announce()
111 |
112 | elif func in ["subway", "last_subway"]:
113 | import subway
114 | if func == "subway":
115 | time = json.loads(req['action']['detailParams']['date_time']['value'])['time']
116 | return_json = subway.LiveSubwayTraffic().get_string(time)
117 |
118 | else:
119 | return_json = subway.LastTraffic().real_time_traffic()
120 |
121 | elif func == "commerce":
122 | import test_block
123 | return_json = test_block.commerce_test() # 원래 기능
124 | # return_json = test_block.image_test()
125 | # return_json = test_block.card_test()
126 |
127 | elif func == "perm_chk":
128 | from return_type_generator import ReturnType as GEN
129 | return_json = GEN().set_text(access_id)
130 |
131 | else:
132 | from return_type_generator import ReturnType as GEN
133 | GEN().set_text(text=debugging("error", "main.function_handler", "전달된 파라미터가 잘못되었습니다."))
134 |
135 | return {
136 | 'statusCode': 200,
137 | 'body': json.dumps(return_json, ensure_ascii=False),
138 | 'headers': {
139 | 'Access-Control-Allow-Origin': '*',
140 | }
141 | }
142 |
143 | # if __name__ == "__main__": # Deploy 할때 무조건 주석처리 하기
144 | # import pprint
145 | # func_call: json = lambda_handler("event", "context")
146 | # pprint.pprint(func_call) # 디버깅용 함수 호출
147 | # print(json.loads(func_call['body'])) # json 유니코드 -> UTF 확인용
148 |
--------------------------------------------------------------------------------
/alphaSandol/return_type_generator.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 | type_check = lambda x, y: type(x) == y
4 |
5 |
6 | def init_json():
7 | return {
8 | "version": "2.0",
9 | "template": {
10 | "outputs": [
11 | ],
12 | "quickReplies": [
13 | {
14 | "messageText": "도움말",
15 | "action": "message",
16 | "label": "도움말"
17 | }
18 | ]
19 | }
20 | }
21 |
22 |
23 | def ParamOption(param_type, **kw):
24 | def button(**kwargs):
25 | data = {}
26 | params = ['label', 'action', 'webLinkUrl', 'messageText', 'phoneNumber', 'blockId']
27 | for item in kwargs.items():
28 | if item[0] not in params:
29 | data.clear()
30 | break
31 | data[item[0]] = item[1]
32 |
33 | return data
34 |
35 | def link(url):
36 | return {
37 | 'web': url
38 | }
39 |
40 | def thumbnail(img_url, **kwargs):
41 | data = {'imageUrl': img_url}
42 | param = ['link'] # 'fixedRatio', 'width', 'height' 옵션은 제작하지 않음, 추후 필요한경우 제작하여 사용
43 | print(kwargs.keys())
44 | for key in kwargs.keys():
45 | if key in param:
46 | data[key] = kwargs[key]
47 | return data
48 |
49 | def profile(nickname, imageUrl=None):
50 | result = {
51 | 'nickname': nickname,
52 | }
53 | if imageUrl is not None:
54 | result["imageUrl"] = imageUrl
55 |
56 | return result
57 |
58 | def detail_list(**kwargs):
59 | param = ['title', 'description', 'imageUrl']
60 | result = {}
61 | if 'link' in kwargs.keys():
62 | result['link'] = ParamOption('link', url=kwargs['link']) # 링크가 있는 경우
63 |
64 | for key in kwargs.keys(): # 나머지 파라미터 적용
65 | if key in param:
66 | result[key] = kwargs[key]
67 | return result
68 |
69 | return locals()[param_type](**kw)
70 |
71 |
72 | class ReturnType: # 리턴 타입별 JSON 형식을 만드는 곳 입니다.
73 | def __init__(self, reply_json: dict = None):
74 | self.return_json = init_json()
75 | if reply_json is not None:
76 | self.return_json['template']['quickReplies'].append(reply_json)
77 |
78 | def set_text(self, text, is_init=True): # 텍스트 형식
79 | if is_init:
80 | self.return_json = init_json() # 이전에 들어간 텍스트가 유지될건지 여부
81 | basic_text = {
82 | "simpleText": {
83 | "text": str(text)
84 | }
85 | }
86 | self.return_json["template"]["outputs"].append(basic_text)
87 | return self.return_json
88 |
89 | def set_card(self, thumb_img, *is_buttons, is_title=None, is_description=None, is_carousel=False): # 카드 형식
90 | self.return_json = init_json()
91 | basic_card = {
92 | "thumbnail": {
93 | "imageUrl": thumb_img
94 | }
95 | }
96 |
97 | try:
98 | if is_title is not None:
99 | basic_card["title"] = is_title # 타이틀 입력
100 |
101 | if is_description is not None:
102 | basic_card["description"] = is_description # 설명 입력
103 |
104 | if 0 < len(is_buttons) <= 3:
105 | basic_card.update({"buttons": list(is_buttons)})
106 |
107 | if is_carousel: # flag 가 True이면 Card Json만 반환하지만, False이면 return 해야하는 기본 JSON도 포함이 된다.
108 | return basic_card
109 |
110 | else:
111 | self.return_json["template"]["outputs"].append({"basicCard": basic_card}) # 위 정보들을 return_json에 입력
112 | return self.return_json
113 |
114 | except Exception as e: # 오류 발생시 오류 코드 리턴
115 | basic_card["description"] = "error :" + str(e)
116 | self.return_json["template"]["outputs"].append({"basicCard": basic_card})
117 | return self.return_json
118 |
119 | def set_image(self, src, text=None, is_init=True): # 이미지 반환 형식
120 | if is_init:
121 | init_json()
122 |
123 | basic_image = {
124 | "simpleImage": {
125 | "imageUrl": src,
126 | }
127 | }
128 |
129 | if text is not None:
130 | basic_image["simpleImage"]["altText"] = text
131 |
132 | self.return_json["template"]["outputs"].append(basic_image)
133 | return self.return_json
134 |
135 | def set_commerce(self, thumbnail, description, price, *is_buttons, currency="won", is_discount=None,
136 | is_discountRate=None, is_discountedPrice=None, profile=None, is_carousel=False): # 커머스 반환 형식
137 | commerce_card = {
138 | "commerceCard": {
139 | "description": description,
140 | "price": price,
141 | "currecy": currency,
142 | "thumbnails": [
143 |
144 | ]
145 | }
146 | }
147 | commerce_card["commerceCard"]["thumbnails"].append(thumbnail)
148 |
149 | if 0 < len(is_buttons) <= 3: # 버튼 관련 파라미터
150 | commerce_card["commerceCard"]["buttons"] = list(is_buttons)
151 |
152 | if is_discount is not None and \
153 | is_discountRate is not None and \
154 | is_discountedPrice is not None: # 할인 관련 파라미터
155 | commerce_card["commerceCard"]["discount"] = is_discount
156 | commerce_card["commerceCard"]["discountRate"] = is_discountRate
157 | commerce_card["commerceCard"]["discountedPrice"] = is_discountedPrice
158 |
159 | if profile is not None: # 프로필 관련 파라미터
160 | commerce_card["commerceCard"]["profile"] = profile
161 |
162 | if is_carousel: # 리턴 형식 확인
163 | return commerce_card
164 |
165 | else:
166 | self.return_json["template"]["outputs"].append(commerce_card)
167 | return self.return_json
168 |
169 | def set_list(self, header_title, is_button: list, *data, is_carousel=False):
170 | basic_list = {
171 | "listCard": {
172 | "header": {
173 | "title": header_title
174 | },
175 | "items": []
176 | }
177 | }
178 | if 0 < len(is_button) <= 2: # 버튼은 최대 2개까지 설정 가능
179 | basic_list['listCard']['buttons'] = []
180 | for btn in is_button:
181 | basic_list['listCard']['buttons'].append(btn)
182 |
183 | for itm in data: # 값 연결
184 | basic_list['listCard']['items'].append(itm)
185 |
186 | if is_carousel: # 반환 형식 설정
187 | return basic_list
188 |
189 | else:
190 | self.return_json["template"]["outputs"].append(basic_list)
191 | return self.return_json
192 |
193 | def set_carousel(self, card_type, *items): # 케로셀 반환 형식 #(link, Title, description)
194 | init_json()
195 | basic_carousel = {
196 | "carousel": {
197 | "type": card_type,
198 | "items": []
199 | }
200 | }
201 |
202 | for itm in list(items):
203 | basic_carousel['carousel']['items'].append(itm)
204 |
205 | self.return_json["template"]["outputs"].append(basic_carousel)
206 | return self.return_json
207 |
208 | def __str__(self):
209 | return str(self.return_json)
210 |
211 |
212 | if __name__ == "__main__":
213 | Gen = ReturnType()
214 | buttons = [
215 | ParamOption('button', label='label1'),
216 | ParamOption('button', label='label2'),
217 | ParamOption('button', label='label3'),
218 | ParamOption('button', label='label4'),
219 | ]
220 | print(Gen.set_card("THUMB", *buttons, is_title="테스트!", is_description="산돌이 카드 테스트"))
221 |
--------------------------------------------------------------------------------
/betaSandol/return_type_generator.py:
--------------------------------------------------------------------------------
1 | class Return_Type: # 리턴 타입별 JSON 형식을 만드는 곳 입니다.
2 | def __init__(self):
3 | self.return_json = {
4 | "version": "2.0",
5 | "template": {
6 | "outputs": [
7 | ],
8 | "quickReplies": [
9 | {
10 | "messageText": "도움말",
11 | "action": "message",
12 | "label": "도움말"
13 | }
14 | ]
15 | }
16 | }
17 | self.common_params = common_params()
18 |
19 | def init_json(self):
20 | self.return_json = {
21 | "version": "2.0",
22 | "template": {
23 | "outputs": [
24 | ],
25 | "quickReplies": [
26 | {
27 | "messageText": "도움말",
28 | "action": "message",
29 | "label": "도움말"
30 | }
31 | ]
32 | }
33 | }
34 |
35 | def set_text(self, text, is_init = True): #텍스트 형식
36 | if (is_init == True):
37 | self.init_json()
38 | basic_text ={
39 | "simpleText": {
40 | "text": str(text)
41 | }
42 | }
43 | self.return_json["template"]["outputs"].append(basic_text)
44 | return self.return_json
45 |
46 | def set_card(self,thumb_img, *is_buttons, is_title = None, is_description = None, flag = False): #카드 형식
47 | self.init_json()
48 | basic_card = {
49 | "thumbnail": {
50 | "imageUrl": thumb_img
51 | }
52 | }
53 |
54 | try:
55 | if is_title != None:
56 | basic_card["title"] = is_title #타이틀 입력
57 |
58 | if is_description != None:
59 | basic_card["description"] = is_description # 설명 입력
60 |
61 | if is_buttons != ():
62 | if len(is_buttons) > 3:
63 | raise Exception("Buttons are must less then 3") # 버튼이 3개 이상이라면 오류 발생
64 | else:
65 | basic_card.update({"buttons": list(is_buttons)})
66 |
67 | if flag == True: #flag 가 True이면 Card Json만 반환하지만, False이면 return해야하는 기본 JSON도 포함이 된다.
68 | return basic_card
69 |
70 | else:
71 | self.return_json["template"]["outputs"].append({"basicCard": basic_card}) # 위 정보들을 return_json에 입력
72 | return self.return_json
73 |
74 | except Exception as e: #오류 발생시 오류 코드 리턴
75 | basic_card["description"] = "error :" + str(e)
76 | self.return_json["template"]["outputs"].append({"basicCard": basic_card})
77 | return self.return_json
78 |
79 | def set_image(self, src, text = None): # 이미지 반환 형식
80 | self.init_json()
81 | basic_image ={
82 | "simpleImage": {
83 | "imageUrl": src,
84 | }
85 | }
86 |
87 | if text != None:
88 | basic_image["simpleImage"]["altText"] = text
89 |
90 | self.return_json["template"]["outputs"].append(basic_image)
91 | return self.return_json
92 |
93 | def set_commerce(self,thumbnail, description, price, currency, is_discount = None, is_discountRate = None, is_discountedPrice = None, profile = None, **kwargs): # 커머스 반환 형식
94 | self.common_params.Button(**kwargs)
95 | return_json = {
96 | "version": "2.0",
97 | "template": {
98 | "outputs": [
99 | {
100 | "commerceCard": {
101 | "description": "따끈따끈한 보물 상자 팝니다",
102 | "price": 10000,
103 | "discount": 1000,
104 | "currency": "won",
105 | "thumbnails": [
106 | {
107 | "imageUrl": "http://k.kakaocdn.net/dn/83BvP/bl20duRC1Q1/lj3JUcmrzC53YIjNDkqbWK/i_6piz1p.jpg",
108 | "link": {
109 | "web": "https://store.kakaofriends.com/kr/products/1542"
110 | }
111 | }
112 | ],
113 | "profile": {
114 | "imageUrl": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcT4BJ9LU4Ikr_EvZLmijfcjzQKMRCJ2bO3A8SVKNuQ78zu2KOqM",
115 | "nickname": "보물상자 팝니다"
116 | },
117 | "buttons": [
118 | {
119 | "label": "구매하기",
120 | "action": "webLink",
121 | "webLinkUrl": "https://store.kakaofriends.com/kr/products/1542"
122 | },
123 | {
124 | "label": "전화하기",
125 | "action": "phone",
126 | "phoneNumber": "354-86-00070"
127 | },
128 | {
129 | "label": "공유하기",
130 | "action": "share"
131 | }
132 | ]
133 | }
134 | }
135 | ]
136 | }
137 | }
138 | return return_json
139 |
140 |
141 | def set_carousel(self, card_type, card_num, *params): #케로셀 반환 형식 #(link, Title, description)
142 | self.init_json()
143 | basic_carousel = {
144 | "carousel": {
145 | "type": card_type,
146 | "items": []
147 | }
148 | }
149 | if card_type == "basicCard":
150 | for param in range(card_num): # thumb_img, *is_buttons, is_title = None, is_description = None
151 | basic_carousel['carousel']['items'].append(self.is_Card(thumb_img = params[param][0], is_title = params[param][1], is_description = params[param][2], flag= True))
152 |
153 | else:
154 | for param in range(card_num): # thumb_img, *is_buttons, is_title = None, is_description = None
155 | basic_carousel['carousel']['items'].append(self.is_Card(thumb_img = params[param][0], is_title = params[param][1], is_description = params[param][2], flag= True))
156 | self.return_json["template"]["outputs"].append(basic_carousel)
157 | return self.return_json
158 |
159 | def set_list(self, title, data, is_Button = None): # [title, desc, url], 만약 없으면 None #data = list
160 | self.init_json()
161 | order = ['title', 'description', 'link']
162 | basic_list = {
163 | "listCard": {
164 | "header": {
165 | "title": title
166 | },
167 | "items": []
168 | }
169 | }
170 | for column in data:
171 | item = {}
172 | for idx, dat in enumerate(column):
173 | if dat is not None:
174 | if order[idx] == "link":
175 | item[order[idx]] = self.common_params.Link(dat)
176 |
177 | else:
178 | item[order[idx]] = dat
179 |
180 | basic_list['listCard']['items'].append(item)
181 | if is_Button != None:
182 | basic_list['listCard']['buttons'] = list()
183 | basic_list['listCard']['buttons'].append(is_Button)
184 |
185 | self.return_json["template"]["outputs"].append(basic_list)
186 | return self.return_json
187 |
188 |
189 | class common_params:
190 |
191 | #kwargs로 들어올 수 있는 값은 DOCS를 참조
192 | # label = string
193 | # action = string
194 | # webLinkUrl = string | action = webLink
195 | # messageText = string | action = message or block
196 | # phoneNumber = string | action = phone
197 | # blockId = string | action = block
198 | # extra ...
199 | def Button(self, **kwargs):
200 | data = {}
201 | params = ['label', 'action', 'webLinkUrl', 'messageText', 'phoneNumber', 'blockId']
202 | for item in kwargs.items():
203 | if item[0] not in params:
204 | data.clear()
205 | data["label"] = "error, Check Parameter"
206 | data["action"] = "message"
207 | break
208 | data[item[0]] = item[1]
209 |
210 | return data
211 |
212 | def Link(self, url):
213 | return {
214 | 'web' : url
215 | }
216 |
--------------------------------------------------------------------------------
/alphaSandol/subway.py:
--------------------------------------------------------------------------------
1 | import requests
2 | import json
3 | import datetime
4 | from bs4 import BeautifulSoup
5 | import settings
6 |
7 |
8 | class LiveSubwayTraffic:
9 | def __init__(self, station_no=None) -> None:
10 | self.URL = "https://map.naver.com/v5/api/transit/subway/stations/"
11 | self.time = None
12 | self.station_name: str
13 | self.return_data = ''
14 | self.station_no = station_no
15 |
16 | def get_data(self) -> dict:
17 | URL = self.URL + self.station_no + "/schedule?lang=ko&stationID=" + self.station_no
18 | html = requests.get(URL).text
19 | soup = BeautifulSoup(html, 'html.parser')
20 |
21 | json_data = json.loads(soup.text)
22 | # print(json_data)
23 | return json_data
24 |
25 | def arrival_time(self):
26 | try:
27 | if self.data['todayServiceDay']['name'] == '평일': # 평일 시간표
28 | schedule_data_up = self.data['weekdaySchedule']['up']
29 | schedule_data_down = self.data['weekdaySchedule']['down']
30 |
31 | it = schedule_data_up.__iter__() # 상행선
32 | flag = False
33 | for i in schedule_data_up:
34 | it.__next__()
35 | if datetime.datetime.strptime(i['departureTime'], '%H:%M:%S') > self.time:
36 | self.return_data += i['headsign'] + " 방면 " + i['departureTime'] + ", " \
37 | + it.__next__()['departureTime'] + "\n"
38 | flag = True
39 | break
40 | else:
41 | continue
42 |
43 | if not flag:
44 | self.return_data += schedule_data_up[-1]['headsign'] + schedule_data_up[-1][
45 | 'departureTime'] + " 막차입니다"
46 |
47 |
48 | it = schedule_data_down.__iter__() # 하행선
49 | for i in schedule_data_down:
50 | it.__next__()
51 | if datetime.datetime.strptime(i['departureTime'], '%H:%M:%S') > self.time:
52 | self.return_data += i['headsign'] + "방면 " + i['departureTime'] + ", " \
53 | + it.__next__()['departureTime'] + "\n"
54 | flag = True
55 | # print(i['departureTime'], end=' ')
56 | # print(it.__next__()['departureTime'], end=' ')
57 | break
58 |
59 | else:
60 | continue
61 |
62 | if not flag:
63 | self.return_data += schedule_data_down[-1]['headsign'] + schedule_data_down[-1][
64 | 'departureTime'] + " 막차입니다"
65 |
66 | else: # 주말 시간표
67 | schedule_data_up = self.data['sundaySchedule']['up']
68 | schedule_data_down = self.data['sundaySchedule']['down']
69 |
70 | flag = False
71 |
72 | it = schedule_data_up.__iter__()
73 | for i in schedule_data_up:
74 | it.__next__()
75 | if datetime.datetime.strptime(i['departureTime'], '%H:%M:%S') > self.time:
76 | self.return_data += i['headsign'] + "방면 " + i['departureTime'] + ", " \
77 | + it.__next__()['departureTime'] + "\n"
78 | flag = True
79 | # print(i['departureTime'], end=' ')
80 | # print(it.__next__()['departureTime'])
81 | break
82 |
83 | else:
84 | continue
85 |
86 | if not flag:
87 | self.return_data += schedule_data_up[-1]['headsign'] + schedule_data_up[-1][
88 | 'departureTime'] + " 막차입니다"
89 |
90 | flag = False
91 | it = schedule_data_down.__iter__()
92 | for i in schedule_data_down:
93 | it.__next__()
94 | if datetime.datetime.strptime(i['departureTime'], '%H:%M:%S') > self.time:
95 | self.return_data += i['headsign'] + "방면 " + i['departureTime'] + ", " \
96 | + it.__next__()['departureTime'] + "\n"
97 | flag = True
98 | # print(i['departureTime'], end=' ')
99 | # print(it.__next__()['departureTime'])
100 | break
101 |
102 | else:
103 | continue
104 |
105 | if not flag:
106 | self.return_data += schedule_data_down[-1]['headsign'] + schedule_data_down[-1][
107 | 'departureTime'] + " 막차입니다"
108 |
109 | except Exception as e:
110 | return str(e)
111 |
112 | def get_time(self) -> dict:
113 | return settings.GEN.set_text(self.time)
114 |
115 | def get_string(self, time):
116 | self.time = datetime.datetime.strptime(time, '%H:%M:%S') # time 모듈로 변환
117 | for subway in ["455", "11120"]:
118 | self.station_no = subway
119 | self.data = self.get_data()
120 | self.arrival_time()
121 | return settings.GEN.set_text(self.return_data)
122 |
123 |
124 | class LastTraffic: # 교통 관련 클래스
125 | def __init__(self):
126 |
127 | self.SUBWAY_URL = ["https://map.naver.com/v5/api/transit/subway/stations/455/schedule?lang=ko&stationID=455",
128 | "https://map.naver.com/v5/api/transit/subway/stations/11120/schedule?lang=ko&stationID=11120"]
129 |
130 | def real_time_traffic(self):
131 | context = ''
132 | header = [f"{settings.IMOGE('emotion', 'walk')}4호선 막차시간입니다\n",
133 | f"\n{settings.IMOGE('emotion', 'walk')}수인선 막차시간입니다\n"]
134 |
135 | try:
136 | for iteration in range(len(self.SUBWAY_URL)):
137 | context += ''.join(header[iteration])
138 | html = requests.get(self.SUBWAY_URL[iteration])
139 | soup = BeautifulSoup(html.text, 'html.parser')
140 |
141 | last_arrival_weekday = json.loads(soup.text)['weekdaySchedule'] # 평일 막차
142 | last_arrival_weekend = json.loads(soup.text)['sundaySchedule'] # 주말 막차
143 | if iteration == 0:
144 | weekday_last = lambda sign: [last_arrival_weekday[sign][101 + i] for i in
145 | range(len(last_arrival_weekday[sign]) - 101)][::-1]
146 | weekend_last = lambda sign: [last_arrival_weekend[sign][85 + i] for i in
147 | range(len(last_arrival_weekend[sign]) - 85)][::-1]
148 |
149 | else:
150 | weekday_last = lambda sign: [last_arrival_weekday[sign][i] for i in
151 | range(len(last_arrival_weekday[sign]))][::-1]
152 | weekend_last = lambda sign: [last_arrival_weekend[sign][i] for i in
153 | range(len(last_arrival_weekend[sign]))][::-1]
154 | # usage : weekend_last('up')
155 | # 마지막에 있는 열차 10개 정도를 가지고 와서 각 막차 시간 비교
156 | # 모두 불러오지 않는 이유는 속도 때문
157 | station = [i['headsign'] for i in weekday_last('up')] # headsign이 가장 처음으로 나오는 경우의 인덱스를 반환하기 위한 리스트
158 | station_weekend = [i['headsign'] for i in
159 | weekend_last('up')] # headsign이 가장 처음으로 나오는 경우의 인덱스를 반환하기 위한 리스트
160 | # 상행선에서의 막차별 역을 저장하는 리스트 (역 중복 가능)
161 |
162 | station2 = [i['headsign'] for i in weekday_last('down')] # headsign이 가장 처음으로 나오는 경우의 인덱스를 반환하기 위한 리스트
163 | station_weekend2 = [i['headsign'] for i in
164 | weekend_last('down')] # headsign이 가장 처음으로 나오는 경우의 인덱스를 반환하기 위한 리스트
165 | # 상행선에서의 막차별 역을 저장하는 리스트 (역 중복 가능)
166 |
167 | find_weekday = station.index
168 | find_weekend = station_weekend.index
169 |
170 | find_weekday2 = station2.index
171 | find_weekend2 = station_weekend2.index
172 |
173 | find_arrival_time_up = lambda a: weekday_last('up')[a]["departureTime"][:-3] # 평일 상행선
174 | find_arrival_time_down = lambda a: weekday_last('down')[a]["departureTime"][:-3] # 평일 하행선
175 |
176 | find_arrival_time_up2 = lambda a: weekend_last('up')[a]["departureTime"][:-3] # 주말 상행선
177 | find_arrival_time_down2 = lambda a: weekend_last('down')[a]["departureTime"][:-3] # 주말 하행선
178 |
179 | station_name_up: list = [["당고개", "안산", "노원", "금정", "한성대입구", "사당"], ["왕십리", "죽전", "고색"]]
180 | station_name_down: list = [["오이도"], ["오이도", "인천"]]
181 |
182 | for arv in (station_name_up[iteration]):
183 | context += ''.join(f"{arv} - ")
184 | try:
185 | context += ''.join(f"(평일) {find_arrival_time_up(find_weekday(arv))}")
186 | except Exception:
187 | pass
188 |
189 | try:
190 | context += "".join(f"(휴일) {find_arrival_time_up2(find_weekend(arv))}\n") # 휴일 시간이 있으면 시간 추가
191 | except Exception:
192 | context += "".join("\n") # 휴일 시간 없으면 개행문자 넣고 pass
193 |
194 | for arv in (station_name_down[iteration]):
195 | context += ''.join(f"{arv} - ")
196 | try:
197 | context += ''.join(f"(평일) {find_arrival_time_down(find_weekday2(arv))}")
198 | except Exception:
199 | pass
200 |
201 | try:
202 | context += "".join(f"(휴일) {find_arrival_time_down2(find_weekend2(arv))}\n") # 휴일 시간이 있으면 시간 추가
203 | except Exception:
204 | context += "".join("\n") # 휴일 시간 없으면 개행문자 넣고 pass
205 | except Exception as e:
206 | return settings.GEN.set_text(str(e))
207 | return settings.GEN.set_text(str(context[:-1]))
208 |
209 |
210 | class EfficientTransfer(LastTraffic): # 수인분당선
211 | def __init__(self):
212 | super().__init__()
213 |
214 | def real_time_traffic(self):
215 | return super().real_time_traffic()
216 |
217 |
218 | if __name__ == "__main__":
219 | import pprint
220 | pprint.pprint(LiveSubwayTraffic().get_string("12:13:30"))
221 | # pprint.pprint(LastTraffic().real_time_traffic())
222 | # pprint.pprint(EfficientTransfer().real_time_traffic())
223 |
--------------------------------------------------------------------------------
/alphaSandol/restaurant.py:
--------------------------------------------------------------------------------
1 | import boto3
2 | import settings
3 | import datetime
4 |
5 |
6 | class Time:
7 | DATE = 0
8 | LUNCH = 1
9 | DINNER = 2
10 |
11 |
12 | class AboutMeal: # 학식 관련 클래스
13 | def __init__(self):
14 | self.S3 = boto3.resource('s3')
15 | self.S3_client = boto3.client('s3')
16 | self.bucket = self.S3.Bucket(settings.BUCKET_NAME)
17 | self.data = ""
18 | self.URL_MENU = "https://ibook.kpu.ac.kr/Viewer/menu01"
19 |
20 | def read_meal(self, uid) -> dict: # 학식 불러오기
21 | restaurant_position = {"messageText": "운영시간",
22 | "action": "message",
23 | "label": "운영시간 및 위치"
24 | } # quick reply 형식
25 | MEAL_GEN = settings.ReturnType(reply_json=restaurant_position) # 따로 리턴타입을 불러옴, 이유는 발화안에 여러 응답을 줘야하기때문
26 | # 이전과 같은 id의 인스턴스로 사용하면 다른 발화에도 영향
27 | if not settings.DEBUG: # 디버그 모드가 아닌 경우
28 | try:
29 | self.bucket.download_file(settings.RESTAURANT_MENU, settings.LOCAL_RESTAURANT_MENU)
30 |
31 | except Exception as e:
32 | return settings.GEN.set_text(
33 | f"[File-Open-Error #131] 저장소에서 파일을 가져오는데 실패했습니다.{settings.IMOGE('emotion', 'sad')}\n{e}")
34 | # 버킷을 로컬 임시 폴더에 다운로드
35 |
36 | rst_name = list(settings.RESTAURANT_ACCESS_ID.values()) # 식당id만 뽑아낸 리스트
37 | if uid not in rst_name:
38 | try:
39 | weekday = ['월', '화', '수', '목', '금', '토', '일']
40 | file_dir = lambda \
41 | is_debug: settings.LOCAL_RESTAURANT_MENU if is_debug is False else "../test_stored_data/restaurant_menu.txt"
42 |
43 | with open(file_dir(settings.DEBUG), "r", encoding='UTF-8') as f:
44 | data = f.readlines()
45 | ret = '[교외식당 메뉴입니다!]\n'
46 | for restaurant in range(0, len(data) - 4, 2): # 파일에서 식당 구분이 2칸 간격으로 되어있음 교외식당
47 | menu_list = data[restaurant + 1].replace("\'", '').split(", ")
48 | last_update_date = datetime.date.fromisoformat(menu_list[0])
49 | form = data[restaurant].replace("\n", '').replace("🐾", settings.IMOGE('emotion', 'walk'))
50 |
51 | ret += f"{form}[{str(last_update_date)} {weekday[last_update_date.weekday()]}요일]\n" \
52 | f"{settings.IMOGE('emotion', 'paw')} 중식 : {menu_list[Time.LUNCH].replace(' ', ', ')}\n" \
53 | f"{settings.IMOGE('emotion', 'paw')} 석식 : {menu_list[Time.DINNER].replace(' ', ', ')}\n"
54 | ret = ret[:-2]
55 | MEAL_GEN.set_text(ret, is_init=False) # 교외식당 저장
56 | ret = '[교내식당 메뉴입니다!]\n'
57 | for school_restaurant in range(len(data) - 4, len(data) - 2, 2):
58 | menu_list = data[school_restaurant + 1].replace("\'", '').split(", ")
59 | last_update_date = datetime.date.fromisoformat(menu_list[0])
60 | form = data[school_restaurant].replace("\n", '').replace("🐾",
61 | settings.IMOGE('emotion', 'walk'))
62 |
63 | ret += f"{form}[{str(last_update_date)} {weekday[last_update_date.weekday()]}요일]\n포장메뉴도 있어요\n" \
64 | f"{settings.IMOGE('emotion', 'paw')} 중식 : {menu_list[Time.LUNCH]}\n" \
65 | f"{settings.IMOGE('emotion', 'paw')} 석식 : {menu_list[Time.DINNER]}\n"
66 | ret += "🐾웰스프레쉬(E동 교직원식당) [URL 참조]\nhttps://ibook.kpu.ac.kr/Viewer/menu01"
67 |
68 | return_string = MEAL_GEN.set_text(ret, is_init=False) # 교외식당 저장
69 | return return_string
70 |
71 | except Exception as e:
72 | return settings.GEN.set_text(
73 | "[File-Open-Error #132] 파일을 여는 중 오류가 발생했어요.." + settings.IMOGE('emotion', 'sad') + str(e))
74 |
75 | else:
76 | selected_restaurant = rst_name.index(uid) * 2 # 식당 이름 포인터
77 | try:
78 | weekday = ['월', '화', '수', '목', '금', '토', '일']
79 | file_dir = lambda \
80 | is_debug: settings.LOCAL_RESTAURANT_MENU if is_debug is False else "../test_stored_data/restaurant_menu.txt"
81 | with open(file_dir(settings.DEBUG), "r", encoding='UTF-8') as f:
82 | data = f.readlines()
83 |
84 | menu_list = data[selected_restaurant + 1].replace("\'", '').split(", ")
85 | last_update_date = datetime.date.fromisoformat(menu_list[0])
86 | form = data[selected_restaurant].replace("\n", '').replace("🐾", settings.IMOGE('emotion', 'walk'))
87 |
88 | if uid == settings.RESTAURANT_ACCESS_ID['푸드라운지']:
89 | ret = f"{form}[{str(last_update_date)} {weekday[last_update_date.weekday()]}요일]\n포장메뉴도 있어요\n" \
90 | f"{settings.IMOGE('emotion', 'paw')} 중식 : {menu_list[Time.LUNCH].replace(' ', ', ')}\n" \
91 | f"{settings.IMOGE('emotion', 'paw')} 석식 : {menu_list[Time.DINNER].replace(' ', ', ')}\n"
92 | else:
93 | ret = f"{form}[{str(last_update_date)} {weekday[last_update_date.weekday()]}요일]\n" \
94 | f"{settings.IMOGE('emotion', 'paw')} 중식 : {menu_list[Time.LUNCH].replace(' ', ', ')}\n" \
95 | f"{settings.IMOGE('emotion', 'paw')} 석식 : {menu_list[Time.DINNER].replace(' ', ', ')}\n"
96 | return_string = settings.GEN.set_text(ret)
97 |
98 | return return_string
99 |
100 | except Exception as e:
101 | return settings.GEN.set_text(
102 | "[File-Open-Error #132] 파일을 여는 중 오류가 발생했어요.." + settings.IMOGE('emotion', 'sad') + str(e))
103 |
104 | def upload_meal(self, store_name, lunch_list: str, dinner_list: str, input_date, owner_id) -> dict: # 학식 업로드
105 | if (owner_id != settings.RESTAURANT_ACCESS_ID[store_name]) and owner_id not in list(
106 | settings.SANDOL_ACCESS_ID.values()):
107 | return settings.GEN.set_text(
108 | f"[Permission-Error #121-1] 권한이 없습니다{owner_id}{settings.IMOGE('emotion', 'angry')}")
109 | # 권한 확인
110 |
111 | if store_name not in settings.RESTAURANT_ACCESS_ID.keys():
112 | return settings.GEN.set_text(f"[Not-Found-Error #121-2] 해당하는 식당이 없습니다.{settings.IMOGE('emotion', 'sad')}")
113 | # 식당 존재 여부 확인
114 |
115 | if not settings.DEBUG:
116 | try:
117 | self.S3.meta.client.download_file(settings.BUCKET_NAME, settings.RESTAURANT_MENU,
118 | settings.LOCAL_RESTAURANT_MENU)
119 |
120 | except Exception as e:
121 | return settings.GEN.set_text(
122 | f"[File-Open-Error #122] 저장소에서 파일을 찾을 수 없습니다.{settings.IMOGE('emotion', 'sad')}\n{e}")
123 |
124 | file_dir = lambda \
125 | is_debug: settings.LOCAL_RESTAURANT_MENU if is_debug is False else "../test_stored_data/restaurant_menu.txt"
126 | with open(file_dir(settings.DEBUG), "r", encoding='UTF-8') as f:
127 | try:
128 | data = f.readlines()
129 | menu_info = data[data.index("🐾" + store_name + "\n") + 1].replace('\'', '').replace("\n", "").split(
130 | ", ")
131 | menu_info[Time.DATE] = input_date
132 |
133 | menu_info[Time.LUNCH] = lunch_list
134 | menu_info[Time.DINNER] = dinner_list
135 |
136 | final_string = str(menu_info)[1:-1]
137 |
138 | data[data.index("🐾" + store_name + "\n") + 1] = final_string + "\n" # 최종 문자열
139 | with open(file_dir(settings.DEBUG), "w", encoding='UTF-8') as rf:
140 | rf.writelines(data)
141 |
142 | except Exception as e:
143 | return settings.GEN.set_text(
144 | f"[File-Open-Error #123]파일을 수정하는 중 오류가 발생했습니다.{settings.IMOGE('emotion', 'sad')}\n{e}")
145 |
146 | if not settings.DEBUG:
147 | try:
148 | s3 = boto3.client('s3') # 이 부분 해당 버킷 생성 후 적절히 수정 예정
149 | s3.upload_file(settings.LOCAL_RESTAURANT_MENU, 'sandol', settings.RESTAURANT_MENU)
150 |
151 | except Exception as e:
152 | return settings.GEN.set_text(
153 | f"[File-Open-Error #124]파일을 저장소에 업로드하는 중 오류가 발생했습니다.{settings.IMOGE('emotion', 'sad')}\n{e}")
154 |
155 | return settings.GEN.set_text(f"네! 학생들에게 잘 전달할게요! 감사합니다!{settings.IMOGE('emotion', 'walk')}")
156 |
157 | def reset_meal(self, bot_id, date) -> dict: # 학식 초기화
158 | if bot_id not in list(settings.SANDOL_ACCESS_ID.values()):
159 | return settings.GEN.set_text(f"[Permission-Error #141] 권한이 없습니다{settings.IMOGE('emotion', 'angry')}")
160 |
161 | if not settings.DEBUG:
162 | try:
163 | self.S3.meta.client.download_file(settings.BUCKET_NAME, settings.RESTAURANT_MENU,
164 | settings.LOCAL_RESTAURANT_MENU)
165 |
166 | except Exception as e:
167 | return settings.GEN.set_text(
168 | f"[File-Open-Error #122] 저장소에서 파일을 찾을 수 없습니다.{settings.IMOGE('emotion', 'sad')}\n{e}")
169 |
170 | try:
171 | file_dir = lambda \
172 | is_debug: settings.LOCAL_RESTAURANT_MENU if is_debug is False else "../test_stored_data/restaurant_menu.txt"
173 | print(file_dir(settings.DEBUG))
174 | with open(file_dir(settings.DEBUG), "w", encoding='UTF-8') as f:
175 | rest_name = [f"{settings.IMOGE('emotion', 'paw')}미가식당\n",
176 | f"{settings.IMOGE('emotion', 'paw')}세미콘식당\n",
177 | f"{settings.IMOGE('emotion', 'paw')}푸드라운지\n",
178 | f"{settings.IMOGE('emotion', 'paw')}웰스프레쉬\n"
179 | ]
180 |
181 | return_string = ''
182 | for i in range(len(rest_name)):
183 | return_string += rest_name[i] + "\'" + date + "\', \'업데이트되지않았습니다\', \'업데이트되지않았습니다\'\n"
184 | # 초기화 작업
185 |
186 | f.writelines(return_string)
187 |
188 | except Exception as e:
189 | return settings.GEN.set_text(
190 | f"[File-Open-Error #143]파일을 수정하는 중 오류가 발생했습니다.{settings.IMOGE('emotion', 'sad')}\n{e}")
191 |
192 | if not settings.DEBUG:
193 | try:
194 | s3 = boto3.client('s3') # 이 부분 해당 버킷 생성 후 적절히 수정 예정
195 | s3.upload_file(settings.LOCAL_RESTAURANT_MENU, 'sandol', settings.RESTAURANT_MENU)
196 |
197 | except Exception as e:
198 | return settings.GEN.set_text(
199 | f"[File-Open-Error #124]파일을 저장소에 업로드하는 중 오류가 발생했습니다.{settings.IMOGE('emotion', 'sad')}\n{e}")
200 |
201 | return settings.GEN.set_text(f"파일을 정상적으로 초기화했습니다")
202 |
203 |
204 | # 식당 운영시간 불러오기
205 | def time_meal():
206 | MEAL_GEN = settings.ReturnType()
207 | MEAL_GEN.set_image(settings.SANDOL_RSTRNT_MAP, is_init=False) # 식당 지도
208 |
209 | time_meal_string = f"교외식당 운영시간입니다! \n" \
210 | f"{settings.IMOGE('emotion', 'walk')}미가식당 \n" \
211 | f"{settings.IMOGE('emotion', 'paw')}운영시간 : 08:30 ~ 19:30 \n" \
212 | f"{settings.IMOGE('emotion', 'paw')}운영시간동안 항시 식사 가능합니다. \n\n" \
213 | f"{settings.IMOGE('emotion', 'walk')}세미콘 식당 \n" \
214 | f"{settings.IMOGE('emotion', 'paw')}중식 : 11:30 ~ 1:30\n" \
215 | f"{settings.IMOGE('emotion', 'paw')}석식 : 5:00 ~ 6:30\n"
216 | MEAL_GEN.set_text(time_meal_string, is_init=False)
217 |
218 | time_meal_string = f"교내식당 운영시간입니다! \n" \
219 | f"{settings.IMOGE('emotion', 'walk')}웰스 프레쉬(E동 교직원식당) \n" \
220 | f"{settings.IMOGE('emotion', 'paw')}중식 : 11:30 ~ 13:30 \n" \
221 | f"{settings.IMOGE('emotion', 'paw')}석식 : 영업하지 않습니다. \n\n" \
222 | f"{settings.IMOGE('emotion', 'walk')}푸드라운지 \n" \
223 | f"{settings.IMOGE('emotion', 'paw')}천원의 아침 : 8시 30분 ~ 10시 \n" \
224 | f"{settings.IMOGE('emotion', 'paw')}운영시간 : 11:00 ~ 20:00 \n" \
225 | f"{settings.IMOGE('emotion', 'paw')}토,일,공유일 영업하지 않습니다. \n"
226 |
227 | return MEAL_GEN.set_text(time_meal_string, is_init=False)
228 |
229 |
230 | # 식당 계좌이체 결제
231 | def payment_meal():
232 | btn_list = [{
233 | "label": "세미콘 식당",
234 | "action": "webLink",
235 | "webLinkUrl": "https://qr.kakaopay.com/2810060111751110120069009c404611"
236 | },
237 | {
238 | "label": "민이 식당",
239 | "action": "webLink",
240 | "webLinkUrl": "https://qr.kakaopay.com/2810060110000075262686359c406394"
241 | }]
242 | title = "hello"
243 | dsc = "dsc"
244 | params = ['label', 'action', 'webLinkUrl', 'messageText', 'phoneNumber', 'blockId']
245 | return settings.GEN.set_card(settings.SANDOL_LOGO1, settings.GEN_OPTION.button(label="세미콘 식당", action="webLink",
246 | webLinkUrl="https://qr.kakaopay.com/2810060111751110120069009c404611"),
247 | is_title=title, is_description=dsc, flag=False)
248 |
249 |
250 | if __name__ == "__main__":
251 | # print(AboutMeal().read_meal(uid="d367f2ec55f41b4207156f4b8fce5ce885b05d8c3b238cf8861c55a9012f6f5895")) # read meal (산돌팀 (학생)) 기준
252 | # print(AboutMeal().read_meal(uid="32d8a05a91242ffb4c64b5630ec55953121dffd83a121d985e26e06e2c457197e6")) # read meal (미가식당 (업주)) 기준
253 | # print(AboutMeal().reset_meal(bot_id="d367f2ec55f41b4207156f4b8fce5ce885b05d8c3b238cf8861c55a9012f6f5895", date="2001-09-03")) # reset meal 테스트 데이터 형식
254 | # print(AboutMeal().upload_meal(store_name="미가식당", lunch_list="ㅁ ㅁ ㅁ ㅁ", dinner_list="ㄹ ㄹ ㄹ ㄹ", input_date="2001-09-03",owner_id="d367f2ec55f41b4207156f4b8fce5ce885b05d8c3b238cf8861c55a9012f6f5895")) # read meal (미가식당 (업주)) 기준
255 | # print(time_meal()) # time meal
256 | print(payment_meal())
257 |
--------------------------------------------------------------------------------
/alphaSandol/Pipfile.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_meta": {
3 | "hash": {
4 | "sha256": "49e3f1ab224f2bb5ff92bb139bae000bac6aca1fde8c9e5c8957ec9ebf64f797"
5 | },
6 | "pipfile-spec": 6,
7 | "requires": {
8 | "python_version": "3.8"
9 | },
10 | "sources": [
11 | {
12 | "name": "pypi",
13 | "url": "https://pypi.org/simple",
14 | "verify_ssl": true
15 | }
16 | ]
17 | },
18 | "default": {
19 | "argcomplete": {
20 | "hashes": [
21 | "sha256:291f0beca7fd49ce285d2f10e4c1c77e9460cf823eef2de54df0c0fec88b0d81",
22 | "sha256:2c7dbffd8c045ea534921e63b0be6fe65e88599990d8dc408ac8c542b72a5445"
23 | ],
24 | "version": "==1.12.3"
25 | },
26 | "beautifulsoup4": {
27 | "hashes": [
28 | "sha256:9a315ce70049920ea4572a4055bc4bd700c940521d36fc858205ad4fcde149bf",
29 | "sha256:c23ad23c521d818955a4151a67d81580319d4bf548d3d49f4223ae041ff98891"
30 | ],
31 | "markers": "python_version >= '3.1'",
32 | "version": "==4.10.0"
33 | },
34 | "boto3": {
35 | "hashes": [
36 | "sha256:035191ad6c7e8aed972e1374f4e0ecb38767c497fd6c961e4ae33898b62f78fb",
37 | "sha256:cd58563dd3f36d5909815752b12c80a2c510c051474f8296e28dbd3ef5634d65"
38 | ],
39 | "index": "pypi",
40 | "version": "==1.20.11"
41 | },
42 | "botocore": {
43 | "hashes": [
44 | "sha256:133fa0837762587fb4e5da3fb61ac0b45495cd9fd2d2be7679ba64899da1f3ba",
45 | "sha256:497234f137810909289a600433cec5583ea8dc05a78b644653d76484138d78b9"
46 | ],
47 | "markers": "python_version >= '3.6'",
48 | "version": "==1.23.11"
49 | },
50 | "bs4": {
51 | "hashes": [
52 | "sha256:36ecea1fd7cc5c0c6e4a1ff075df26d50da647b75376626cc186e2212886dd3a"
53 | ],
54 | "index": "pypi",
55 | "version": "==0.0.1"
56 | },
57 | "certifi": {
58 | "hashes": [
59 | "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872",
60 | "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"
61 | ],
62 | "version": "==2021.10.8"
63 | },
64 | "cfn-flip": {
65 | "hashes": [
66 | "sha256:003e02a089c35e1230ffd0e1bcfbbc4b12cc7d2deb2fcc6c4228ac9819307362",
67 | "sha256:faca8e77f0d32fb84cce1db1ef4c18b14a325d31125dae73c13bcc01947d2722"
68 | ],
69 | "version": "==1.3.0"
70 | },
71 | "charset-normalizer": {
72 | "hashes": [
73 | "sha256:e019de665e2bcf9c2b64e2e5aa025fa991da8720daa3c1138cadd2fd1856aed0",
74 | "sha256:f7af805c321bfa1ce6714c51f254e0d5bb5e5834039bc17db7ebe3a4cec9492b"
75 | ],
76 | "markers": "python_version >= '3'",
77 | "version": "==2.0.7"
78 | },
79 | "click": {
80 | "hashes": [
81 | "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3",
82 | "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"
83 | ],
84 | "markers": "python_version >= '3.6'",
85 | "version": "==8.0.3"
86 | },
87 | "durationpy": {
88 | "hashes": [
89 | "sha256:5ef9416b527b50d722f34655becfb75e49228eb82f87b855ed1911b3314b5408"
90 | ],
91 | "version": "==0.5"
92 | },
93 | "future": {
94 | "hashes": [
95 | "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"
96 | ],
97 | "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
98 | "version": "==0.18.2"
99 | },
100 | "hjson": {
101 | "hashes": [
102 | "sha256:2838fd7200e5839ea4516ece953f3a19892c41089f0d933ba3f68e596aacfcd5",
103 | "sha256:5546438bf4e1b52bc964c6a47c4ed10fa5fba8a1b264e22efa893e333baad2db"
104 | ],
105 | "version": "==3.0.2"
106 | },
107 | "idna": {
108 | "hashes": [
109 | "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff",
110 | "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"
111 | ],
112 | "markers": "python_version >= '3'",
113 | "version": "==3.3"
114 | },
115 | "jmespath": {
116 | "hashes": [
117 | "sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9",
118 | "sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f"
119 | ],
120 | "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
121 | "version": "==0.10.0"
122 | },
123 | "kappa": {
124 | "hashes": [
125 | "sha256:4b5b372872f25d619e427e04282551048dc975a107385b076b3ffc6406a15833",
126 | "sha256:4d6b7b3accce4a0aaaac92b36237a6304f0f2fffbbe3caea3f7c9f52d12c9989"
127 | ],
128 | "version": "==0.6.0"
129 | },
130 | "placebo": {
131 | "hashes": [
132 | "sha256:03157f8527bbc2965b71b88f4a139ef8038618b346787f20d63e3c5da541b047"
133 | ],
134 | "version": "==0.9.0"
135 | },
136 | "python-dateutil": {
137 | "hashes": [
138 | "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86",
139 | "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"
140 | ],
141 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
142 | "version": "==2.8.2"
143 | },
144 | "python-slugify": {
145 | "hashes": [
146 | "sha256:6d8c5df75cd4a7c3a2d21e257633de53f52ab0265cd2d1dc62a730e8194a7380",
147 | "sha256:f13383a0b9fcbe649a1892b9c8eb4f8eab1d6d84b84bb7a624317afa98159cab"
148 | ],
149 | "markers": "python_version >= '3.6'",
150 | "version": "==5.0.2"
151 | },
152 | "pyyaml": {
153 | "hashes": [
154 | "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293",
155 | "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b",
156 | "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57",
157 | "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b",
158 | "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4",
159 | "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07",
160 | "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba",
161 | "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9",
162 | "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287",
163 | "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513",
164 | "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0",
165 | "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0",
166 | "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92",
167 | "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f",
168 | "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2",
169 | "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc",
170 | "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c",
171 | "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86",
172 | "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4",
173 | "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c",
174 | "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34",
175 | "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b",
176 | "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c",
177 | "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb",
178 | "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737",
179 | "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3",
180 | "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d",
181 | "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53",
182 | "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78",
183 | "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803",
184 | "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a",
185 | "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174",
186 | "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"
187 | ],
188 | "markers": "python_version >= '3.6'",
189 | "version": "==6.0"
190 | },
191 | "requests": {
192 | "hashes": [
193 | "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24",
194 | "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"
195 | ],
196 | "index": "pypi",
197 | "version": "==2.26.0"
198 | },
199 | "s3transfer": {
200 | "hashes": [
201 | "sha256:50ed823e1dc5868ad40c8dc92072f757aa0e653a192845c94a3b676f4a62da4c",
202 | "sha256:9c1dc369814391a6bda20ebbf4b70a0f34630592c9aa520856bf384916af2803"
203 | ],
204 | "markers": "python_version >= '3.6'",
205 | "version": "==0.5.0"
206 | },
207 | "six": {
208 | "hashes": [
209 | "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
210 | "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
211 | ],
212 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
213 | "version": "==1.16.0"
214 | },
215 | "soupsieve": {
216 | "hashes": [
217 | "sha256:1a3cca2617c6b38c0343ed661b1fa5de5637f257d4fe22bd9f1338010a1efefb",
218 | "sha256:b8d49b1cd4f037c7082a9683dfa1801aa2597fb11c3a1155b7a5b94829b4f1f9"
219 | ],
220 | "markers": "python_version >= '3.6'",
221 | "version": "==2.3.1"
222 | },
223 | "text-unidecode": {
224 | "hashes": [
225 | "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8",
226 | "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"
227 | ],
228 | "version": "==1.3"
229 | },
230 | "toml": {
231 | "hashes": [
232 | "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
233 | "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
234 | ],
235 | "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
236 | "version": "==0.10.2"
237 | },
238 | "tqdm": {
239 | "hashes": [
240 | "sha256:8dd278a422499cd6b727e6ae4061c40b48fce8b76d1ccbf5d34fca9b7f925b0c",
241 | "sha256:d359de7217506c9851b7869f3708d8ee53ed70a1b8edbba4dbcb47442592920d"
242 | ],
243 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
244 | "version": "==4.62.3"
245 | },
246 | "troposphere": {
247 | "hashes": [
248 | "sha256:2de96a37c9037c4344d561612042e3a83d258667f82f402abe734926e3de1f76",
249 | "sha256:68313c119c3e5ad457d2a41f7396baadd54551f221268ab97d44134f15bdb2f3"
250 | ],
251 | "markers": "python_full_version >= '3.6.2'",
252 | "version": "==3.1.1"
253 | },
254 | "urllib3": {
255 | "hashes": [
256 | "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece",
257 | "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"
258 | ],
259 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
260 | "version": "==1.26.7"
261 | },
262 | "werkzeug": {
263 | "hashes": [
264 | "sha256:63d3dc1cf60e7b7e35e97fa9861f7397283b75d765afcaefd993d6046899de8f",
265 | "sha256:aa2bb6fc8dee8d6c504c0ac1e7f5f7dc5810a9903e793b6f715a9f015bdadb9a"
266 | ],
267 | "markers": "python_version >= '3.6'",
268 | "version": "==2.0.2"
269 | },
270 | "wheel": {
271 | "hashes": [
272 | "sha256:21014b2bd93c6d0034b6ba5d35e4eb284340e09d63c59aef6fc14b0f346146fd",
273 | "sha256:e2ef7239991699e3355d54f8e968a21bb940a1dbf34a4d226741e64462516fad"
274 | ],
275 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
276 | "version": "==0.37.0"
277 | },
278 | "wsgi-request-logger": {
279 | "hashes": [
280 | "sha256:445d7ec52799562f812006394d0b4a7064b37084c6ea6bd74ea7a2136c97ed83"
281 | ],
282 | "version": "==0.4.6"
283 | },
284 | "zappa": {
285 | "git": "https://github.com/zappa/Zappa.git",
286 | "ref": "b5b80cf096227e4eb0feb1de5ff8097711d53c88"
287 | }
288 | },
289 | "develop": {}
290 | }
291 |
--------------------------------------------------------------------------------
/betaSandol/Pipfile.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_meta": {
3 | "hash": {
4 | "sha256": "2a672084bd1c014ac6c38a2b2151153a467491cfb27ee3e8de251fd9a6828084"
5 | },
6 | "pipfile-spec": 6,
7 | "requires": {
8 | "python_version": "3.8"
9 | },
10 | "sources": [
11 | {
12 | "name": "pypi",
13 | "url": "https://pypi.org/simple",
14 | "verify_ssl": true
15 | }
16 | ]
17 | },
18 | "default": {
19 | "argcomplete": {
20 | "hashes": [
21 | "sha256:291f0beca7fd49ce285d2f10e4c1c77e9460cf823eef2de54df0c0fec88b0d81",
22 | "sha256:2c7dbffd8c045ea534921e63b0be6fe65e88599990d8dc408ac8c542b72a5445"
23 | ],
24 | "version": "==1.12.3"
25 | },
26 | "beautifulsoup4": {
27 | "hashes": [
28 | "sha256:4c98143716ef1cb40bf7f39a8e3eec8f8b009509e74904ba3a7b315431577e35",
29 | "sha256:84729e322ad1d5b4d25f805bfa05b902dd96450f43842c4e99067d5e1369eb25",
30 | "sha256:fff47e031e34ec82bf17e00da8f592fe7de69aeea38be00523c04623c04fb666"
31 | ],
32 | "version": "==4.9.3"
33 | },
34 | "boto3": {
35 | "hashes": [
36 | "sha256:00be3c440db39a34a049eabce79377a0b3d453b6a24e2fa52e5156fa08f929bd",
37 | "sha256:3a7b183def075f6fe17c1154ecec42fc42f9c4ac05a7e7e018f267b7d5ef5961"
38 | ],
39 | "index": "pypi",
40 | "version": "==1.17.110"
41 | },
42 | "botocore": {
43 | "hashes": [
44 | "sha256:3500d0f0f15240a86efa6be91bf37df412d8cc10fc4b98ffea369dc13fb014da",
45 | "sha256:b69fd6c72d30b2ea0a42e7a2c3b9d65da3f4ccdff57bfaf6c721b0555a971bd6"
46 | ],
47 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
48 | "version": "==1.20.110"
49 | },
50 | "bs4": {
51 | "hashes": [
52 | "sha256:36ecea1fd7cc5c0c6e4a1ff075df26d50da647b75376626cc186e2212886dd3a"
53 | ],
54 | "index": "pypi",
55 | "version": "==0.0.1"
56 | },
57 | "certifi": {
58 | "hashes": [
59 | "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee",
60 | "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"
61 | ],
62 | "version": "==2021.5.30"
63 | },
64 | "cfn-flip": {
65 | "hashes": [
66 | "sha256:2bed32a1f4dca26dc64178d52511fd4ef778b5ccbcf32559cac884ace75bde6a"
67 | ],
68 | "version": "==1.2.3"
69 | },
70 | "chardet": {
71 | "hashes": [
72 | "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa",
73 | "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"
74 | ],
75 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
76 | "version": "==4.0.0"
77 | },
78 | "click": {
79 | "hashes": [
80 | "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a",
81 | "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"
82 | ],
83 | "markers": "python_version >= '3.6'",
84 | "version": "==8.0.1"
85 | },
86 | "durationpy": {
87 | "hashes": [
88 | "sha256:5ef9416b527b50d722f34655becfb75e49228eb82f87b855ed1911b3314b5408"
89 | ],
90 | "version": "==0.5"
91 | },
92 | "future": {
93 | "hashes": [
94 | "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"
95 | ],
96 | "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
97 | "version": "==0.18.2"
98 | },
99 | "hjson": {
100 | "hashes": [
101 | "sha256:2838fd7200e5839ea4516ece953f3a19892c41089f0d933ba3f68e596aacfcd5",
102 | "sha256:5546438bf4e1b52bc964c6a47c4ed10fa5fba8a1b264e22efa893e333baad2db"
103 | ],
104 | "version": "==3.0.2"
105 | },
106 | "idna": {
107 | "hashes": [
108 | "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6",
109 | "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"
110 | ],
111 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
112 | "version": "==2.10"
113 | },
114 | "jmespath": {
115 | "hashes": [
116 | "sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9",
117 | "sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f"
118 | ],
119 | "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
120 | "version": "==0.10.0"
121 | },
122 | "kappa": {
123 | "hashes": [
124 | "sha256:4b5b372872f25d619e427e04282551048dc975a107385b076b3ffc6406a15833",
125 | "sha256:4d6b7b3accce4a0aaaac92b36237a6304f0f2fffbbe3caea3f7c9f52d12c9989"
126 | ],
127 | "version": "==0.6.0"
128 | },
129 | "pep517": {
130 | "hashes": [
131 | "sha256:ac59f3f6b9726a49e15a649474539442cf76e0697e39df4869d25e68e880931b",
132 | "sha256:eba39d201ef937584ad3343df3581069085bacc95454c80188291d5b3ac7a249"
133 | ],
134 | "version": "==0.10.0"
135 | },
136 | "pip-tools": {
137 | "hashes": [
138 | "sha256:77727ef7457d1865e61fe34c2b1439f9b971b570cc232616a22ce82ab89d357d",
139 | "sha256:9ed38c73da4993e531694ea151f77048b4dbf2ba7b94c4a569daa39568cc6564"
140 | ],
141 | "markers": "python_version >= '3.6'",
142 | "version": "==6.2.0"
143 | },
144 | "placebo": {
145 | "hashes": [
146 | "sha256:03157f8527bbc2965b71b88f4a139ef8038618b346787f20d63e3c5da541b047"
147 | ],
148 | "version": "==0.9.0"
149 | },
150 | "python-dateutil": {
151 | "hashes": [
152 | "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c",
153 | "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"
154 | ],
155 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
156 | "version": "==2.8.1"
157 | },
158 | "python-slugify": {
159 | "hashes": [
160 | "sha256:6d8c5df75cd4a7c3a2d21e257633de53f52ab0265cd2d1dc62a730e8194a7380",
161 | "sha256:f13383a0b9fcbe649a1892b9c8eb4f8eab1d6d84b84bb7a624317afa98159cab"
162 | ],
163 | "markers": "python_version >= '3.6'",
164 | "version": "==5.0.2"
165 | },
166 | "pyyaml": {
167 | "hashes": [
168 | "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf",
169 | "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696",
170 | "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393",
171 | "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77",
172 | "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922",
173 | "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5",
174 | "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8",
175 | "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10",
176 | "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc",
177 | "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018",
178 | "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e",
179 | "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253",
180 | "sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347",
181 | "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183",
182 | "sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541",
183 | "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb",
184 | "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185",
185 | "sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc",
186 | "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db",
187 | "sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa",
188 | "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46",
189 | "sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122",
190 | "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b",
191 | "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63",
192 | "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df",
193 | "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc",
194 | "sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247",
195 | "sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6",
196 | "sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0"
197 | ],
198 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
199 | "version": "==5.4.1"
200 | },
201 | "requests": {
202 | "hashes": [
203 | "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804",
204 | "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"
205 | ],
206 | "index": "pypi",
207 | "version": "==2.25.1"
208 | },
209 | "s3transfer": {
210 | "hashes": [
211 | "sha256:9b3752887a2880690ce628bc263d6d13a3864083aeacff4890c1c9839a5eb0bc",
212 | "sha256:cb022f4b16551edebbb31a377d3f09600dbada7363d8c5db7976e7f47732e1b2"
213 | ],
214 | "version": "==0.4.2"
215 | },
216 | "six": {
217 | "hashes": [
218 | "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
219 | "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
220 | ],
221 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
222 | "version": "==1.16.0"
223 | },
224 | "soupsieve": {
225 | "hashes": [
226 | "sha256:052774848f448cf19c7e959adf5566904d525f33a3f8b6ba6f6f8f26ec7de0cc",
227 | "sha256:c2c1c2d44f158cdbddab7824a9af8c4f83c76b1e23e049479aa432feb6c4c23b"
228 | ],
229 | "markers": "python_version >= '3.0'",
230 | "version": "==2.2.1"
231 | },
232 | "text-unidecode": {
233 | "hashes": [
234 | "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8",
235 | "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"
236 | ],
237 | "version": "==1.3"
238 | },
239 | "toml": {
240 | "hashes": [
241 | "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
242 | "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
243 | ],
244 | "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
245 | "version": "==0.10.2"
246 | },
247 | "tqdm": {
248 | "hashes": [
249 | "sha256:5aa445ea0ad8b16d82b15ab342de6b195a722d75fc1ef9934a46bba6feafbc64",
250 | "sha256:8bb94db0d4468fea27d004a0f1d1c02da3cdedc00fe491c0de986b76a04d6b0a"
251 | ],
252 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
253 | "version": "==4.61.2"
254 | },
255 | "troposphere": {
256 | "hashes": [
257 | "sha256:ea2e5f2f82c224eaa1414a008b1939aae124c3e3e1dd993301968f155b333bd7"
258 | ],
259 | "ignore": [
260 | "zappa"
261 | ],
262 | "index": "pypi",
263 | "version": "==2.7.1"
264 | },
265 | "urllib3": {
266 | "hashes": [
267 | "sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4",
268 | "sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f"
269 | ],
270 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
271 | "version": "==1.26.6"
272 | },
273 | "werkzeug": {
274 | "hashes": [
275 | "sha256:1e0dedc2acb1f46827daa2e399c1485c8fa17c0d8e70b6b875b4e7f54bf408d2",
276 | "sha256:b353856d37dec59d6511359f97f6a4b2468442e454bd1c98298ddce53cac1f04"
277 | ],
278 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
279 | "version": "==0.16.1"
280 | },
281 | "wheel": {
282 | "hashes": [
283 | "sha256:78b5b185f0e5763c26ca1e324373aadd49182ca90e825f7853f4b2509215dc0e",
284 | "sha256:e11eefd162658ea59a60a0f6c7d493a7190ea4b9a85e335b33489d9f17e0245e"
285 | ],
286 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
287 | "version": "==0.36.2"
288 | },
289 | "wsgi-request-logger": {
290 | "hashes": [
291 | "sha256:445d7ec52799562f812006394d0b4a7064b37084c6ea6bd74ea7a2136c97ed83"
292 | ],
293 | "version": "==0.4.6"
294 | },
295 | "zappa": {
296 | "hashes": [
297 | "sha256:46a0afc1218de17bf713a8f4cfcb4dde2ba0466d18088918b9d2bc22ec6f9434",
298 | "sha256:a3623197a1dd30faa028f62fda1b7ba5dcbb643bc6ac43ad4cffdfd89a3b85c8"
299 | ],
300 | "index": "pypi",
301 | "version": "==0.53.0"
302 | }
303 | },
304 | "develop": {}
305 | }
306 |
--------------------------------------------------------------------------------
/betaSandol/lambda_prototype_module.py:
--------------------------------------------------------------------------------
1 | from bs4 import BeautifulSoup
2 | import requests
3 | import boto3
4 | import random
5 | import datetime
6 | import json
7 | import time
8 | import return_type_generator as Generator
9 |
10 | imoge_mapping = {
11 | 'emotion':{
12 | 'paw' : '🐾',
13 | 'smile' : '😺',
14 | 'happy' : '😸',
15 | 'sad' : '😹',
16 | 'love' : '😻',
17 | 'confident' : '😼',
18 | 'angry' : '😾',
19 | 'surprise' : '🙀',
20 | 'walk' : '🐈',
21 | 'nexpression' : '🐱'
22 |
23 | },
24 | 'weather':{
25 | '흐림' : '☁',
26 | '구름많음' : '⛅',
27 | 'hvy_rain' : '⛈',
28 | '비' : '☔',
29 | '약간흐림' : '🌤',
30 | '맑음' : '☀',
31 | 'sun_wth_rain' : '🌦',
32 | 'thunder' : '🌩',
33 | '바람' : '🌪',
34 | '안개' : '🌫'
35 | }
36 | }
37 | gen = Generator.Return_Type()
38 | opt = Generator.common_params()
39 | class CrawlingFunction():
40 | def subway(self, station='정왕'):
41 | try:
42 | header = {
43 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36"}
44 | arrival_subway_api_url = "http://swopenapi.seoul.go.kr/api/subway/49664c636d6a68303634704d4f7649/json/realtimeStationArrival/0/5/" + station
45 | soup = requests.get(arrival_subway_api_url, headers=header) # 여기까지 기본 크롤링 준비
46 |
47 | if soup.status_code != 200:
48 | raise Exception('[Crawling-Error #001] API 서버에 연결을 실패했습니다 잠시후 다시 시도해주세요'+ imoge_mapping['emotion']['sad'])
49 |
50 | receptdata = soup.json()
51 | reprocess = {'subwayStatus': [], # arivlCd
52 | 'subwayPos': [], # arivlMsg2
53 | 'reqDate': None, # recptnDt
54 | 'heading': [], # trainLineNm
55 | 'arivlTime': [] # barvlDt
56 | }
57 |
58 | reprocess['reqDate'] = receptdata['realtimeArrivalList'][0]['recptnDt']
59 | for i in range(len(receptdata['realtimeArrivalList'])):
60 | reprocess['subwayStatus'].append(receptdata['realtimeArrivalList'][i]['arvlCd'])
61 | reprocess['subwayPos'].append(receptdata['realtimeArrivalList'][i]['arvlMsg2'])
62 | reprocess['heading'].append(receptdata['realtimeArrivalList'][i]['trainLineNm'])
63 | reprocess['arivlTime'].append(
64 | receptdata['realtimeArrivalList'][i]['barvlDt']) # 여기까지 크롤링 한 내용들 기준으로 업데이트
65 |
66 | retn_str = reprocess['reqDate'] + "기준 " + station + " 도착정보입니다"+ imoge_mapping['emotion']['walk']+"\n"
67 | for i in range(len(reprocess['arivlTime'])):
68 | rept_str = str(i + 1) + ".\n[" + reprocess['heading'][i] + "] - " + "\n" + reprocess['subwayPos'][i] + "\n\n"
69 | retn_str += rept_str
70 |
71 | retn_str += imoge_mapping['emotion']['paw']+"실제 열차 도착 시간과 상이할 수 있습니다.\n"
72 |
73 | return gen.set_text(retn_str)
74 |
75 |
76 | except Exception as e:
77 | return gen.set_text("[Crawling_Error #002] 현재 열차 운행 시간이 아니거나, API 서버와의 통신에 실패하였습니다"+ imoge_mapping['emotion']['sad'])
78 | def last_subway(self):
79 | def station_no4():
80 | target_url = "https://map.naver.com/v5/api/transit/subway/stations/455/schedule?lang=ko&stationID=455"
81 | html = requests.get(target_url)
82 | soup = BeautifulSoup(html.text, 'html.parser')
83 |
84 | last_arrival_weekday = json.loads(soup.text)["weekdaySchedule"] # 평일
85 | last_arrival_weekend = json.loads(soup.text)["sundaySchedule"] # 주말
86 |
87 | weekday_last = [last_arrival_weekday['up'][101 + i] for i in range(len(last_arrival_weekday['up']) - 101)][
88 | ::-1] # 역순으로 변경
89 | weekend_last = [last_arrival_weekend['up'][85 + i] for i in range(len(last_arrival_weekend['up']) - 85)][
90 | ::-1] # 역순으로 변경
91 | station = [i['headsign'] for i in weekday_last] # headsign이 가장 처음으로 나오는 경우의 인덱스를 반환하기 위한 리스트
92 | station2 = [i['headsign'] for i in weekend_last] # headsign이 가장 처음으로 나오는 경우의 인덱스를 반환하기 위한 리스트
93 | find_station_idx = station.index # 가독성 up
94 | find_station2_idx = station2.index # 가독성 up
95 |
96 | return "당고개 - (평일) ", weekday_last[find_station_idx("당고개")]['departureTime'][:-3], " (휴일) ", \
97 | weekend_last[find_station2_idx("당고개")]['departureTime'][:-3] \
98 | + "\n안산 - (평일) ", weekday_last[find_station_idx("안산")]['departureTime'][:-3] \
99 | + "\n노원 - (평일) ", weekday_last[find_station_idx("노원")]['departureTime'][:-3], " (휴일) ", \
100 | weekend_last[find_station2_idx("노원")]['departureTime'][:-3] \
101 | + "\n금정 - (평일) ", weekday_last[find_station_idx("금정")]['departureTime'][:-3], " (휴일) ", \
102 | weekend_last[find_station2_idx("금정")]['departureTime'][:-3] \
103 | + "\n한성대입구 - (휴일) ", weekend_last[find_station2_idx("한성대입구")]['departureTime'][:-3] \
104 | + "\n사당 - (휴일) ", weekend_last[find_station2_idx("사당")]['departureTime'][:-3] \
105 | + "\n오이도 - (평일) ", last_arrival_weekday['down'][-1]['departureTime'][:-3], " (휴일) ", \
106 | last_arrival_weekend['down'][-1]['departureTime'][:-3]
107 |
108 | def station_suin():
109 | target_url = "https://map.naver.com/v5/api/transit/subway/stations/11120/schedule?lang=ko&stationID=11120"
110 | html = requests.get(target_url)
111 | soup = BeautifulSoup(html.text, 'html.parser')
112 |
113 | last_arrival_weekday = json.loads(soup.text)["weekdaySchedule"] # 평일
114 | last_arrival_weekend = json.loads(soup.text)["sundaySchedule"] # 주말
115 | weekday_last = [last_arrival_weekday['up'][i] for i in range(len(last_arrival_weekday['up']))][
116 | ::-1] # 역순으로 변경 (상행)
117 | weekend_last = [last_arrival_weekend['up'][i] for i in range(len(last_arrival_weekend['up']))][
118 | ::-1] # 역순으로 변경
119 |
120 | weekday_last2 = [last_arrival_weekday['down'][i] for i in range(len(last_arrival_weekday['down']))][
121 | ::-1] # 역순으로 변경 (하행)
122 | weekend_last2 = [last_arrival_weekend['down'][i] for i in range(len(last_arrival_weekend['down']))][
123 | ::-1] # 역순으로 변경
124 |
125 | station = [i['headsign'] for i in weekday_last] # headsign이 가장 처음으로 나오는 경우의 인덱스를 반환하기 위한 리스트 (상행)
126 | station2 = [i['headsign'] for i in weekend_last] # headsign이 가장 처음으로 나오는 경우의 인덱스를 반환하기 위한 리스트
127 |
128 | station_down = [i['headsign'] for i in weekday_last2] # headsign이 가장 처음으로 나오는 경우의 인덱스를 반환하기 위한 리스트 (하행)
129 | station_down2 = [i['headsign'] for i in weekend_last2] # headsign이 가장 처음으로 나오는 경우의 인덱스를 반환하기 위한 리스트
130 |
131 | find_station_idx = station.index # 가독성 up (상행)
132 | find_station2_idx = station2.index # 가독성 up
133 |
134 | find_station_down_idx = station_down.index # 가독성 up (하행)
135 | find_station_down_idx2 = station_down2.index # 가독성 up
136 | return "왕십리 - (평일) ", weekday_last[find_station_idx("왕십리")]['departureTime'][:-3], " (휴일) ", \
137 | weekend_last[find_station2_idx("왕십리")]['departureTime'][:-3] \
138 | + "\n죽전 - (평일) ", weekday_last[find_station_idx("죽전")]['departureTime'][:-3], " (휴일) ", \
139 | weekend_last[find_station2_idx("죽전")]['departureTime'][:-3] \
140 | + "\n고색 - (평일) ", weekday_last[find_station_idx("고색")]['departureTime'][:-3], " (휴일) ", \
141 | weekend_last[find_station2_idx("고색")]['departureTime'][:-3] \
142 | + "\n오이도 - (평일) ", weekday_last2[find_station_down_idx("오이도")]['departureTime'][:-3], " (휴일) ", \
143 | weekend_last2[find_station_down_idx2("오이도")]['departureTime'][:-3] \
144 | + "\n인천 - (평일) ", weekday_last2[find_station_down_idx("인천")]['departureTime'][:-3], " (휴일) ", \
145 | weekend_last2[find_station_down_idx2("인천")]['departureTime'][:-3]
146 |
147 | # station_suin()
148 | return_str = imoge_mapping['emotion']['walk'] + '4호선 막차 시간입니다\n'
149 | return_str += ''.join(station_no4())
150 | return_str += '\n\n' + imoge_mapping['emotion']['walk'] + '수인선 막차 시간입니다\n'
151 | return_str += ''.join(station_suin())
152 | return gen.set_text(return_str)
153 | # boto3 주석 해제하기
154 | # def random_meal(self):
155 | # s3 = boto3.resource('s3')
156 | # bucket = s3.Bucket("sandol")
157 | # try:
158 | # local_file = "/tmp/" + "test.txt"
159 | # bucket.download_file("tmp/test.txt", local_file) # s3에서 파일을 다운로드 후 /tmp에 저장
160 | #
161 | # except Exception as e:
162 | # return str(e)
163 | #
164 | # with open("/tmp/test.txt", "r", encoding='UTF-8') as rf:
165 | # data = rf.readlines() # 파일을 전부 읽어서 list로 변환
166 | #
167 | # idx = random.randint(0, 100)
168 | # result_string = data[idx]
169 | # return "☆빠밤★\n" + result_string.split("->")[0] + " 에서, " + result_string.split("->")[1].replace("\n",
170 | # '') + " 어떠세요?"
171 |
172 | def today_covid(self):
173 | try:
174 | url = 'https://m.search.naver.com/p/csearch/content/nqapirender.nhn?where=nexearch&pkid=9005&key=diffV2API'
175 | html = requests.get(url).text
176 | data = json.loads(html)
177 | result = data['result']['list'][-1]['date'] +"일까지 코로나 발생 현황이에요"+imoge_mapping['emotion']['walk']+"\n"+imoge_mapping['emotion']['paw']+"지역발생 : " + data['result']['list'][-1]['local'] +"명\n" + imoge_mapping['emotion']['paw'] + "해외유입 : "+data['result']['list'][-1]['oversea']+"명 입니다!\n코로나 조심하세요"+imoge_mapping['emotion']['nexpression']
178 | return gen.set_card("https://raw.githubusercontent.com/hhhminme/kpu_sandol_team/main/img/card_covid.png", is_title="코로나 확진자 수", is_description= result)
179 |
180 | except Exception as e:
181 | return gen.set_text("코로나 확진자 정보를 불러오는데 실패했어요" + imoge_mapping['emotion']['sad'])
182 |
183 | def weather(self, location):
184 |
185 | url = 'https://search.naver.com/search.naver?query=' + location + "날씨"
186 | html = requests.get(url).text
187 | soup = BeautifulSoup(html, 'html.parser')
188 | form = soup.find("div", {'class': 'api_subject_bx'}).find("div", {'class': 'main_info'}).find("div", {
189 | 'class': 'info_data'})
190 | sub_form = soup.find("div", {'class': 'api_subject_bx'}).find("div", {'class': 'sub_info'}).find("div", {
191 | 'class': 'detail_box'})
192 | today_temp = form.find("span", {'class': 'todaytemp'}).text
193 |
194 | try:
195 | today_temp_min = form.find("span", {'class': 'min'}).text
196 | except:
197 | today_temp_min = "-"
198 |
199 | try:
200 | today_temp_max = form.find("span", {'class': 'max'}).text
201 | except:
202 | today_temp_max = "-"
203 |
204 | try:
205 | today_temp_ray = form.find("span", {'class': 'indicator'}).find("span").text
206 | except:
207 | today_temp_ray = "-"
208 | update_date = soup.find("div", {'class': 'guide_bx _guideBox'}).find("span", {'class': 'guide_txt'}).find(
209 | 'span', {'class': 'update'}).text
210 |
211 | today_weather = form.find("ul").find("li").text.strip()
212 | today_dust_list = sub_form.find_all("dd")
213 | today_dust10 = today_dust_list[0].text
214 | today_dust25 = today_dust_list[1].text
215 |
216 | try:
217 | weather_icon = imoge_mapping['weather'][today_weather.split(', ')[0]]
218 |
219 | except:
220 | weather_icon = ''
221 |
222 | result = imoge_mapping['emotion']['walk']+ location + "의 기상정보입니다" \
223 | "\n\n기온 : " + today_temp + "°C (" + today_temp_min + "C / " + today_temp_max + "C)\n" + weather_icon + today_weather + \
224 | "\n\n미세먼지 : " + today_dust10.replace("㎥", "㎥, ") + "\n초미세먼지 : " + today_dust25.replace("㎥", "㎥, ") + \
225 | "\n자외선 : " + today_temp_ray + "이에요!\n\n" + update_date + "시에 업데이트 된 네이버 날씨 정보입니다!"
226 |
227 | return gen.set_text(result)
228 |
229 | def announcement(self):
230 | URL = "http://www.kpu.ac.kr/front/boardlist.do?bbsConfigFK=1&siteGubun=14&menuGubun=1"
231 | ORIGIN = "http://www.kpu.ac.kr"
232 | req = requests.get(URL)
233 | soup = BeautifulSoup(req.text, 'html.parser')
234 | announce_list = soup.find('table').find('tbody').find_all('tr')
235 | result = [] # title, date, URl
236 |
237 | for i in range (5):
238 | result.append([announce_list[i].find_all("td")[1].find('a').text.strip(), announce_list[i].find_all("td")[4].text.strip(), ORIGIN+announce_list[i].find_all("td")[1].find("a")['href']])
239 | return gen.set_list("교내 최신 학사공지 내역입니다", result, is_Button= opt.Button(label="바로가기", action="webLink", webLinkUrl = "http://www.kpu.ac.kr/contents/main/cor/noticehaksa.html"))
240 |
241 | class s3IOEvent():
242 | def upload_feedback(self, params): # 피드백 업로드 기능
243 | s3 = boto3.resource('s3')
244 | bucket = s3.Bucket('sandol') # 이 부분 해당 버킷 생성 후 적절히 수정 예정
245 | params = "[" + str(datetime.datetime.today()) + "] :" + params + "\n"
246 | try:
247 | local_file = "/tmp/" + "feedback.txt"
248 | bucket.download_file("feedback.txt", local_file)
249 | except Exception as e:
250 | return gen.set_text("[File-Open-Error #101] 서버에서 피드백 파일을 불러오는 중 오류가 발생했어요"+ imoge_mapping['emotion']['sad'])
251 |
252 | try:
253 | with open("/tmp/feedback.txt", "a", encoding="UTF-8") as f:
254 | f.writelines(params)
255 | except Exception as e:
256 | return gen.set_text("[File-Open-Error #102] 파일을 저장 중 오류가 발생했습니다" + imoge_mapping['emotion']['sad'])
257 |
258 | try:
259 | s3 = boto3.client('s3') # 이 부분 해당 버킷 생성 후 적절히 수정 예정
260 | s3.upload_file("/tmp/feedback.txt", 'sandol', 'feedback.txt')
261 |
262 | except Exception as e:
263 | return gen.set_text("[File-Open-Error #103] 파일을 서버에 업로드 하는 중 오류가 발생했습니다" + imoge_mapping['emotion']['sad'])
264 |
265 | return gen.set_text("피드백 주셔서 감사해요! 빠른 시일내에 검토 후 적용해볼게요!" + imoge_mapping['emotion']['love'])
266 |
267 | def read_feedback(self, params, bot_id): # 피드백 읽기 기능 (관리자 전용)
268 | sandol_team = ['d367f2ec55f41b4207156f4b8fce5ce885b05d8c3b238cf8861c55a9012f6f5895',
269 | '339b0444bfabbffa0f13508ea7c45b61675b5720234cca8f73cd7421c22de9e546',
270 | '04eabc8b965bf5ae6cccb122a18521969cc391162e3fd5f61b85efe8bb12e5e98a',
271 | 'def99464e022b38389697fe68d54bbba723d1da291094c19bbf5eaace7b059a997']
272 |
273 | if bot_id not in sandol_team:
274 | return gen.set_text("권한이 없습니다")
275 |
276 | if params == '1': # 읽기
277 | s3 = boto3.resource('s3')
278 | bucket = s3.Bucket("sandol")
279 |
280 | try:
281 | local_file = "/tmp/" + "feedback.txt"
282 | bucket.download_file("feedback.txt", local_file)
283 | except Exception as e:
284 | return gen.set_text("[File-Open-Error #111] 서버에서 피드백 파일을 불러오는 중 오류가 발생했어요 ")
285 |
286 | try:
287 | with open("/tmp/feedback.txt", "r", encoding="UTF-8") as f: # 이 부분 해당 버킷 생성 후 적절히 수정 예정
288 | txt = ''.join(f.readlines())
289 | return gen.set_text(txt)
290 |
291 | except Exception as e:
292 | return gen.set_text("[File-Open-Error #112] 파일을 읽는 중 오류가 발생했습니다")
293 |
294 | elif params == '2': # 지우기
295 | s3 = boto3.resource('s3')
296 | bucket = s3.Bucket('sandol') # 이 부분 해당 버킷 생성 후 적절히 수정 예정
297 | params = "#feedbacks\n"
298 | try:
299 | local_file = "/tmp/" + "feedback.txt"
300 | bucket.download_file("feedback.txt", local_file)
301 | except Exception as e:
302 | return gen.set_text("[File-Open-Error #113] 서버에서 피드백 파일을 불러오는 중 오류가 발생했어요")
303 |
304 | try:
305 | with open("/tmp/feedback.txt", "w", encoding="UTF-8") as f: # 이 부분 해당 버킷 생성 후 적절히 수정 예정
306 | f.writelines(params)
307 | except Exception as e:
308 | return gen.set_text("[File-Open-Error #114] 파일을 삭제 중 오류가 발생했습니다")
309 |
310 | try:
311 | s3 = boto3.client('s3')
312 | s3.upload_file("/tmp/feedback.txt", 'sandol', 'feedback.txt')
313 |
314 | except Exception as e:
315 | return gen.set_text("[File-Open-Error #115] 파일을 서버에 업로드 하는 중 오류가 발생했습니다")
316 | return gen.set_text("성공적으로 파일 내용을 삭제했습니다")
317 |
318 |
319 | else: # param error
320 | return gen.set_text('[Param-Error #116] 잘못된 파라미터')
321 |
322 | def upload_meal(self, store_name, lunch_list, dinner_list,input_date, owner_id): # 식사 업로드 기능
323 | owner_id_dec = {'미가식당': "32d8a05a91242ffb4c64b5630ec55953121dffd83a121d985e26e06e2c457197e6",
324 | '웰스프레쉬': "d367f2ec55f41b4207156f4b8fce5ce885b05d8c3b238cf8861c55a9012f6f5895",
325 | '푸드라운지': "46f338132e6af63c32c07220c318f0e7c570e8eb6f375c9e8bb59ce33776f27c4c"
326 | }
327 | sandol_team = ['d367f2ec55f41b4207156f4b8fce5ce885b05d8c3b238cf8861c55a9012f6f5895',
328 | '339b0444bfabbffa0f13508ea7c45b61675b5720234cca8f73cd7421c22de9e546',
329 | '04eabc8b965bf5ae6cccb122a18521969cc391162e3fd5f61b85efe8bb12e5e98a',
330 | 'def99464e022b38389697fe68d54bbba723d1da291094c19bbf5eaace7b059a997']
331 |
332 | if (owner_id_dec[store_name] != owner_id) and owner_id not in sandol_team:
333 | return gen.set_text("[Permission-Error #121-1] 권한이 없습니다" + imoge_mapping['emotion']['angry'])
334 |
335 | if store_name not in owner_id_dec.keys():
336 | return gen.set_text("[Not-Found-Error #121-2] 해당하는 식당이 없습니다."+ imoge_mapping['emotion']['sad'])
337 |
338 | else:
339 | store_file = "../test_stored_data/restaurant_menu.txt"
340 | s3 = boto3.resource('s3')
341 | bucket = s3.Bucket("sandol")
342 | local_file = "/tmp/" + store_file
343 |
344 | try:
345 | # local_file = "./restaurant_menu/" + store_file
346 | s3.meta.client.download_file("sandol", "restaurant_menu.txt", '/tmp/restaurant_menu.txt')
347 |
348 | except Exception as e:
349 | return gen.set_text("[File-Open-Error #122] 저장소에서 파일을 찾을 수 없습니다."+ imoge_mapping['emotion']['sad'])
350 |
351 | with open(local_file, "r", encoding="UTF-8") as f:
352 | try:
353 | data = f.readlines()
354 | print(data)
355 | menu_info = data[data.index("🐾"+store_name+"\n") + 1].replace('\'','').replace("\n","").split(", ") #내부 데이터 처리
356 | menu_info[0] = input_date
357 |
358 | menu_info[1] = lunch_list.replace(", ",",").replace(" ",",")
359 | menu_info[2] = dinner_list.replace(",","").replace(" ",",") #메뉴 수정
360 |
361 | menu_info[1] = lunch_list.replace(" ",",")
362 | menu_info[2] = dinner_list.replace(" ",",") #메뉴 수정
363 |
364 | menu_info[1] = lunch_list.replace(" ",",")
365 | menu_info[2] = dinner_list.replace(" ",",") #메뉴 수정
366 |
367 | data[data.index("🐾"+store_name+"\n") + 1] = str(menu_info)[1:-1] + "\n" #최종 문자열
368 | with open(local_file, "w", encoding='UTF-8') as rf:
369 | rf.writelines(data)
370 |
371 |
372 | except Exception as e:
373 | return gen.set_text("[File-Open-Error #123]파일을 수정하는 중 오류가 발생했습니다."+ imoge_mapping['emotion']['sad'])
374 | try:
375 | s3 = boto3.client('s3') # 이 부분 해당 버킷 생성 후 적절히 수정 예정
376 | s3.upload_file(local_file, 'sandol', store_file)
377 |
378 | except Exception:
379 | return gen.set_text("[File-Open-Error #124]파일을 저장소에 업로드하는 중 오류가 발생했습니다."+ imoge_mapping['emotion']['sad'])
380 |
381 |
382 | return gen.set_text("네! 학생들에게 잘 전달할게요! 감사합니다!"+ imoge_mapping['emotion']['walk'])
383 |
384 |
385 | def read_meal(self):
386 | store_file = "../test_stored_data/restaurant_menu.txt"
387 | s3 = boto3.resource('s3') # 이 부분 해당 버킷 생성 후 적절히 수정 예정
388 | bucket = s3.Bucket("sandol")
389 | try:
390 | local_file = "/tmp/" + store_file
391 | # local_file = "./restaurant_menu/" + store_file #이 부분 해당 버킷 생성 후 적절히 수정 예정
392 | bucket.download_file(store_file, local_file)
393 |
394 | except Exception:
395 | return gen.set_text(
396 | "[File-Open-Error #131] 저장소에서 파일을 가져오는데 실패했습니다" + imoge_mapping['emotion']['sad']) # 파일을 /tmp/에 복사하여 다운로드
397 |
398 | try:
399 | meal_gen = Generator.Return_Type()
400 | t = ['월', '화', '수', '목', '금', '토', '일']
401 | return_string = ''
402 | with open(local_file, "r", encoding='UTF-8') as f:
403 | data = f.readlines()
404 | for restaurant in range(0, len(data), 2):
405 | menu_list = data[restaurant + 1].replace("\'", '').split(", ")
406 | last_update_date = datetime.date.fromisoformat(menu_list[0])
407 | if restaurant == 2:
408 | continue
409 |
410 | ret = data[restaurant].replace("\n", '').replace("🐾", imoge_mapping['emotion'][
411 | 'walk']) + " [" + str(last_update_date) + " " + t[last_update_date.weekday()] + "요일]\n" + \
412 | imoge_mapping['emotion']['paw'] + "중식 : " + menu_list[1] + "\n" + \
413 | imoge_mapping['emotion']['paw'] + "석식 : " + menu_list[2]
414 |
415 | meal_gen.set_text(ret, is_init=False)
416 |
417 | return_string = meal_gen.set_text("웰스프레쉬\nhttps://ibook.kpu.ac.kr/Viewer/menu01", is_init=False)
418 | return return_string
419 |
420 | except Exception as e:
421 | return gen.set_text("[File-Open-Error #132] 파일을 여는 중 오류가 발생했어요.." + imoge_mapping['emotion']['sad'] + str(e))
422 |
423 | def reset_meal(self, bot_id, date):
424 | sandol_team = ['d367f2ec55f41b4207156f4b8fce5ce885b05d8c3b238cf8861c55a9012f6f5895',
425 | '339b0444bfabbffa0f13508ea7c45b61675b5720234cca8f73cd7421c22de9e546',
426 | '04eabc8b965bf5ae6cccb122a18521969cc391162e3fd5f61b85efe8bb12e5e98a',
427 | 'def99464e022b38389697fe68d54bbba723d1da291094c19bbf5eaace7b059a997']
428 | if bot_id not in sandol_team:
429 | return gen.set_text("[Permission-Error #141] 권한이 없습니다" + imoge_mapping['emotion']['angry'])
430 |
431 | store_file = "../test_stored_data/restaurant_menu.txt"
432 | s3 = boto3.resource('s3')
433 | bucket = s3.Bucket("sandol")
434 | local_file = "/tmp/" + store_file
435 |
436 | try:
437 | # local_file = "./restaurant_menu/" + store_file
438 | s3.meta.client.download_file("sandol", "restaurant_menu.txt", '/tmp/restaurant_menu.txt')
439 |
440 | except Exception as e:
441 | return gen.set_text("[File-Open-Error #142] 저장소에서 파일을 찾을 수 없습니다." + imoge_mapping['emotion']['sad'])
442 | try:
443 | with open(local_file, "w", encoding="UTF-8") as f:
444 | rest_name = [imoge_mapping['emotion']['paw'] + "미가식당\n", imoge_mapping['emotion']['paw'] + "웰스프레쉬\n",
445 | imoge_mapping['emotion']['paw'] + "푸드라운지\n"]
446 |
447 | return_string = ''
448 | for i in range(len(rest_name)):
449 | return_string += rest_name[i] + "\'" + date + "\', \'업데이트되지않았습니다\', \'업데이트되지않았습니다\'\n"
450 | f.writelines(return_string)
451 |
452 | except Exception as e:
453 | return gen.set_text("[File-Open-Error #143]파일을 수정하는 중 오류가 발생했습니다." + imoge_mapping['emotion']['sad'])
454 |
455 | try:
456 | s3 = boto3.client('s3') # 이 부분 해당 버킷 생성 후 적절히 수정 예정
457 | s3.upload_file(local_file, 'sandol', store_file)
458 |
459 | except Exception:
460 | return gen.set_text("[File-Open-Error #144]파일을 저장소에 업로드하는 중 오류가 발생했습니다." + imoge_mapping['emotion']['sad'])
461 | return gen.set_text("파일을 정상적으로 초기화했습니다" + imoge_mapping['emotion']['happy'])
462 |
463 | class Test():
464 | def __init__(self, time: str = "00:00:00", station_no: str = "455") ->None:
465 | self.time = datetime.datetime.strptime(time, '%H:%M:%S') #time 모듈로 변환
466 | self.station_no = station_no
467 | self.rail: str
468 | self.station_name: str
469 | self.data = self.get_data()
470 |
471 | def get_data(self) -> dict:
472 | URL = "https://map.naver.com/v5/api/transit/subway/stations/"+self.station_no+"/schedule?lang=ko&stationID="+self.station_no
473 | html = requests.get(URL).text
474 | soup = BeautifulSoup(html, 'html.parser')
475 |
476 | json_data = json.loads(soup.text)
477 | # print(json_data)
478 | return json_data
479 |
480 | def arrival_time(self) -> str:
481 | return_data = ''
482 |
483 | try:
484 | if self.data['todayServiceDay']['name'] == '평일': # 평일 시간표
485 | schedule_data_up = self.data['weekdaySchedule']['up']
486 | schedule_data_down = self.data['weekdaySchedule']['down']
487 |
488 | it = schedule_data_up.__iter__() # 상행선
489 | flag = False
490 | for i in schedule_data_up:
491 | it.__next__()
492 | if datetime.datetime.strptime(i['departureTime'], '%H:%M:%S') > self.time:
493 | return_data += i['headsign'] +"방면 "+ i['departureTime'] + ", " + it.__next__()['departureTime']
494 | # print(i['departureTime'], end=' ')
495 | # print(it.__next__()['departureTime'])
496 | flag = True
497 | break
498 | else:
499 | continue
500 |
501 | if flag == False:
502 | return_data += schedule_data_up[-1]['headsign'] + schedule_data_up[-1]['departureTime']+ " 막차입니다"
503 |
504 | return_data += "\n\n"
505 |
506 | flag = False
507 | it = schedule_data_down.__iter__() # 하행선
508 | for i in schedule_data_down:
509 | it.__next__()
510 | if datetime.datetime.strptime(i['departureTime'], '%H:%M:%S') > self.time:
511 | return_data += i['headsign'] +"방면 "+i['departureTime'] + ", " + it.__next__()['departureTime']
512 | flag = True
513 | # print(i['departureTime'], end=' ')
514 | # print(it.__next__()['departureTime'], end=' ')
515 | break
516 |
517 | else:
518 | continue
519 |
520 | if flag == False:
521 | return_data += schedule_data_down[-1]['headsign'] + schedule_data_down[-1]['departureTime']+ " 막차입니다"
522 |
523 | else: # 주말 시간표
524 | schedule_data_up = self.data['sundaySchedule']['up']
525 | schedule_data_down = self.data['sundaySchedule']['down']
526 |
527 | flag = False
528 |
529 | it = schedule_data_up.__iter__()
530 | for i in schedule_data_up:
531 | it.__next__()
532 | if datetime.datetime.strptime(i['departureTime'], '%H:%M:%S') > self.time:
533 | return_data += i['headsign'] +"방면 "+i['departureTime'] + ", " + it.__next__()['departureTime']
534 | flag = True
535 | # print(i['departureTime'], end=' ')
536 | # print(it.__next__()['departureTime'])
537 | break
538 |
539 | else:
540 | continue
541 |
542 | if flag == False:
543 | return_data += schedule_data_up[-1]['headsign'] +schedule_data_up[-1]['departureTime']+ " 막차입니다"
544 | return_data += "\n\n"
545 |
546 | flag = False
547 | it = schedule_data_down.__iter__()
548 | for i in schedule_data_down:
549 | it.__next__()
550 | if datetime.datetime.strptime(i['departureTime'], '%H:%M:%S') > self.time:
551 | return_data += i['headsign'] +"방면 "+i['departureTime'] + ", " + it.__next__()['departureTime']
552 | flag = True
553 | # print(i['departureTime'], end=' ')
554 | # print(it.__next__()['departureTime'])
555 | break
556 |
557 | else:
558 | continue
559 |
560 | if flag == False:
561 | return_data += schedule_data_down[-1]['headsign'] +schedule_data_down[-1]['departureTime'] + " 막차입니다"
562 |
563 | except Exception as e:
564 | return str(e)
565 |
566 | return return_data
567 |
568 | def get_time(self):
569 | return gen.set_text(self.time)
570 | #boto3 주석 해제하기
571 | # print(Test("23:59:11", "455").arrival_time())
--------------------------------------------------------------------------------
/statistic/sandol_200109-211018.csv:
--------------------------------------------------------------------------------
1 | ,날짜,활성사용자,웰컴 및 event 수신 제외 활성사용자,신규 사용자,재방문사용자,누적사용자,전체 세션 수,세션 당 평균 메시지 수,친구수,채널 추가수 합계,채팅 요청 친구수
2 | 0,2020-01-09,1,1,1,0,1,2,2.0,1,1,1
3 | 1,2020-01-10,0,0,0,0,1,0,0.0,1,0,0
4 | 2,2020-01-11,0,0,0,0,1,0,0.0,1,0,0
5 | 3,2020-01-12,1,1,0,1,1,1,1.0,1,0,1
6 | 4,2020-01-13,1,1,1,0,2,1,3.0,1,0,1
7 | 5,2020-01-14,1,1,0,1,2,1,3.0,1,0,1
8 | 6,2020-01-15,0,0,0,0,2,0,0.0,1,0,0
9 | 7,2020-01-16,8,7,7,1,9,9,3.56,7,6,7
10 | 8,2020-01-17,1,1,0,1,9,1,14.0,7,0,1
11 | 9,2020-01-18,0,0,0,0,9,0,0.0,7,0,0
12 | 10,2020-01-19,1,1,1,0,10,1,4.0,7,0,1
13 | 11,2020-01-20,1,1,0,1,10,1,3.0,7,0,1
14 | 12,2020-01-21,1,1,0,1,10,1,2.0,7,0,1
15 | 13,2020-01-22,1,1,0,1,10,1,1.0,7,0,1
16 | 14,2020-01-23,0,0,0,0,10,0,0.0,7,0,0
17 | 15,2020-01-24,0,0,0,0,10,0,0.0,7,0,0
18 | 16,2020-01-25,0,0,0,0,10,0,0.0,7,0,0
19 | 17,2020-01-26,1,1,0,1,10,2,2.0,7,0,1
20 | 18,2020-01-27,0,0,0,0,10,0,0.0,7,0,0
21 | 19,2020-01-28,19,16,18,1,28,32,3.94,20,13,15
22 | 20,2020-01-29,19,19,9,10,37,41,4.32,27,7,18
23 | 21,2020-01-30,29,25,21,8,58,42,3.36,44,17,21
24 | 22,2020-01-31,10,10,4,6,62,14,2.93,47,3,10
25 | 23,2020-02-01,6,6,2,4,64,10,3.0,49,2,5
26 | 24,2020-02-02,7,7,1,6,65,9,3.11,49,0,7
27 | 25,2020-02-03,37,34,26,11,91,45,3.29,74,25,32
28 | 26,2020-02-04,32,32,14,18,105,42,2.1,83,9,31
29 | 27,2020-02-05,32,32,11,21,116,48,2.63,89,6,31
30 | 28,2020-02-06,40,40,10,30,126,50,1.88,97,8,33
31 | 29,2020-02-07,30,30,3,27,129,42,1.5,100,3,28
32 | 30,2020-02-08,7,7,4,3,133,7,5.0,104,4,7
33 | 31,2020-02-09,3,3,0,3,133,4,1.0,104,0,2
34 | 32,2020-02-10,24,24,4,20,137,30,1.57,108,4,23
35 | 33,2020-02-11,32,31,4,28,141,49,1.71,111,3,29
36 | 34,2020-02-12,33,32,14,19,155,50,2.36,125,14,30
37 | 35,2020-02-13,77,67,45,32,200,125,2.23,169,44,64
38 | 36,2020-02-14,46,44,11,35,211,59,1.63,180,11,42
39 | 37,2020-02-15,10,10,2,8,213,11,2.0,181,1,10
40 | 38,2020-02-16,2,2,0,2,213,2,1.0,181,0,2
41 | 39,2020-02-17,40,40,2,38,215,89,2.48,183,2,38
42 | 40,2020-02-18,48,47,6,42,221,70,2.0,189,6,41
43 | 41,2020-02-19,45,44,8,37,229,98,2.51,193,4,43
44 | 42,2020-02-20,40,40,3,37,232,47,1.81,194,1,35
45 | 43,2020-02-21,28,28,1,27,233,53,2.02,194,0,25
46 | 44,2020-02-22,5,5,1,4,234,5,2.4,194,1,5
47 | 45,2020-02-23,2,2,0,2,234,2,1.5,194,0,1
48 | 46,2020-02-24,34,34,3,31,237,55,2.02,195,1,30
49 | 47,2020-02-25,35,34,6,29,243,60,2.08,201,6,33
50 | 48,2020-02-26,32,32,4,28,247,53,1.91,204,4,28
51 | 49,2020-02-27,30,30,1,29,248,35,1.49,205,1,27
52 | 50,2020-02-28,24,24,2,22,250,31,1.9,207,2,22
53 | 51,2020-02-29,5,5,0,5,250,5,2.4,207,0,5
54 | 52,2020-03-01,5,5,0,5,250,5,1.6,207,0,5
55 | 53,2020-03-02,28,28,3,25,253,34,1.44,208,1,25
56 | 54,2020-03-03,31,31,1,30,254,44,1.48,209,1,27
57 | 55,2020-03-04,36,36,5,31,259,40,2.02,213,4,33
58 | 56,2020-03-05,33,33,4,29,263,40,1.85,215,2,32
59 | 57,2020-03-06,33,33,5,28,268,57,1.21,220,5,29
60 | 58,2020-03-07,7,7,0,7,268,7,4.0,220,0,7
61 | 59,2020-03-08,5,5,2,3,270,6,2.5,222,2,4
62 | 60,2020-03-09,38,38,3,35,273,44,1.59,224,2,36
63 | 61,2020-03-10,34,34,3,31,276,42,1.33,226,3,25
64 | 62,2020-03-11,43,43,3,40,279,57,1.79,228,2,37
65 | 63,2020-03-12,40,40,1,39,280,65,1.58,229,1,40
66 | 64,2020-03-13,42,42,3,39,283,48,1.42,230,1,38
67 | 65,2020-03-14,5,5,2,3,285,8,4.13,231,2,5
68 | 66,2020-03-15,1,1,0,1,285,2,1.0,231,0,1
69 | 67,2020-03-16,36,36,1,35,286,44,1.25,231,0,34
70 | 68,2020-03-17,50,50,1,49,287,54,1.52,232,1,46
71 | 69,2020-03-18,44,44,3,41,290,52,1.42,234,2,40
72 | 70,2020-03-19,44,44,3,41,293,67,2.25,234,0,39
73 | 71,2020-03-20,39,39,2,37,295,67,2.94,236,2,36
74 | 72,2020-03-21,5,5,0,5,295,5,1.2,236,0,5
75 | 73,2020-03-22,2,2,0,2,295,2,1.0,236,0,2
76 | 74,2020-03-23,43,43,2,41,297,58,1.63,237,1,39
77 | 75,2020-03-24,46,46,4,42,301,63,1.62,240,3,44
78 | 76,2020-03-25,38,38,1,37,302,42,1.31,240,0,31
79 | 77,2020-03-26,40,40,4,36,306,43,1.65,242,2,35
80 | 78,2020-03-27,37,37,1,36,307,53,1.66,243,1,32
81 | 79,2020-03-28,0,0,0,0,307,0,0.0,243,0,0
82 | 80,2020-03-29,2,2,1,1,308,2,2.0,243,0,2
83 | 81,2020-03-30,42,42,2,40,310,73,1.81,244,1,40
84 | 82,2020-03-31,43,43,1,42,311,60,1.35,245,1,35
85 | 83,2020-04-01,42,42,2,40,313,45,1.49,247,2,33
86 | 84,2020-04-02,45,45,4,41,317,53,1.38,250,3,40
87 | 85,2020-04-03,0,43,0,0,317,58,1.66,255,5,37
88 | 86,2020-04-04,0,3,0,0,317,3,2.0,256,1,3
89 | 87,2020-04-05,0,0,0,0,317,0,0.0,256,0,0
90 | 88,2020-04-06,0,47,0,0,317,51,1.35,258,2,40
91 | 89,2020-04-07,0,45,0,0,317,80,1.56,258,0,41
92 | 90,2020-04-08,0,50,0,0,317,56,1.52,261,3,43
93 | 91,2020-04-09,0,44,0,0,317,49,1.45,262,1,38
94 | 92,2020-04-10,0,42,0,0,317,95,2.18,266,4,38
95 | 93,2020-04-11,0,2,0,0,317,2,2.0,266,0,2
96 | 94,2020-04-12,0,1,0,0,317,1,1.0,266,0,1
97 | 95,2020-04-13,0,44,0,0,317,75,1.37,266,0,37
98 | 96,2020-04-14,0,36,0,0,317,64,1.91,266,0,33
99 | 97,2020-04-15,0,9,0,0,317,12,1.42,266,0,8
100 | 98,2020-04-16,0,49,0,0,317,83,1.43,270,4,47
101 | 99,2020-04-17,0,37,0,0,317,67,1.63,271,1,33
102 | 100,2020-04-18,0,1,0,0,317,1,1.0,271,0,1
103 | 101,2020-04-19,0,1,0,0,317,1,1.0,271,0,0
104 | 102,2020-04-20,0,45,0,0,317,61,1.54,272,1,41
105 | 103,2020-04-21,0,38,0,0,317,44,1.59,274,2,34
106 | 104,2020-04-22,0,45,0,0,317,55,1.38,275,1,41
107 | 105,2020-04-23,0,45,0,0,317,57,1.28,275,0,40
108 | 106,2020-04-24,0,36,0,0,317,66,1.52,276,1,33
109 | 107,2020-04-25,0,2,0,0,317,3,1.67,276,0,2
110 | 108,2020-04-26,0,0,0,0,317,0,0.0,276,0,0
111 | 109,2020-04-27,0,48,0,0,317,57,1.46,277,1,45
112 | 110,2020-04-28,0,32,0,0,317,42,1.29,278,1,25
113 | 111,2020-04-29,0,28,0,0,317,30,1.23,278,0,24
114 | 112,2020-04-30,0,5,0,0,317,5,1.4,278,0,5
115 | 113,2020-05-01,0,21,0,0,317,37,1.43,278,0,20
116 | 114,2020-05-02,0,2,0,0,317,2,1.0,278,0,2
117 | 115,2020-05-03,0,4,0,0,317,4,4.25,279,1,3
118 | 116,2020-05-04,0,27,0,0,317,44,1.66,283,4,23
119 | 117,2020-05-05,0,6,0,0,317,6,2.5,283,0,7
120 | 118,2020-05-06,0,33,0,0,317,38,1.26,284,1,31
121 | 119,2020-05-07,0,39,0,0,317,48,1.19,285,1,35
122 | 120,2020-05-08,0,36,0,0,317,43,1.49,286,1,32
123 | 121,2020-05-09,0,4,0,0,317,4,1.75,287,1,4
124 | 122,2020-05-10,0,5,0,0,317,5,2.8,287,0,5
125 | 123,2020-05-11,0,106,0,0,317,151,2.72,352,65,102
126 | 124,2020-05-12,0,78,0,0,317,90,1.84,365,13,71
127 | 125,2020-05-13,0,92,0,0,317,106,1.8,374,9,84
128 | 126,2020-05-14,0,84,0,0,317,101,1.43,380,6,71
129 | 127,2020-05-15,0,71,0,0,317,84,1.82,390,10,65
130 | 128,2020-05-16,0,15,0,0,317,18,2.44,392,2,13
131 | 129,2020-05-17,0,7,0,0,317,7,1.71,393,1,7
132 | 130,2020-05-18,0,77,0,0,317,90,1.44,396,3,73
133 | 131,2020-05-19,0,90,0,0,317,140,1.96,405,9,85
134 | 132,2020-05-20,0,80,0,0,317,118,1.67,407,2,72
135 | 133,2020-05-21,0,80,0,0,317,94,1.5,413,6,72
136 | 134,2020-05-22,0,69,0,0,317,85,1.51,416,3,59
137 | 135,2020-05-23,0,10,0,0,317,10,2.8,416,0,10
138 | 136,2020-05-24,0,3,0,0,317,4,1.25,416,0,2
139 | 137,2020-05-25,0,90,0,0,317,121,1.68,423,7,82
140 | 138,2020-05-26,0,74,0,0,317,82,1.45,428,5,70
141 | 139,2020-05-27,0,83,0,0,317,98,1.84,434,6,75
142 | 140,2020-05-28,0,84,0,0,317,93,1.4,437,3,77
143 | 141,2020-05-29,0,74,0,0,317,96,1.55,441,4,70
144 | 142,2020-05-30,18,17,3,15,547,22,2.73,444,3,15
145 | 143,2020-05-31,0,12,0,0,547,13,1.46,444,0,11
146 | 144,2020-06-01,0,91,0,0,547,108,1.39,445,1,79
147 | 145,2020-06-02,0,98,0,0,547,121,1.54,447,2,89
148 | 146,2020-06-03,0,90,0,0,547,120,1.49,450,3,76
149 | 147,2020-06-04,0,90,0,0,547,104,1.48,452,2,81
150 | 148,2020-06-05,0,84,0,0,547,125,1.7,454,2,76
151 | 149,2020-06-06,0,20,0,0,547,21,1.95,457,3,19
152 | 150,2020-06-07,0,2,0,0,547,2,1.0,457,0,1
153 | 151,2020-06-08,0,108,0,0,547,133,1.56,462,5,99
154 | 152,2020-06-09,0,100,0,0,547,118,1.5,470,9,86
155 | 153,2020-06-10,99,99,4,95,585,132,1.55,472,2,90
156 | 154,2020-06-11,0,104,0,0,585,114,1.64,479,7,91
157 | 155,2020-06-12,0,104,0,0,585,116,1.39,482,3,94
158 | 156,2020-06-13,0,24,0,0,585,28,2.07,483,1,23
159 | 157,2020-06-14,0,15,0,0,585,17,2.12,483,0,13
160 | 158,2020-06-15,0,107,0,0,585,126,1.4,486,3,95
161 | 159,2020-06-16,0,111,0,0,585,122,1.32,487,1,95
162 | 160,2020-06-17,0,112,0,0,585,134,1.69,498,11,101
163 | 161,2020-06-18,0,124,0,0,585,164,1.48,504,6,114
164 | 162,2020-06-19,0,117,0,0,585,136,1.38,507,3,96
165 | 163,2020-06-20,0,42,0,0,585,48,2.0,518,11,38
166 | 164,2020-06-21,0,18,0,0,585,19,1.84,520,2,17
167 | 165,2020-06-22,0,128,0,0,585,152,1.46,525,5,118
168 | 166,2020-06-23,0,124,0,0,585,139,1.47,528,3,114
169 | 167,2020-06-24,0,102,0,0,585,126,1.74,533,5,90
170 | 168,2020-06-25,0,109,0,0,585,126,1.38,537,4,100
171 | 169,2020-06-26,0,86,0,0,585,127,1.5,538,1,76
172 | 170,2020-06-27,0,12,0,0,585,12,1.92,539,1,10
173 | 171,2020-06-28,0,1,0,0,585,1,2.0,539,0,1
174 | 172,2020-06-29,0,79,0,0,585,108,1.44,543,4,72
175 | 173,2020-06-30,0,62,0,0,585,75,1.32,543,0,58
176 | 174,2020-07-01,0,63,0,0,585,91,1.49,545,2,59
177 | 175,2020-07-02,0,62,0,0,585,83,1.25,545,0,56
178 | 176,2020-07-03,0,50,0,0,585,64,1.59,546,1,49
179 | 177,2020-07-04,0,4,0,0,585,4,1.5,546,0,4
180 | 178,2020-07-05,0,8,0,0,585,8,1.5,547,1,8
181 | 179,2020-07-06,0,61,0,0,585,88,1.28,547,0,58
182 | 180,2020-07-07,0,68,0,0,585,89,1.31,550,3,64
183 | 181,2020-07-08,0,82,0,0,585,104,1.4,556,6,73
184 | 182,2020-07-09,0,67,0,0,585,80,1.38,558,2,60
185 | 183,2020-07-10,0,47,0,0,585,57,1.37,558,0,43
186 | 184,2020-07-11,0,7,0,0,585,7,1.57,559,1,4
187 | 185,2020-07-12,0,5,0,0,585,5,1.4,558,0,4
188 | 186,2020-07-13,0,69,0,0,585,96,1.45,562,4,65
189 | 187,2020-07-14,0,68,0,0,585,83,1.37,564,2,62
190 | 188,2020-07-15,0,75,0,0,585,127,1.72,567,3,65
191 | 189,2020-07-16,0,0,0,0,585,97,1.43,575,8,73
192 | 190,2020-07-17,0,55,0,0,585,64,1.36,575,0,49
193 | 191,2020-07-18,0,9,0,0,585,11,2.45,575,0,8
194 | 192,2020-07-19,0,5,0,0,585,6,1.83,575,0,5
195 | 193,2020-07-20,0,76,0,0,585,101,1.46,580,5,71
196 | 194,2020-07-21,0,93,0,0,585,118,1.46,588,8,76
197 | 195,2020-07-22,0,93,0,0,585,121,1.41,594,6,84
198 | 196,2020-07-23,0,87,0,0,585,121,1.31,594,0,72
199 | 197,2020-07-24,0,83,0,0,585,109,1.37,600,6,78
200 | 198,2020-07-25,0,7,0,0,585,8,1.5,600,0,7
201 | 199,2020-07-26,0,3,0,0,585,3,1.67,601,1,3
202 | 200,2020-07-27,0,75,0,0,585,80,1.21,601,1,69
203 | 201,2020-07-28,0,79,0,0,585,91,1.43,603,2,73
204 | 202,2020-07-29,0,79,0,0,585,92,1.25,603,0,68
205 | 203,2020-07-30,0,78,0,0,585,82,1.27,604,1,62
206 | 204,2020-07-31,0,62,0,0,585,77,1.48,606,2,53
207 | 205,2020-08-01,0,1,0,0,585,1,1.0,606,0,1
208 | 206,2020-08-02,0,2,0,0,585,2,1.0,606,0,2
209 | 207,2020-08-03,50,60,17,33,602,75,1.35,607,1,53
210 | 208,2020-08-04,0,65,0,0,602,76,1.2,610,3,57
211 | 209,2020-08-05,0,66,0,0,602,70,1.26,610,0,55
212 | 210,2020-08-06,0,59,0,0,602,69,1.13,610,0,52
213 | 211,2020-08-07,0,60,0,0,602,76,1.47,611,1,52
214 | 212,2020-08-08,0,6,0,0,602,7,1.29,611,0,6
215 | 213,2020-08-09,0,2,0,0,602,2,3.0,611,0,2
216 | 214,2020-08-10,0,56,0,0,602,63,1.29,612,1,50
217 | 215,2020-08-11,0,58,0,0,602,85,1.46,613,1,54
218 | 216,2020-08-12,0,61,0,0,602,68,1.3,616,4,52
219 | 217,2020-08-13,0,75,0,0,602,84,1.35,616,1,66
220 | 218,2020-08-14,0,33,0,0,602,35,2.14,616,0,27
221 | 219,2020-08-15,0,5,0,0,602,5,1.2,616,0,3
222 | 220,2020-08-16,0,5,0,0,602,5,1.0,616,0,4
223 | 221,2020-08-17,0,21,0,0,602,31,1.68,616,0,18
224 | 222,2020-08-18,0,68,0,0,602,72,1.14,616,0,52
225 | 223,2020-08-19,0,52,0,0,602,58,1.19,616,0,43
226 | 224,2020-08-20,0,62,0,0,602,71,1.3,617,1,54
227 | 225,2020-08-21,0,45,0,0,602,58,1.43,617,0,36
228 | 226,2020-08-22,0,5,0,0,602,5,2.6,617,0,5
229 | 227,2020-08-23,0,0,0,0,602,0,0.0,617,0,0
230 | 228,2020-08-24,0,46,0,0,602,54,1.46,617,0,39
231 | 229,2020-08-25,0,48,0,0,602,74,1.64,617,0,43
232 | 230,2020-08-26,0,53,0,0,602,58,1.21,618,1,44
233 | 231,2020-08-27,0,45,0,0,602,49,1.33,619,1,39
234 | 232,2020-08-28,0,0,0,0,602,36,1.39,623,5,29
235 | 233,2020-08-29,0,2,0,0,602,2,1.5,623,0,1
236 | 234,2020-08-30,0,2,0,0,602,3,1.0,623,0,2
237 | 235,2020-08-31,0,43,0,0,602,49,1.39,624,1,35
238 | 236,2020-09-01,41,41,0,41,778,50,1.3,624,0,33
239 | 237,2020-09-02,44,44,0,44,778,48,1.27,623,0,38
240 | 238,2020-09-03,0,49,0,0,778,58,1.31,624,1,44
241 | 239,2020-09-04,0,38,0,0,778,41,1.29,625,1,32
242 | 240,2020-09-05,0,3,0,0,778,3,1.67,625,0,3
243 | 241,2020-09-06,0,5,0,0,778,6,1.33,625,0,3
244 | 242,2020-09-07,0,44,0,0,778,49,1.33,625,0,36
245 | 243,2020-09-08,0,55,0,0,778,62,1.42,629,4,53
246 | 244,2020-09-09,0,57,0,0,778,67,1.45,632,3,48
247 | 245,2020-09-10,0,58,0,0,778,74,1.58,633,1,50
248 | 246,2020-09-11,0,58,0,0,778,73,1.34,633,0,44
249 | 247,2020-09-12,0,8,0,0,778,10,2.3,633,0,5
250 | 248,2020-09-13,0,8,0,0,778,11,1.45,633,0,7
251 | 249,2020-09-14,0,95,0,0,778,127,1.46,638,5,74
252 | 250,2020-09-15,0,96,0,0,778,115,1.59,644,7,75
253 | 251,2020-09-16,0,115,0,0,778,148,1.46,649,6,92
254 | 252,2020-09-17,0,101,0,0,778,126,1.41,651,2,73
255 | 253,2020-09-18,0,100,0,0,778,129,1.74,670,19,75
256 | 254,2020-09-19,16,16,4,12,842,22,2.05,674,4,12
257 | 255,2020-09-20,16,16,2,14,844,17,2.24,675,1,11
258 | 256,2020-09-21,138,137,9,129,853,166,1.39,684,9,107
259 | 257,2020-09-22,120,120,10,110,863,155,1.53,692,9,94
260 | 258,2020-09-23,141,141,16,125,879,167,1.51,708,16,102
261 | 259,2020-09-24,139,139,6,133,885,164,1.57,713,6,104
262 | 260,2020-09-25,114,114,3,111,888,142,1.61,716,3,95
263 | 261,2020-09-26,15,15,5,10,893,16,3.0,719,3,12
264 | 262,2020-09-27,10,10,1,9,894,12,1.83,720,1,10
265 | 263,2020-09-28,129,129,3,126,897,158,1.4,720,1,104
266 | 264,2020-09-29,96,96,4,92,901,127,1.47,723,3,73
267 | 265,2020-09-30,12,11,2,10,903,12,1.83,726,3,10
268 | 266,2020-10-01,4,3,3,1,906,4,2.5,728,3,2
269 | 267,2020-10-02,4,4,0,4,906,4,3.0,728,0,3
270 | 268,2020-10-03,6,6,1,5,907,7,3.0,729,1,6
271 | 269,2020-10-04,6,6,1,5,908,7,3.14,729,1,6
272 | 270,2020-10-05,137,137,10,127,918,181,1.62,740,11,110
273 | 271,2020-10-06,161,161,11,150,929,187,1.5,749,9,124
274 | 272,2020-10-07,165,164,14,151,943,213,1.46,762,15,129
275 | 273,2020-10-08,161,161,8,153,951,186,1.48,771,9,119
276 | 274,2020-10-09,43,43,3,40,954,62,1.9,773,2,39
277 | 275,2020-10-10,17,17,2,15,956,20,2.2,775,2,16
278 | 276,2020-10-11,12,12,0,12,956,14,1.71,775,0,10
279 | 277,2020-10-12,168,168,12,156,968,205,1.47,785,10,142
280 | 278,2020-10-13,186,183,12,174,980,214,1.44,795,10,153
281 | 279,2020-10-14,156,156,4,152,984,178,1.46,798,4,120
282 | 280,2020-10-15,186,185,16,170,1000,223,1.56,814,16,144
283 | 281,2020-10-16,148,147,9,139,1009,175,1.55,821,7,111
284 | 282,2020-10-17,32,32,2,30,1011,35,2.06,823,2,24
285 | 283,2020-10-18,11,11,0,11,1011,11,1.36,823,0,8
286 | 284,2020-10-19,196,195,13,183,1024,287,1.64,831,8,166
287 | 285,2020-10-20,193,193,9,184,1033,220,1.49,838,8,155
288 | 286,2020-10-21,201,200,7,194,1040,239,1.36,845,7,146
289 | 287,2020-10-22,200,200,17,183,1057,296,1.7,859,14,167
290 | 288,2020-10-23,177,176,30,147,1087,217,1.85,886,27,137
291 | 289,2020-10-24,30,30,1,29,1088,33,1.85,887,1,22
292 | 290,2020-10-25,20,20,0,20,1088,21,2.48,887,0,19
293 | 291,2020-10-26,180,180,4,176,1092,217,1.4,890,3,145
294 | 292,2020-10-27,165,165,1,164,1093,187,1.4,893,3,132
295 | 293,2020-10-28,164,164,8,156,1101,184,1.48,898,6,129
296 | 294,2020-10-29,156,156,6,150,1107,188,1.47,904,6,126
297 | 295,2020-10-30,107,107,3,104,1110,115,1.5,906,2,85
298 | 296,2020-10-31,9,9,1,8,1111,10,1.6,906,1,7
299 | 297,2020-11-01,9,9,0,9,1111,10,1.2,906,0,5
300 | 298,2020-11-02,184,184,12,172,1123,232,1.66,918,12,151
301 | 299,2020-11-03,175,174,2,173,1125,199,1.48,921,3,141
302 | 300,2020-11-04,170,170,7,163,1132,185,1.5,926,5,125
303 | 301,2020-11-05,227,226,14,213,1146,272,1.56,936,11,161
304 | 302,2020-11-06,132,132,3,129,1149,152,1.43,939,3,100
305 | 303,2020-11-07,19,19,2,17,1151,19,1.84,941,2,16
306 | 304,2020-11-08,10,10,0,10,1151,10,1.8,941,0,9
307 | 305,2020-11-09,188,188,7,181,1158,210,1.46,948,7,148
308 | 306,2020-11-10,225,225,10,215,1168,388,1.79,956,8,192
309 | 307,2020-11-11,212,211,15,197,1183,256,1.61,969,14,176
310 | 308,2020-11-12,238,237,15,223,1198,278,1.72,982,13,184
311 | 309,2020-11-13,149,148,5,144,1203,165,1.53,986,4,113
312 | 310,2020-11-14,15,15,0,15,1203,15,1.87,986,0,12
313 | 311,2020-11-15,13,13,1,12,1204,13,1.54,987,1,9
314 | 312,2020-11-16,219,219,5,214,1209,299,1.47,992,5,182
315 | 313,2020-11-17,245,244,9,236,1218,301,1.5,998,6,177
316 | 314,2020-11-18,232,231,7,225,1225,284,1.51,1005,7,170
317 | 315,2020-11-19,220,220,7,213,1232,190,1.55,1012,7,176
318 | 316,2020-11-20,165,165,4,161,1236,278,1.7,1014,3,142
319 | 317,2020-11-21,21,21,2,19,1238,22,2.14,1015,1,17
320 | 318,2020-11-22,12,12,0,12,1238,13,2.38,1015,0,9
321 | 319,2020-11-23,196,196,4,192,1242,258,1.45,1019,4,150
322 | 320,2020-11-24,200,200,6,194,1248,232,1.56,1025,6,152
323 | 321,2020-11-25,190,189,8,182,1256,220,1.45,1034,9,146
324 | 322,2020-11-26,196,196,2,194,1258,217,1.44,1036,2,152
325 | 323,2020-11-27,136,136,4,132,1262,195,1.69,1038,2,109
326 | 324,2020-11-28,24,24,0,24,1262,25,2.08,1038,0,16
327 | 325,2020-11-29,8,8,0,8,1262,8,1.63,1038,0,7
328 | 326,2020-11-30,181,181,2,179,1264,236,1.62,1041,3,137
329 | 327,2020-12-01,183,183,1,182,1265,221,1.43,1042,1,141
330 | 328,2020-12-02,207,207,10,197,1275,225,1.4,1052,10,161
331 | 329,2020-12-03,195,195,8,187,1283,226,1.51,1059,7,142
332 | 330,2020-12-04,185,185,6,179,1289,235,1.55,1063,4,149
333 | 331,2020-12-05,34,34,2,32,1291,41,1.68,1065,2,25
334 | 332,2020-12-06,25,25,1,24,1292,26,1.92,1065,1,20
335 | 333,2020-12-07,200,200,6,194,1298,231,1.42,1069,4,149
336 | 334,2020-12-08,208,208,4,204,1302,249,1.39,1072,3,152
337 | 335,2020-12-09,216,216,3,213,1305,238,1.34,1074,2,157
338 | 336,2020-12-10,195,195,2,193,1307,335,1.67,1076,2,163
339 | 337,2020-12-11,148,148,4,144,1311,169,1.52,1080,4,115
340 | 338,2020-12-12,34,34,1,33,1312,38,1.42,1079,0,27
341 | 339,2020-12-13,19,19,2,17,1314,20,1.55,1081,2,11
342 | 340,2020-12-14,173,173,1,172,1315,220,1.4,1082,1,143
343 | 341,2020-12-15,160,160,8,152,1323,207,1.5,1087,5,127
344 | 342,2020-12-16,175,175,2,173,1325,232,1.45,1087,1,129
345 | 343,2020-12-17,132,132,1,131,1326,175,1.58,1088,1,104
346 | 344,2020-12-18,84,84,2,82,1328,92,1.4,1088,1,63
347 | 345,2020-12-19,13,13,0,13,1328,13,1.38,1088,0,9
348 | 346,2020-12-20,6,6,0,6,1328,6,1.33,1088,0,3
349 | 347,2020-12-21,52,52,2,50,1330,75,1.67,1090,2,44
350 | 348,2020-12-22,43,43,0,43,1330,56,1.48,1090,0,35
351 | 349,2020-12-23,41,41,0,41,1330,47,1.34,1090,0,33
352 | 350,2020-12-24,20,20,0,20,1330,23,1.43,1090,0,15
353 | 351,2020-12-25,3,3,0,3,1330,5,1.6,1090,0,2
354 | 352,2020-12-26,3,3,0,3,1330,3,2.0,1091,1,3
355 | 353,2020-12-27,4,4,0,4,1330,4,1.5,1091,0,4
356 | 354,2020-12-28,45,45,0,45,1330,72,1.4,1091,0,34
357 | 355,2020-12-29,36,36,1,35,1331,48,1.56,1092,1,30
358 | 356,2020-12-30,31,31,0,31,1331,54,1.69,1091,0,24
359 | 357,2020-12-31,24,24,0,24,1331,33,1.61,1091,0,20
360 | 358,2021-01-01,1,1,0,1,1331,1,1.0,1091,0,1
361 | 359,2021-01-02,1,1,0,1,1331,1,2.0,1091,0,1
362 | 360,2021-01-03,4,4,1,3,1332,5,1.4,1091,0,3
363 | 361,2021-01-04,49,49,0,49,1332,59,1.31,1091,0,36
364 | 362,2021-01-05,54,54,2,52,1334,97,1.55,1093,2,44
365 | 363,2021-01-06,63,62,5,58,1339,72,1.46,1096,3,46
366 | 364,2021-01-07,64,64,5,59,1344,80,1.82,1098,3,52
367 | 365,2021-01-08,33,33,1,32,1345,37,2.19,1099,1,25
368 | 366,2021-01-09,4,4,0,4,1345,5,1.4,1099,0,3
369 | 367,2021-01-10,5,4,1,4,1346,5,1.6,1100,1,2
370 | 368,2021-01-11,54,54,1,53,1347,66,1.71,1101,1,49
371 | 369,2021-01-12,58,58,3,55,1350,68,1.53,1103,2,41
372 | 370,2021-01-13,65,65,7,58,1357,70,1.54,1107,5,51
373 | 371,2021-01-14,55,55,1,54,1358,75,1.59,1108,2,36
374 | 372,2021-01-15,38,38,1,37,1359,43,1.4,1109,2,26
375 | 373,2021-01-16,4,4,0,4,1359,4,1.25,1109,0,2
376 | 374,2021-01-17,3,3,0,3,1359,3,1.33,1109,0,3
377 | 375,2021-01-18,56,56,0,56,1359,60,1.4,1108,0,46
378 | 376,2021-01-19,62,62,2,60,1361,72,1.5,1109,1,46
379 | 377,2021-01-20,57,57,2,55,1363,86,1.53,1111,2,44
380 | 378,2021-01-21,52,52,1,51,1364,62,1.37,1112,1,39
381 | 379,2021-01-22,45,45,0,45,1364,57,1.39,1112,0,36
382 | 380,2021-01-23,3,3,0,3,1364,3,1.67,1112,0,2
383 | 381,2021-01-24,2,2,0,2,1364,2,2.5,1112,0,2
384 | 382,2021-01-25,52,52,0,52,1364,54,1.37,1112,0,38
385 | 383,2021-01-26,48,48,1,47,1365,53,1.49,1112,0,32
386 | 384,2021-01-27,58,58,2,56,1367,86,1.71,1114,2,48
387 | 385,2021-01-28,52,52,5,47,1372,59,1.46,1120,6,42
388 | 386,2021-01-29,49,48,2,47,1374,66,2.06,1121,2,43
389 | 387,2021-01-30,3,3,0,3,1374,3,1.33,1120,0,2
390 | 388,2021-01-31,2,2,0,2,1374,2,2.0,1120,0,1
391 | 389,2021-02-01,46,46,0,46,1374,53,1.38,1120,0,35
392 | 390,2021-02-02,41,41,1,40,1375,56,1.38,1120,1,35
393 | 391,2021-02-03,50,50,1,49,1376,53,1.4,1121,1,41
394 | 392,2021-02-04,51,51,1,50,1377,75,1.45,1121,1,44
395 | 393,2021-02-05,43,42,3,40,1380,48,1.5,1124,4,29
396 | 394,2021-02-06,5,5,1,4,1381,5,1.4,1125,1,4
397 | 395,2021-02-07,3,3,0,3,1381,3,1.33,1125,0,1
398 | 396,2021-02-08,40,40,1,39,1382,53,1.45,1126,1,31
399 | 397,2021-02-09,44,44,1,43,1383,48,1.63,1127,1,32
400 | 398,2021-02-10,21,21,0,21,1383,31,1.55,1127,0,18
401 | 399,2021-02-11,2,2,1,1,1384,3,1.67,1128,1,2
402 | 400,2021-02-12,2,2,0,2,1384,2,1.5,1128,0,2
403 | 401,2021-02-13,0,0,0,0,1384,0,0.0,1128,0,0
404 | 402,2021-02-14,2,2,0,2,1384,3,1.33,1128,0,2
405 | 403,2021-02-15,43,43,0,43,1384,59,1.34,1128,0,33
406 | 404,2021-02-16,38,38,0,38,1384,39,1.49,1128,0,29
407 | 405,2021-02-17,48,47,2,46,1386,60,1.43,1129,1,39
408 | 406,2021-02-18,41,38,9,32,1395,44,1.45,1140,11,33
409 | 407,2021-02-19,31,30,11,20,1406,33,2.09,1150,11,29
410 | 408,2021-02-20,12,12,10,2,1416,15,2.93,1160,10,9
411 | 409,2021-02-21,6,6,4,2,1420,6,2.5,1162,3,4
412 | 410,2021-02-22,30,30,2,28,1422,31,1.42,1163,2,23
413 | 411,2021-02-23,29,29,3,26,1425,33,1.52,1166,3,25
414 | 412,2021-02-24,25,27,6,19,1431,32,1.53,1172,6,21
415 | 413,2021-02-25,33,32,5,28,1436,34,1.35,1176,4,29
416 | 414,2021-02-26,24,23,1,23,1437,33,1.82,1177,1,20
417 | 415,2021-02-27,17,17,4,13,1441,18,1.89,1181,4,13
418 | 416,2021-02-28,12,10,6,6,1447,13,1.69,1186,5,6
419 | 417,2021-03-01,31,30,13,18,1460,38,2.42,1195,10,20
420 | 418,2021-03-02,131,130,10,121,1470,169,1.53,1206,11,93
421 | 419,2021-03-03,138,137,15,123,1485,172,1.66,1222,16,113
422 | 420,2021-03-04,176,171,50,126,1535,248,1.97,1269,47,149
423 | 421,2021-03-05,143,140,40,103,1575,214,2.01,1309,40,116
424 | 422,2021-03-06,19,19,2,17,1577,21,1.81,1311,2,16
425 | 423,2021-03-07,19,18,8,11,1585,23,2.39,1319,8,18
426 | 424,2021-03-08,157,157,12,145,1597,181,1.52,1329,11,120
427 | 425,2021-03-09,158,158,16,142,1613,176,1.71,1343,14,125
428 | 426,2021-03-10,217,216,37,180,1650,266,1.84,1371,29,166
429 | 427,2021-03-11,163,163,12,151,1662,167,1.64,1382,11,129
430 | 428,2021-03-12,137,137,6,131,1668,166,1.55,1387,5,108
431 | 429,2021-03-13,41,41,4,37,1672,50,2.16,1389,2,32
432 | 430,2021-03-14,37,36,10,27,1682,42,2.5,1396,7,28
433 | 431,2021-03-15,201,201,12,189,1694,220,1.91,1410,14,152
434 | 432,2021-03-16,227,227,15,212,1709,265,1.63,1424,14,182
435 | 433,2021-03-17,242,240,22,220,1731,322,1.89,1444,21,194
436 | 434,2021-03-18,233,233,25,208,1756,285,1.66,1465,22,182
437 | 435,2021-03-19,160,160,9,151,1765,190,1.61,1475,10,115
438 | 436,2021-03-20,49,49,9,40,1774,57,2.02,1483,8,38
439 | 437,2021-03-21,26,25,6,20,1780,33,2.06,1488,5,21
440 | 438,2021-03-22,244,242,19,225,1799,282,1.7,1505,17,189
441 | 439,2021-03-23,299,299,18,281,1817,347,1.63,1519,15,229
442 | 440,2021-03-24,265,263,27,238,1844,314,1.63,1542,26,207
443 | 441,2021-03-25,268,266,18,250,1862,310,1.63,1560,18,225
444 | 442,2021-03-26,198,197,13,185,1875,232,1.72,1573,13,151
445 | 443,2021-03-27,47,47,6,41,1881,52,1.92,1578,5,36
446 | 444,2021-03-28,24,24,2,22,1883,29,1.76,1578,2,20
447 | 445,2021-03-29,254,253,15,239,1898,315,2.61,1592,15,202
448 | 446,2021-03-30,308,308,20,288,1918,377,2.07,1610,18,253
449 | 447,2021-03-31,260,260,10,250,1928,287,1.58,1620,10,199
450 | 448,2021-04-01,262,260,13,249,1941,332,1.55,1632,13,201
451 | 449,2021-04-02,201,199,12,189,1953,261,2.07,1641,9,159
452 | 450,2021-04-03,25,25,0,25,1953,33,1.94,1641,0,19
453 | 451,2021-04-04,26,25,3,23,1956,27,2.15,1643,2,21
454 | 452,2021-04-05,277,277,11,266,1967,340,1.81,1654,11,223
455 | 453,2021-04-06,263,263,5,258,1972,345,1.76,1659,5,189
456 | 454,2021-04-07,255,255,6,249,1978,283,1.48,1665,7,177
457 | 455,2021-04-08,234,234,7,227,1985,259,1.9,1671,6,176
458 | 456,2021-04-09,227,227,5,222,1990,260,1.97,1676,5,164
459 | 457,2021-04-10,53,53,3,50,1993,67,1.84,1679,3,41
460 | 458,2021-04-11,35,35,3,32,1996,40,2.92,1680,2,32
461 | 459,2021-04-12,243,243,7,236,2003,392,1.9,1687,7,201
462 | 460,2021-04-13,298,298,13,285,2016,327,1.65,1699,12,229
463 | 461,2021-04-14,126,263,10,116,2026,136,1.18,1709,11,201
464 | 462,2021-04-15,270,270,10,260,2036,316,1.66,1719,10,214
465 | 463,2021-04-16,217,217,7,210,2043,258,1.66,1726,7,164
466 | 464,2021-04-17,48,46,2,46,2045,54,1.54,1728,2,34
467 | 465,2021-04-18,25,24,4,21,2049,31,2.32,1732,4,19
468 | 466,2021-04-19,261,261,7,254,2056,295,1.48,1739,7,199
469 | 467,2021-04-20,251,251,5,246,2061,276,1.51,1742,5,187
470 | 468,2021-04-21,254,254,3,251,2064,271,1.41,1745,4,200
471 | 469,2021-04-22,225,225,4,221,2068,267,1.42,1748,4,169
472 | 470,2021-04-23,180,180,5,175,2073,204,1.53,1753,5,138
473 | 471,2021-04-24,35,35,2,33,2075,37,1.73,1755,2,27
474 | 472,2021-04-25,19,19,2,17,2077,23,2.22,1757,2,15
475 | 473,2021-04-26,174,173,4,170,2081,268,2.24,1761,4,174
476 | 474,2021-04-27,215,215,9,206,2090,241,1.54,1771,10,166
477 | 475,2021-04-28,197,197,4,193,2094,217,1.44,1775,5,147
478 | 476,2021-04-29,195,194,4,191,2098,223,1.46,1779,4,139
479 | 477,2021-04-30,137,137,1,136,2099,151,1.38,1778,0,112
480 | 478,2021-05-01,27,26,2,25,2101,37,1.89,1778,2,23
481 | 479,2021-05-02,13,13,1,12,2102,14,1.71,1778,0,9
482 | 480,2021-05-03,206,206,7,199,2109,243,1.46,1785,8,163
483 | 481,2021-05-04,200,200,7,193,2116,230,1.48,1791,6,154
484 | 482,2021-05-05,94,94,3,91,2119,126,1.67,1794,3,76
485 | 483,2021-05-06,193,193,7,186,2126,211,1.47,1797,5,154
486 | 484,2021-05-07,139,139,2,137,2128,149,1.5,1799,2,106
487 | 485,2021-05-08,19,19,0,19,2128,21,1.5,1799,0,14
488 | 486,2021-05-09,18,18,1,17,2129,18,2.1,1800,1,14
489 | 487,2021-05-10,188,188,3,185,2132,219,1.5,1803,3,145
490 | 488,2021-05-11,245,245,7,238,2139,278,1.7,1810,7,194
491 | 489,2021-05-12,227,227,7,220,2146,253,1.6,1817,7,164
492 | 490,2021-05-13,214,214,4,210,2150,266,1.58,1820,3,172
493 | 491,2021-05-14,142,142,6,136,2156,107,1.37,1825,6,112
494 | 492,2021-05-15,23,23,1,22,2157,24,1.9,1824,0,18
495 | 493,2021-05-16,9,9,1,8,2158,12,1.5,1824,0,9
496 | 494,2021-05-17,177,177,2,175,2160,202,1.49,1827,3,185
497 | 495,2021-05-18,202,202,4,198,2164,228,1.46,1831,4,202
498 | 496,2021-05-19,77,77,2,75,2166,95,1.62,1832,2,77
499 | 497,2021-05-20,182,182,4,178,2170,205,1.37,1833,2,182
500 | 498,2021-05-21,211,202,49,162,2219,251,2.36,1881,49,202
501 | 499,2021-05-22,46,43,13,33,2232,59,2.71,1895,14,43
502 | 500,2021-05-23,19,19,5,14,2237,20,2.6,1898,4,19
503 | 501,2021-05-24,219,219,9,210,2246,260,1.56,1904,8,219
504 | 502,2021-05-25,232,232,11,221,2257,263,1.58,1913,9,232
505 | 503,2021-05-26,236,236,7,229,2264,274,1.46,1918,6,236
506 | 504,2021-05-27,229,229,4,225,2268,251,1.57,1922,4,230
507 | 505,2021-05-28,183,183,7,176,2275,227,1.93,1929,7,183
508 | 506,2021-05-29,29,29,2,27,2277,35,2.0,1929,0,29
509 | 507,2021-05-30,14,14,2,12,2279,18,1.72,1931,2,14
510 | 508,2021-05-31,233,233,7,226,2286,263,1.44,1938,7,233
511 | 509,2021-06-01,247,247,4,243,2290,261,1.39,1940,2,247
512 | 510,2021-06-02,235,235,1,234,2291,268,1.38,1941,1,235
513 | 511,2021-06-03,233,233,7,226,2298,262,1.5,1947,7,233
514 | 512,2021-06-04,216,216,4,212,2302,240,1.57,1950,3,216
515 | 513,2021-06-05,52,52,0,52,2302,68,1.54,1949,1,52
516 | 514,2021-06-06,24,24,0,24,2302,24,1.75,1949,0,25
517 | 515,2021-06-07,247,247,2,245,2304,278,1.4,1951,2,247
518 | 516,2021-06-08,258,258,13,245,2317,285,1.49,1963,12,258
519 | 517,2021-06-09,247,247,7,240,2324,268,1.38,1970,7,247
520 | 518,2021-06-10,243,243,4,239,2328,268,1.46,1975,5,243
521 | 519,2021-06-11,204,204,9,195,2337,229,1.56,1984,9,204
522 | 520,2021-06-12,41,41,2,39,2339,51,2.14,1986,2,41
523 | 521,2021-06-13,20,20,1,19,2340,22,2.09,1987,1,20
524 | 522,2021-06-14,217,217,3,214,2343,251,1.45,1990,4,217
525 | 523,2021-06-15,179,179,3,176,2346,193,1.41,1992,3,179
526 | 524,2021-06-16,172,172,2,170,2348,201,1.55,1993,1,172
527 | 525,2021-06-17,159,159,0,159,2348,176,1.46,1994,1,160
528 | 526,2021-06-18,111,111,1,110,2349,118,1.4,1993,1,111
529 | 527,2021-06-19,24,24,0,24,2349,28,1.39,1993,0,24
530 | 528,2021-06-20,3,3,1,2,2350,3,3.0,1994,1,3
531 | 529,2021-06-21,99,99,2,97,2352,117,1.44,1994,1,99
532 | 530,2021-06-22,102,101,7,95,2359,118,1.54,2000,6,101
533 | 531,2021-06-23,84,84,1,83,2360,92,1.34,2001,1,84
534 | 532,2021-06-24,98,98,2,96,2362,108,1.46,2000,1,98
535 | 533,2021-06-25,82,82,0,82,2362,96,1.65,1999,0,82
536 | 534,2021-06-26,9,9,0,9,2362,9,2.11,1999,0,9
537 | 535,2021-06-27,4,4,0,4,2362,4,1.25,1998,0,4
538 | 536,2021-06-28,85,85,1,84,2363,105,1.48,1999,1,85
539 | 537,2021-06-29,92,92,2,90,2365,109,1.83,2001,2,92
540 | 538,2021-06-30,104,104,1,103,2366,121,1.5,2002,1,104
541 | 539,2021-07-01,102,102,5,97,2371,125,1.55,2007,5,102
542 | 540,2021-07-02,78,78,1,77,2372,91,1.47,2007,1,78
543 | 541,2021-07-03,18,18,0,18,2372,19,1.63,2008,1,19
544 | 542,2021-07-04,7,7,1,6,2373,9,5.0,2009,1,7
545 | 543,2021-07-05,100,100,1,99,2374,122,1.61,2010,1,101
546 | 544,2021-07-06,118,118,2,116,2376,141,1.48,2010,2,118
547 | 545,2021-07-07,121,120,3,118,2379,158,1.51,2013,4,120
548 | 546,2021-07-08,106,106,1,105,2380,138,1.3,2014,1,106
549 | 547,2021-07-09,116,115,8,108,2388,152,2.25,2020,6,115
550 | 548,2021-07-10,23,22,2,21,2390,28,2.18,2021,1,22
551 | 549,2021-07-11,3,3,0,3,2390,5,1.4,2021,0,3
552 | 550,2021-07-12,115,115,6,109,2396,142,1.64,2026,5,115
553 | 551,2021-07-13,142,142,2,140,2398,249,2.4,2026,0,142
554 | 552,2021-07-14,120,120,2,118,2400,142,2.28,2026,2,120
555 | 553,2021-07-15,121,121,0,121,2400,167,1.47,2025,0,121
556 | 554,2021-07-16,92,92,2,90,2402,138,1.8,2025,1,92
557 | 555,2021-07-17,21,21,0,21,2402,30,1.4,2025,0,21
558 | 556,2021-07-18,4,4,0,4,2402,4,1.0,2025,0,4
559 | 557,2021-07-19,121,121,2,119,2404,143,1.57,2027,2,121
560 | 558,2021-07-20,113,113,1,112,2405,144,1.47,2028,1,113
561 | 559,2021-07-21,108,108,0,108,2405,135,1.41,2027,0,108
562 | 560,2021-07-22,125,125,0,125,2405,190,1.56,2027,0,125
563 | 561,2021-07-23,101,101,0,101,2405,129,1.37,2027,0,101
564 | 562,2021-07-24,19,19,0,19,2405,26,1.73,2027,0,19
565 | 563,2021-07-25,4,4,0,4,2405,5,1.8,2027,0,4
566 | 564,2021-07-26,120,120,2,118,2407,151,1.32,2028,2,121
567 | 565,2021-07-27,118,118,2,116,2409,144,1.42,2031,3,118
568 | 566,2021-07-28,130,130,3,127,2412,156,1.35,2034,3,130
569 | 567,2021-07-29,120,120,0,120,2412,153,1.35,2035,1,120
570 | 568,2021-07-30,100,100,1,99,2413,133,1.55,2035,0,100
571 | 569,2021-07-31,29,29,1,28,2414,33,1.61,2036,1,30
572 | 570,2021-08-01,3,3,0,3,2414,3,1.0,2036,0,3
573 | 571,2021-08-02,105,105,1,104,2415,127,1.47,2036,0,105
574 | 572,2021-08-03,117,117,2,115,2417,130,1.48,2039,3,117
575 | 573,2021-08-04,112,112,0,112,2417,131,1.49,2039,0,112
576 | 574,2021-08-05,111,111,0,111,2417,124,1.37,2039,0,111
577 | 575,2021-08-06,91,91,0,91,2417,135,1.6,2039,0,91
578 | 576,2021-08-07,24,24,2,22,2419,25,2.32,2039,1,24
579 | 577,2021-08-08,5,5,0,5,2419,7,1.86,2039,0,5
580 | 578,2021-08-09,96,96,0,96,2419,116,1.82,2039,0,99
581 | 579,2021-08-10,109,109,1,108,2420,134,1.38,2039,0,109
582 | 580,2021-08-11,118,118,0,118,2420,149,1.43,2039,0,118
583 | 581,2021-08-12,111,111,2,109,2422,138,1.55,2041,2,111
584 | 582,2021-08-13,78,78,2,76,2424,156,1.68,2043,2,78
585 | 583,2021-08-14,11,11,0,11,2424,23,3.22,2043,0,11
586 | 584,2021-08-15,4,4,0,4,2424,15,17.53,2042,0,4
587 | 585,2021-08-16,44,44,0,44,2424,61,2.69,2042,0,44
588 | 586,2021-08-17,85,85,2,83,2426,105,1.61,2044,2,87
589 | 587,2021-08-18,74,74,0,74,2426,89,1.8,2044,0,74
590 | 588,2021-08-19,77,77,0,77,2426,84,1.35,2043,0,77
591 | 589,2021-08-20,64,64,0,64,2426,72,1.43,2044,1,64
592 | 590,2021-08-21,14,13,9,5,2435,14,2.86,2045,1,13
593 | 591,2021-08-22,5,5,0,5,2435,5,3.0,2045,1,5
594 | 592,2021-08-23,70,70,0,70,2435,95,1.42,2045,1,70
595 | 593,2021-08-24,69,69,1,68,2436,77,1.39,2046,1,69
596 | 594,2021-08-25,75,75,1,74,2437,87,1.4,2048,2,75
597 | 595,2021-08-26,60,60,0,60,2437,72,1.5,2048,0,60
598 | 596,2021-08-27,67,67,0,67,2437,82,1.43,2048,0,67
599 | 597,2021-08-28,16,16,1,15,2438,18,1.83,2049,1,16
600 | 598,2021-08-29,5,5,0,5,2438,7,1.29,2049,0,5
601 | 599,2021-08-30,92,92,2,90,2440,98,1.34,2050,2,92
602 | 600,2021-08-31,91,91,0,91,2440,103,1.47,2050,0,91
603 | 601,2021-09-01,146,144,7,139,2447,172,1.48,2058,9,145
604 | 602,2021-09-02,154,154,8,146,2455,188,1.47,2065,8,154
605 | 603,2021-09-03,138,138,4,134,2459,164,1.44,2069,4,138
606 | 604,2021-09-04,47,47,2,45,2461,62,1.84,2071,2,47
607 | 605,2021-09-05,13,12,0,13,2461,14,3.07,2070,1,13
608 | 606,2021-09-06,167,165,2,165,2463,211,1.44,2071,2,166
609 | 607,2021-09-07,166,166,3,163,2466,188,1.36,2074,3,166
610 | 608,2021-09-08,181,181,4,177,2470,221,1.33,2076,3,181
611 | 609,2021-09-09,183,183,7,176,2477,220,1.49,2085,9,183
612 | 610,2021-09-10,137,137,2,135,2479,173,1.43,2086,1,137
613 | 611,2021-09-11,36,36,0,36,2479,43,1.58,2086,0,36
614 | 612,2021-09-12,13,13,0,13,2479,16,1.5,2086,0,13
615 | 613,2021-09-13,156,156,4,152,2483,198,1.36,2088,3,156
616 | 614,2021-09-14,177,172,14,163,2497,207,1.48,2101,13,172
617 | 615,2021-09-15,174,174,5,169,2502,220,1.58,2107,6,174
618 | 616,2021-09-16,169,169,1,168,2503,187,1.36,2108,2,169
619 | 617,2021-09-17,113,113,3,110,2506,138,1.57,2111,3,113
620 | 618,2021-09-18,28,28,4,24,2510,33,1.85,2115,4,28
621 | 619,2021-09-19,3,3,0,3,2510,3,1.33,2115,0,3
622 | 620,2021-09-20,6,6,0,6,2510,6,1.83,2114,0,6
623 | 621,2021-09-21,8,8,0,8,2510,8,1.13,2113,0,8
624 | 622,2021-09-22,13,13,1,12,2511,15,2.27,2114,1,13
625 | 623,2021-09-23,107,107,3,104,2514,130,1.32,2117,3,107
626 | 624,2021-09-24,121,121,0,121,2514,145,1.61,2116,0,121
627 | 625,2021-09-25,48,48,1,47,2515,59,1.93,2117,1,48
628 | 626,2021-09-26,19,19,0,19,2515,21,1.43,2117,0,19
629 | 627,2021-09-27,199,199,3,196,2518,245,1.49,2120,3,199
630 | 628,2021-09-28,221,221,3,218,2521,266,1.61,2123,3,221
631 | 629,2021-09-29,209,209,0,209,2521,256,1.55,2123,0,209
632 | 630,2021-09-30,387,384,64,323,2585,494,1.88,2181,61,384
633 | 631,2021-10-01,397,386,76,321,2661,501,1.9,2256,76,387
634 | 632,2021-10-02,92,92,8,84,2669,115,1.67,2264,8,92
635 | 633,2021-10-03,33,31,4,29,2673,38,1.92,2267,4,31
636 | 634,2021-10-04,154,154,6,148,2679,216,1.92,2272,5,155
637 | 635,2021-10-05,307,304,21,286,2700,397,1.63,2291,19,305
638 | 636,2021-10-06,307,307,4,303,2704,415,1.52,2295,4,307
639 | 637,2021-10-07,272,272,3,269,2707,349,1.41,2298,3,272
640 | 638,2021-10-08,217,216,6,211,2713,297,1.51,2304,6,216
641 | 639,2021-10-09,74,73,2,72,2715,92,1.52,2306,2,73
642 | 640,2021-10-10,23,23,1,22,2716,23,1.52,2306,1,23
643 | 641,2021-10-11,155,155,4,151,2720,202,1.78,2310,4,155
644 | 642,2021-10-12,329,329,11,318,2731,404,1.54,2322,12,329
645 | 643,2021-10-13,305,305,6,299,2737,401,1.5,2327,5,305
646 | 644,2021-10-14,305,305,7,298,2744,398,1.42,2333,6,305
647 | 645,2021-10-15,268,267,6,262,2750,351,1.43,2338,5,267
648 | 646,2021-10-16,100,100,0,100,2750,129,1.64,2338,0,100
649 | 647,2021-10-17,24,24,2,22,2752,26,1.88,2339,1,24
650 | 648,2021-10-18,316,315,9,307,2761,405,1.78,2345,7,316
651 |
--------------------------------------------------------------------------------