카카오 webhook 응답을 위한 새 이미지 추가
This commit is contained in:
BIN
autouploader/__pycache__/config.cpython-310.pyc
Normal file
BIN
autouploader/__pycache__/config.cpython-310.pyc
Normal file
Binary file not shown.
BIN
autouploader/__pycache__/config.cpython-311.pyc
Normal file
BIN
autouploader/__pycache__/config.cpython-311.pyc
Normal file
Binary file not shown.
BIN
autouploader/__pycache__/weather.cpython-310.pyc
Normal file
BIN
autouploader/__pycache__/weather.cpython-310.pyc
Normal file
Binary file not shown.
@ -1,7 +1,9 @@
|
||||
# weather.py
|
||||
import requests
|
||||
import json
|
||||
import re
|
||||
import sqlite3
|
||||
import os
|
||||
import time
|
||||
from datetime import datetime
|
||||
from config import serviceKey, TODAY
|
||||
|
||||
@ -36,6 +38,7 @@ def get_precipitation_summary(retry=True):
|
||||
try:
|
||||
data = response.json()
|
||||
total_rainfall = 0.0
|
||||
time_precip_list = []
|
||||
|
||||
lines = [
|
||||
'<div class="weatherinfo" style="max-width: 100%; overflow-x: auto; padding: 10px; box-sizing: border-box;">',
|
||||
@ -58,11 +61,17 @@ def get_precipitation_summary(retry=True):
|
||||
time_str = f"{time[:2]}:{time[2:]}"
|
||||
lines.append(f'<tr><td style="border: 1px solid #333; padding: 2px;text-align: center;">{time_str}</td><td style="border: 1px solid #333; padding: 2px;text-align: center;">{mm}mm</td></tr>')
|
||||
total_rainfall += mm
|
||||
time_precip_list.append((time_str, mm))
|
||||
|
||||
lines.append(f'<tr><td colspan="2" style="border: 1px solid #333; padding: 2px;text-align: center; font-weight: bold;">영업시간 중 총 예상 강수량: {total_rainfall:.1f}mm</td></tr>')
|
||||
lines.append('</tbody></table><p style="text-align:right; font-size: 0.8em;">08:00 파주 조리읍 기상청 단기예보 기준</div>')
|
||||
|
||||
return ''.join(lines)
|
||||
html_summary = ''.join(lines)
|
||||
|
||||
# SQLite 저장 함수 호출
|
||||
save_weather_to_sqlite(date=TODAY, time_precip_list=time_precip_list, total_rainfall=total_rainfall)
|
||||
|
||||
return html_summary
|
||||
|
||||
except json.decoder.JSONDecodeError:
|
||||
if retry:
|
||||
@ -73,6 +82,45 @@ def get_precipitation_summary(retry=True):
|
||||
print("응답이 JSON 형식이 아닙니다.")
|
||||
return ''
|
||||
|
||||
def save_weather_to_sqlite(date, time_precip_list, total_rainfall):
|
||||
db_path = '/data/weather.sqlite'
|
||||
os.makedirs(os.path.dirname(db_path), exist_ok=True)
|
||||
|
||||
conn = sqlite3.connect(db_path)
|
||||
curs = conn.cursor()
|
||||
|
||||
# 테이블 생성 (없으면)
|
||||
curs.execute('''
|
||||
CREATE TABLE IF NOT EXISTS precipitation (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
date TEXT NOT NULL,
|
||||
time TEXT NOT NULL,
|
||||
rainfall REAL NOT NULL
|
||||
)
|
||||
''')
|
||||
|
||||
curs.execute('''
|
||||
CREATE TABLE IF NOT EXISTS precipitation_summary (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
date TEXT NOT NULL UNIQUE,
|
||||
total_rainfall REAL NOT NULL
|
||||
)
|
||||
''')
|
||||
|
||||
# 기존 데이터 삭제 (동일 날짜)
|
||||
curs.execute('DELETE FROM precipitation WHERE date = ?', (date,))
|
||||
curs.execute('DELETE FROM precipitation_summary WHERE date = ?', (date,))
|
||||
|
||||
# 데이터 삽입
|
||||
curs.executemany('INSERT INTO precipitation (date, time, rainfall) VALUES (?, ?, ?)',
|
||||
[(date, t, r) for t, r in time_precip_list])
|
||||
|
||||
curs.execute('INSERT INTO precipitation_summary (date, total_rainfall) VALUES (?, ?)', (date, total_rainfall))
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
print(f"[DB 저장 완료] {date} 강수량 데이터 저장됨")
|
||||
|
||||
# 테스트용
|
||||
if __name__ == "__main__":
|
||||
print(get_precipitation_summary())
|
||||
24
build.yml
24
build.yml
@ -1,10 +1,26 @@
|
||||
services:
|
||||
fg-auto:
|
||||
gnu-autouploader:
|
||||
build:
|
||||
context: ./build
|
||||
context: ./build/autouploader
|
||||
dockerfile: Dockerfile
|
||||
image: reg.firstgarden.co.kr/fg-auto:latest
|
||||
container_name: fg-auto
|
||||
image: reg.firstgarden.co.kr/gnu-autouploader:latest
|
||||
container_name: gnu-autouploader
|
||||
volumes:
|
||||
- ./data:/data
|
||||
- ./autouploader:/app
|
||||
restart: unless-stopped
|
||||
|
||||
fg-webhook:
|
||||
build:
|
||||
context: ./build/webhook
|
||||
dockerfile: Dockerfile
|
||||
image: reg.firstgarden.co.kr/fg-webhook:latest
|
||||
container_name: fg-webhook
|
||||
volumes:
|
||||
- ./data:/data
|
||||
- ./webhook:/app
|
||||
ports:
|
||||
- 5000:5000
|
||||
#environment:
|
||||
# - DOMAIN=https://webhook.firstgarden.co.kr
|
||||
restart: unless-stopped
|
||||
|
||||
@ -1,54 +0,0 @@
|
||||
FROM python:3.10-slim
|
||||
|
||||
ENV LANG=ko_KR.UTF-8 \
|
||||
LANGUAGE=ko_KR:ko \
|
||||
LC_ALL=ko_KR.UTF-8 \
|
||||
TZ=Asia/Seoul \
|
||||
DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# 필수 패키지 설치
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
locales tzdata bash cron curl unzip wget gnupg ca-certificates \
|
||||
xvfb x11-utils libglib2.0-0 libnss3 libgconf-2-4 libfontconfig1 \
|
||||
libxss1 libxshmfence1 libasound2 libxtst6 libappindicator3-1 \
|
||||
fonts-nanum libu2f-udev \
|
||||
libjpeg-dev zlib1g-dev && \
|
||||
sed -i '/ko_KR.UTF-8/s/^# //g' /etc/locale.gen && \
|
||||
locale-gen && \
|
||||
ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime && \
|
||||
ln -sf /usr/bin/python3 /usr/bin/python && \
|
||||
apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
# Chrome 설치
|
||||
RUN curl -fsSL https://dl.google.com/linux/linux_signing_key.pub | gpg --dearmor -o /usr/share/keyrings/google-linux-keyring.gpg && \
|
||||
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/google-linux-keyring.gpg] http://dl.google.com/linux/chrome/deb/ stable main" \
|
||||
> /etc/apt/sources.list.d/google-chrome.list && \
|
||||
apt-get update && \
|
||||
apt-get install -y google-chrome-stable && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Python 패키지 설치
|
||||
RUN pip install --no-cache-dir \
|
||||
selenium>=4.10 \
|
||||
pymysql \
|
||||
ftputil \
|
||||
pillow \
|
||||
pyvirtualdisplay \
|
||||
requests
|
||||
|
||||
# 작업 디렉토리 설정
|
||||
WORKDIR /data
|
||||
|
||||
# 글꼴 캐시
|
||||
RUN fc-cache -f -v
|
||||
|
||||
# 실행 스크립트 복사 및 실행 권한 부여
|
||||
COPY run.sh /data/run.sh
|
||||
RUN chmod +x /data/run.sh
|
||||
|
||||
# crontab 직접 등록
|
||||
RUN echo "* * * * * /data/run.sh >> /proc/1/fd/1 2>&1" | crontab -
|
||||
|
||||
# 크론 실행
|
||||
CMD ["bash", "-c", "cron -f"]
|
||||
@ -29,14 +29,14 @@ RUN pip install --no-cache-dir \
|
||||
requests
|
||||
|
||||
|
||||
WORKDIR /data
|
||||
WORKDIR /app
|
||||
|
||||
RUN fc-cache -f -v
|
||||
|
||||
COPY run.sh /data/run.sh
|
||||
RUN chmod +x /data/run.sh
|
||||
COPY run.sh /app/run.sh
|
||||
RUN chmod +x /app/run.sh
|
||||
|
||||
# crontab 등록
|
||||
RUN echo "0 9 * * * /data/run.sh >> /proc/1/fd/1 2>&1" | crontab -
|
||||
RUN echo "0 9 * * * /app/run.sh >> /proc/1/fd/1 2>&1" | crontab -
|
||||
|
||||
CMD ["/bin/bash", "-c", "cron -f"]
|
||||
30
build/webhook/Dockerfile
Normal file
30
build/webhook/Dockerfile
Normal file
@ -0,0 +1,30 @@
|
||||
# Dockerfile for webhook server (Ubuntu 22.04 + Python Flask)
|
||||
|
||||
FROM ubuntu:22.04
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive \
|
||||
LANG=ko_KR.UTF-8 \
|
||||
LANGUAGE=ko_KR:ko \
|
||||
LC_ALL=ko_KR.UTF-8
|
||||
|
||||
# 기본 패키지 설치 및 로케일 설정
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
locales tzdata python3 python3-pip curl ca-certificates && \
|
||||
locale-gen ko_KR.UTF-8 && \
|
||||
ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime && \
|
||||
dpkg-reconfigure --frontend noninteractive tzdata && \
|
||||
ln -sf /usr/bin/python3 /usr/bin/python && \
|
||||
apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Flask 설치
|
||||
RUN pip3 install --no-cache-dir flask requests
|
||||
|
||||
# 작업 디렉토리
|
||||
WORKDIR /app
|
||||
|
||||
# 외부 접속 허용 포트
|
||||
EXPOSE 5000
|
||||
|
||||
# Flask 앱 실행
|
||||
CMD ["python3", "webhook.py"]
|
||||
BIN
data/weather.sqlite
Normal file
BIN
data/weather.sqlite
Normal file
Binary file not shown.
BIN
data/weather_capture_20250630.png
Normal file
BIN
data/weather_capture_20250630.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 128 KiB |
@ -1,7 +1,16 @@
|
||||
services:
|
||||
fg-auto:
|
||||
image: reg.firstgarden.co.kr/fg-auto:latest
|
||||
container_name: fg-auto
|
||||
gnu-autouploader:
|
||||
image: reg.firstgarden.co.kr/gnu-autouploader:latest
|
||||
container_name: gnu-autouploader
|
||||
volumes:
|
||||
- ./data:/data
|
||||
- ./autouploader:/app
|
||||
restart: unless-stopped
|
||||
|
||||
fg-webhook:
|
||||
image: reg.firstgarden.co.kr/fg-webhook:latest
|
||||
container_name: fg-webhook
|
||||
volumes:
|
||||
- ./data:/data
|
||||
- ./webhook:/app
|
||||
restart: unless-stopped
|
||||
|
||||
@ -2,9 +2,9 @@ services:
|
||||
fg-auto:
|
||||
build:
|
||||
context: ./build
|
||||
dockerfile: Dockerfile-slim
|
||||
image: reg.firstgarden.co.kr/fg-auto:slim
|
||||
container_name: fg-auto
|
||||
dockerfile: Dockerfile
|
||||
image: reg.firstgarden.co.kr/fg-webhook:latest
|
||||
container_name: fg-webhook
|
||||
volumes:
|
||||
- ./data:/data
|
||||
restart: unless-stopped
|
||||
75
webhook/webhook.py
Normal file
75
webhook/webhook.py
Normal file
@ -0,0 +1,75 @@
|
||||
import os
|
||||
from flask import Flask, request, jsonify
|
||||
import sqlite3
|
||||
from datetime import datetime
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
DB_PATH = '/data/weather.sqlite'
|
||||
|
||||
# 환경변수에서 DOMAIN 읽기, 없으면 기본값 지정 (로컬 테스트용)
|
||||
DOMAIN = os.getenv('DOMAIN', 'http://localhost:5000')
|
||||
|
||||
def get_rain_data(date):
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
curs = conn.cursor()
|
||||
|
||||
curs.execute('SELECT time, rainfall FROM precipitation WHERE date = ? ORDER BY time', (date,))
|
||||
time_rain_list = curs.fetchall()
|
||||
|
||||
curs.execute('SELECT total_rainfall FROM precipitation_summary WHERE date = ?', (date,))
|
||||
row = curs.fetchone()
|
||||
total_rainfall = row[0] if row else 0.0
|
||||
|
||||
conn.close()
|
||||
return time_rain_list, total_rainfall
|
||||
|
||||
@app.route('/webhook', methods=['POST'])
|
||||
def webhook():
|
||||
today = datetime.today().strftime('%Y%m%d')
|
||||
response_text = ""
|
||||
|
||||
try:
|
||||
time_rain_list, total_rainfall = get_rain_data(today)
|
||||
|
||||
if not time_rain_list:
|
||||
response_text = f"{today} 날짜의 강수량 데이터가 없습니다."
|
||||
else:
|
||||
lines = []
|
||||
for time_str, rain in time_rain_list:
|
||||
rain_display = f"{rain}mm" if rain > 0 else "강수 없음"
|
||||
lines.append(f"{time_str} → {rain_display}")
|
||||
|
||||
lines.append(f"\n영업시간 내 총 강수량은 {total_rainfall:.1f}mm 입니다.")
|
||||
response_text = '\n'.join(lines)
|
||||
|
||||
except Exception as e:
|
||||
response_text = f"데이터 조회 중 오류가 발생했습니다: {e}"
|
||||
|
||||
image_filename = f"weather_capture_{today}.png"
|
||||
image_path = f"/data/{image_filename}"
|
||||
|
||||
outputs = [{
|
||||
"simpleText": {
|
||||
"text": response_text
|
||||
}
|
||||
}]
|
||||
|
||||
if os.path.isfile(image_path):
|
||||
image_url = f"{DOMAIN}/data/{image_filename}"
|
||||
outputs.append({
|
||||
"image": {
|
||||
"imageUrl": image_url,
|
||||
"altText": "오늘의 날씨 캡처 이미지"
|
||||
}
|
||||
})
|
||||
|
||||
return jsonify({
|
||||
"version": "2.0",
|
||||
"template": {
|
||||
"outputs": outputs
|
||||
}
|
||||
})
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host='0.0.0.0', port=5000)
|
||||
Reference in New Issue
Block a user