izuemon commited on
Commit
4281abb
·
verified ·
1 Parent(s): fedb44a

Update news.py

Browse files
Files changed (1) hide show
  1. news.py +100 -77
news.py CHANGED
@@ -2,76 +2,66 @@ import os
2
  import time
3
  import json
4
  import requests
 
 
 
 
5
 
6
  # ===== Channel.io 設定 =====
7
  CHANNEL_ID = "200605"
8
- GROUP_ID = "534868"
9
 
10
- GET_URL = f"https://desk-api.channel.io/desk/channels/{CHANNEL_ID}/groups/{GROUP_ID}/messages"
11
- POST_URL = GET_URL
12
 
13
  X_ACCOUNT = os.getenv("channeliotokenbot2")
14
  if not X_ACCOUNT:
15
  raise RuntimeError("環境変数 channeliotokenbot2 が設定されていません")
16
 
17
- HEADERS = {
18
  "accept": "application/json",
19
  "accept-language": "ja",
20
  "content-type": "application/json",
21
  "x-account": X_ACCOUNT,
22
  }
23
 
24
- PARAMS = {
25
- "sortOrder": "asc",
26
- "limit": 50,
27
- }
 
 
28
 
29
- ASSISTANT_PERSON_ID = "595702"
30
 
31
- # ===== ChatGPT互換API =====
32
- CHAT_API_URL = "https://izuemon-gpt-free-api.hf.space/v1/chat/completions"
33
 
34
  # ===== Utils =====
35
- def fetch_channel_messages():
36
- res = requests.get(GET_URL, headers=HEADERS, params=PARAMS, timeout=30)
37
- res.raise_for_status()
38
- return res.json().get("messages", [])
 
39
 
40
- def build_chat_messages(messages):
41
- chat_messages = []
42
 
43
- for msg in messages:
44
- text = msg.get("plainText")
45
- person_id = msg.get("personId")
46
 
47
- if not text:
48
- continue
49
 
50
- role = "assistant" if person_id == ASSISTANT_PERSON_ID else "user"
 
 
 
 
51
 
52
- chat_messages.append({
53
- "role": role,
54
- "content": text
55
- })
56
 
57
- return chat_messages
 
 
58
 
59
- def call_chat_api(chat_messages):
60
- payload = {
61
- "model": "gpt-3.5-turbo",
62
- "messages": chat_messages,
63
- }
64
 
65
- res = requests.post(
66
- CHAT_API_URL,
67
- headers={"Content-Type": "application/json"},
68
- data=json.dumps(payload),
69
- timeout=60
70
- )
71
- res.raise_for_status()
72
 
73
- data = res.json()
74
- return data["choices"][0]["message"]["content"]
75
 
76
  def send_to_channel(text):
77
  payload = {
@@ -83,56 +73,89 @@ def send_to_channel(text):
83
 
84
  res = requests.post(
85
  POST_URL,
86
- headers=HEADERS,
87
  data=json.dumps(payload),
88
  timeout=30
89
  )
90
  res.raise_for_status()
91
 
92
- # ===== Main =====
93
- def main():
94
- processed_message_ids = set()
95
 
96
- while True:
97
- try:
98
- messages = fetch_channel_messages()
99
- if not messages:
100
- time.sleep(10)
101
- continue
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
 
103
- latest_msg = messages[-1]
104
- latest_id = latest_msg.get("id")
105
- latest_person_id = latest_msg.get("personId")
106
 
107
- # 既に処理済みならスキップ
108
- if latest_id in processed_message_ids:
109
- time.sleep(10)
110
- continue
 
 
 
 
 
 
 
 
 
 
 
 
 
111
 
112
- # ★ 最新メッセージがアシス��ントなら待機
113
- if latest_person_id == ASSISTANT_PERSON_ID:
114
- time.sleep(10)
115
- continue
116
 
117
- # GPTに送る会話履歴を構築
118
- chat_messages = build_chat_messages(messages)
119
- if not chat_messages:
120
- processed_message_ids.add(latest_id)
121
- continue
122
 
123
- # GPT呼び出し
124
- reply = call_chat_api(chat_messages)
125
 
126
- # Channel.ioへ送信
127
- send_to_channel(reply)
 
 
 
 
 
128
 
129
- processed_message_ids.add(latest_id)
130
- print("GPT応答を送信しました")
 
 
 
 
 
131
 
132
- except Exception as e:
133
- print("エラー:", e)
134
 
135
- time.sleep(15)
136
 
137
  if __name__ == "__main__":
138
  main()
 
2
  import time
3
  import json
4
  import requests
5
+ import hashlib
6
+ from datetime import datetime
7
+ from bs4 import BeautifulSoup
8
+ import xml.etree.ElementTree as ET
9
 
10
  # ===== Channel.io 設定 =====
11
  CHANNEL_ID = "200605"
12
+ GROUP_ID = "534457"
13
 
14
+ POST_URL = f"https://desk-api.channel.io/desk/channels/{CHANNEL_ID}/groups/{GROUP_ID}/messages"
 
15
 
16
  X_ACCOUNT = os.getenv("channeliotokenbot2")
17
  if not X_ACCOUNT:
18
  raise RuntimeError("環境変数 channeliotokenbot2 が設定されていません")
19
 
20
+ HEADERS_POST = {
21
  "accept": "application/json",
22
  "accept-language": "ja",
23
  "content-type": "application/json",
24
  "x-account": X_ACCOUNT,
25
  }
26
 
27
+ # ===== RSS =====
28
+ RSS_URL = "https://www.nippon.com/ja/rss-all/"
29
+
30
+ # ===== 設定 =====
31
+ SENT_LOG_FILE = "sent_nippon_news.json"
32
+ LAST_RUN_FILE = "last_run.json"
33
 
34
+ TARGET_TIMES = {"06:30", "18:30"} # 朝・夕方
35
 
 
 
36
 
37
  # ===== Utils =====
38
+ def load_sent_log():
39
+ if not os.path.exists(SENT_LOG_FILE):
40
+ return set()
41
+ with open(SENT_LOG_FILE, "r", encoding="utf-8") as f:
42
+ return set(json.load(f))
43
 
 
 
44
 
45
+ def save_sent_log(sent_set):
46
+ with open(SENT_LOG_FILE, "w", encoding="utf-8") as f:
47
+ json.dump(list(sent_set), f, ensure_ascii=False, indent=2)
48
 
 
 
49
 
50
+ def load_last_run():
51
+ if not os.path.exists(LAST_RUN_FILE):
52
+ return ""
53
+ with open(LAST_RUN_FILE, "r", encoding="utf-8") as f:
54
+ return json.load(f).get("last_run", "")
55
 
 
 
 
 
56
 
57
+ def save_last_run(value):
58
+ with open(LAST_RUN_FILE, "w", encoding="utf-8") as f:
59
+ json.dump({"last_run": value}, f)
60
 
 
 
 
 
 
61
 
62
+ def hash_link(link: str) -> str:
63
+ return hashlib.sha256(link.encode("utf-8")).hexdigest()
 
 
 
 
 
64
 
 
 
65
 
66
  def send_to_channel(text):
67
  payload = {
 
73
 
74
  res = requests.post(
75
  POST_URL,
76
+ headers=HEADERS_POST,
77
  data=json.dumps(payload),
78
  timeout=30
79
  )
80
  res.raise_for_status()
81
 
 
 
 
82
 
83
+ def fetch_rss_items():
84
+ res = requests.get(RSS_URL, timeout=30)
85
+ res.raise_for_status()
86
+
87
+ root = ET.fromstring(res.content)
88
+ channel = root.find("channel")
89
+ if channel is None:
90
+ return []
91
+
92
+ items = []
93
+ for item in channel.findall("item"):
94
+ title = item.findtext("title", "").strip()
95
+ link = item.findtext("link", "").strip()
96
+ description_raw = item.findtext("description", "").strip()
97
+
98
+ soup = BeautifulSoup(description_raw, "lxml")
99
+ description = soup.get_text(strip=True)
100
+
101
+ if title and link:
102
+ items.append({
103
+ "title": title,
104
+ "link": link,
105
+ "description": description,
106
+ })
107
+
108
+ return items
109
 
 
 
 
110
 
111
+ # ===== Main =====
112
+ def run_job():
113
+ sent_log = load_sent_log()
114
+ items = fetch_rss_items()
115
+ new_count = 0
116
+
117
+ for item in items:
118
+ link_hash = hash_link(item["link"])
119
+ if link_hash in sent_log:
120
+ continue
121
+
122
+ message = (
123
+ f"<link type=\"url\" value=\"{item['link']}\">"
124
+ f"{item['title']}"
125
+ f"</link>\n\n"
126
+ f"{item['description']}"
127
+ )
128
 
129
+ send_to_channel(message)
130
+ sent_log.add(link_hash)
131
+ new_count += 1
132
+ time.sleep(1)
133
 
134
+ if new_count > 0:
135
+ save_sent_log(sent_log)
136
+ print(f"{new_count} 件のニュースを送信しました")
137
+ else:
138
+ print("新しいニュースはありません")
139
 
 
 
140
 
141
+ def main():
142
+ last_run = load_last_run()
143
+
144
+ while True:
145
+ now = datetime.now()
146
+ now_key = now.strftime("%Y-%m-%d %H:%M")
147
+ now_time = now.strftime("%H:%M")
148
 
149
+ if now_time in TARGET_TIMES and last_run != now_key:
150
+ print(f"{now_time} 実行開始")
151
+ try:
152
+ run_job()
153
+ save_last_run(now_key)
154
+ except Exception as e:
155
+ print("エラー:", e)
156
 
157
+ time.sleep(60) # 1分ごとにチェック
 
158
 
 
159
 
160
  if __name__ == "__main__":
161
  main()