izuemon commited on
Commit
b8ab9ee
·
verified ·
1 Parent(s): 6ebd2d1

Update v2_gpt.py

Browse files
Files changed (1) hide show
  1. v2_gpt.py +131 -48
v2_gpt.py CHANGED
@@ -1,10 +1,4 @@
1
- # main.py
2
- """
3
- CW_EMAIL / CW_PASSWORD で ChannelWorks にログインし、
4
- chatId=583391 のメッセージを ChatGPT プロキシに投げ、
5
- 返答を /desk/channels/240996/groups/583391/messages へ送信する。
6
- """
7
-
8
  import json
9
  import os
10
  import random
@@ -12,12 +6,12 @@ import string
12
  import threading
13
  import time
14
  import traceback
 
15
 
16
  import requests
17
 
18
  from channel_auth import ChannelWorksClient
19
- from channel_msg import ChannelMessenger
20
-
21
 
22
  # ---------------------------------------------------------------------------
23
  # 設定
@@ -25,8 +19,8 @@ from channel_msg import ChannelMessenger
25
  CW_EMAIL = os.environ["CW_EMAIL"]
26
  CW_PASSWORD = os.environ["CW_PASSWORD"]
27
 
28
- ROOM_ID = "240996" # desk の channel id(URL の /channels/240996 の部分)
29
- TARGET_CHAT_ID = "583391" # 監視したい chatId
30
  GROUP_PATH = f"/groups/{TARGET_CHAT_ID}"
31
 
32
  GPT_API_URL = "https://izuemon-gpt-free-api.hf.space/v1/chat/completions"
@@ -39,18 +33,32 @@ CHANNEL_SEND_URL = (
39
  f"/groups/{TARGET_CHAT_ID}/messages"
40
  )
41
 
 
 
 
42
 
43
  # ---------------------------------------------------------------------------
44
- # ユーティリティ
45
  # ---------------------------------------------------------------------------
 
 
 
 
 
 
 
 
 
 
 
 
46
  def _make_request_id() -> str:
47
- """desk-web-1791678445898qhbd のような形式の requestId を生成する。"""
48
  suffix = "".join(random.choices(string.ascii_lowercase + string.digits, k=4))
49
  return f"desk-web-{int(time.time() * 1000)}{suffix}"
50
 
51
 
52
  # ---------------------------------------------------------------------------
53
- # ChatGPT プロキシ呼び出し
54
  # ---------------------------------------------------------------------------
55
  def ask_gpt(text: str) -> str:
56
  payload = {
@@ -61,23 +69,38 @@ def ask_gpt(text: str) -> str:
61
  ],
62
  "stream": False,
63
  }
64
- resp = requests.post(GPT_API_URL, json=payload, timeout=GPT_TIMEOUT)
 
 
 
 
 
 
 
 
 
 
 
 
65
  resp.raise_for_status()
66
  data = resp.json()
67
- # OpenAI 互換レスポンス
68
- return data["choices"][0]["message"]["content"]
 
 
 
69
 
70
 
71
  # ---------------------------------------------------------------------------
72
- # Channel へのメッセージ送信
73
  # ---------------------------------------------------------------------------
74
  def send_channel_message(client: ChannelWorksClient, text: str) -> requests.Response:
75
- # 「最新の」トークンを毎回取得
76
  tokens = client.get_tokens() or {}
77
  x_account = tokens.get("x-account") or ""
78
  x_account_refresh = tokens.get("x-account-refresh") or ""
79
 
80
- # 指定どおり Cookie に x-account / x-account-refresh / x-account-refresh-bound を含める
 
81
  cookie_parts = []
82
  if x_account:
83
  cookie_parts.append(f"x-account={x_account}")
@@ -111,12 +134,19 @@ def send_channel_message(client: ChannelWorksClient, text: str) -> requests.Resp
111
  "customPayload": None,
112
  }
113
 
 
 
 
 
114
  resp = requests.post(
115
  CHANNEL_SEND_URL,
116
  headers=headers,
117
  data=json.dumps(body, ensure_ascii=False).encode("utf-8"),
118
  timeout=30,
119
  )
 
 
 
120
  return resp
121
 
122
 
@@ -124,93 +154,146 @@ def send_channel_message(client: ChannelWorksClient, text: str) -> requests.Resp
124
  # メイン
125
  # ---------------------------------------------------------------------------
126
  def main() -> None:
 
 
 
 
127
  client = ChannelWorksClient(
128
  room_id=ROOM_ID,
129
  email=CW_EMAIL,
130
  password=CW_PASSWORD,
131
- log_level=ChannelWorksClient.LOG_ERROR,
132
  )
 
133
  client.login()
 
 
 
 
 
 
 
 
134
  client.start_auto_touch()
 
135
 
136
- # 自分の account id(自分が送ったメッセージを無視するため)
137
  my_account_id = str(getattr(client, "_account_id", "") or "")
 
138
 
139
- # 同一メッセージの多重処理防止
140
  seen_ids: set[str] = set()
141
  seen_lock = threading.Lock()
142
 
143
  def handle_message(text: str) -> None:
144
- """ChatGPT に投げて、返答を Channel に送信する。"""
145
  try:
146
  answer = ask_gpt(text)
147
  except Exception as exc:
148
- print(f"[GPT ERROR] {exc!r}")
149
  traceback.print_exc()
150
  return
 
151
 
152
  try:
153
  resp = send_channel_message(client, answer)
154
  if 200 <= resp.status_code < 300:
155
- print(f"[SEND OK] status={resp.status_code}")
156
  else:
157
- print(f"[SEND NG] status={resp.status_code} body={resp.text[:300]}")
158
  except Exception as exc:
159
- print(f"[SEND ERROR] {exc!r}")
160
  traceback.print_exc()
161
 
162
  def on_push(wrapper: dict) -> None:
163
- # create イベントのみ対象
 
 
 
 
 
 
164
  if wrapper.get("event") != "create":
 
165
  return
 
166
  entity = wrapper.get("entity") or {}
 
 
 
 
 
 
 
 
 
 
 
167
 
168
- # chatId フィルタ
169
- if str(entity.get("chatId") or "") != TARGET_CHAT_ID:
170
  return
171
 
172
- # 自分の送信メッセージは無視
173
- person_id = str(entity.get("personId") or "")
174
  if person_id and my_account_id and person_id == my_account_id:
 
175
  return
176
 
177
- # メッセージ ID で多重処理防止
178
- msg_id = entity.get("id") or ""
179
  if msg_id:
180
  with seen_lock:
181
  if msg_id in seen_ids:
 
182
  return
183
  seen_ids.add(msg_id)
184
  if len(seen_ids) > 2000:
185
  seen_ids.clear()
186
 
187
- text = entity.get("plainText") or ""
188
- if not text.strip():
189
  return
190
 
191
- print(f"[RECV] chatId={entity.get('chatId')} personId={person_id}: {text!r}")
192
- # WS ループをブロックしないよう別スレッドで処理
193
- threading.Thread(
194
- target=handle_message, args=(text,), daemon=True
195
- ).start()
196
 
 
 
197
  messenger = ChannelMessenger(
198
  client=client,
199
- channel_id=ROOM_ID, # /channels/240996
200
- # manager_id は room 情報から自動解決させる(指定してもよい)
201
- group_path=GROUP_PATH, # /groups/583391
202
- log_level=ChannelMessenger.LOG_ERROR,
203
  on_push=on_push,
204
  )
205
 
206
- messenger.start()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
  try:
 
208
  messenger.wait()
209
  except KeyboardInterrupt:
210
- print("KeyboardInterrupt: 終了します。")
211
  finally:
 
212
  messenger.stop()
213
  client.stop_auto_touch()
 
214
 
215
 
216
  if __name__ == "__main__":
 
1
+ # main_debug.py
 
 
 
 
 
 
2
  import json
3
  import os
4
  import random
 
6
  import threading
7
  import time
8
  import traceback
9
+ from datetime import datetime
10
 
11
  import requests
12
 
13
  from channel_auth import ChannelWorksClient
14
+ from channel_msg import ChannelMessenger # ★ ライブラリ名修正
 
15
 
16
  # ---------------------------------------------------------------------------
17
  # 設定
 
19
  CW_EMAIL = os.environ["CW_EMAIL"]
20
  CW_PASSWORD = os.environ["CW_PASSWORD"]
21
 
22
+ ROOM_ID = "240996"
23
+ TARGET_CHAT_ID = "583391"
24
  GROUP_PATH = f"/groups/{TARGET_CHAT_ID}"
25
 
26
  GPT_API_URL = "https://izuemon-gpt-free-api.hf.space/v1/chat/completions"
 
33
  f"/groups/{TARGET_CHAT_ID}/messages"
34
  )
35
 
36
+ # ★ デバッグログを全開にする
37
+ LOG_LEVEL = ChannelWorksClient.LOG_DEBUG # 2
38
+
39
 
40
  # ---------------------------------------------------------------------------
41
+ # ロガー
42
  # ---------------------------------------------------------------------------
43
+ def log(tag: str, msg: str) -> None:
44
+ ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
45
+ print(f"[{ts}] [{tag}] {msg}", flush=True)
46
+
47
+
48
+ def log_block(tag: str, title: str, body: str) -> None:
49
+ ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
50
+ print(f"\n[{ts}] [{tag}] ===== {title} =====", flush=True)
51
+ print(body, flush=True)
52
+ print(f"[{ts}] [{tag}] ===== /{title} =====\n", flush=True)
53
+
54
+
55
  def _make_request_id() -> str:
 
56
  suffix = "".join(random.choices(string.ascii_lowercase + string.digits, k=4))
57
  return f"desk-web-{int(time.time() * 1000)}{suffix}"
58
 
59
 
60
  # ---------------------------------------------------------------------------
61
+ # ChatGPT プロキシ
62
  # ---------------------------------------------------------------------------
63
  def ask_gpt(text: str) -> str:
64
  payload = {
 
69
  ],
70
  "stream": False,
71
  }
72
+ log("GPT-REQ", f"POST {GPT_API_URL} model={GPT_MODEL}")
73
+ log_block("GPT-REQ-BODY", "request", json.dumps(payload, ensure_ascii=False, indent=2))
74
+
75
+ t0 = time.monotonic()
76
+ try:
77
+ resp = requests.post(GPT_API_URL, json=payload, timeout=GPT_TIMEOUT)
78
+ except Exception as exc:
79
+ log("GPT-ERR", f"通信例外: {exc!r}")
80
+ raise
81
+ dt = time.monotonic() - t0
82
+ log("GPT-RES", f"status={resp.status_code} elapsed={dt:.2f}s")
83
+ log_block("GPT-RES-BODY", "response", resp.text[:4000])
84
+
85
  resp.raise_for_status()
86
  data = resp.json()
87
+ try:
88
+ return data["choices"][0]["message"]["content"]
89
+ except (KeyError, IndexError, TypeError) as exc:
90
+ log("GPT-ERR", f"レスポンス形式が想定外: {exc!r} / keys={list(data.keys())}")
91
+ raise
92
 
93
 
94
  # ---------------------------------------------------------------------------
95
+ # Channel 送信
96
  # ---------------------------------------------------------------------------
97
  def send_channel_message(client: ChannelWorksClient, text: str) -> requests.Response:
 
98
  tokens = client.get_tokens() or {}
99
  x_account = tokens.get("x-account") or ""
100
  x_account_refresh = tokens.get("x-account-refresh") or ""
101
 
102
+ log("SEND-TOK", f"x-account={x_account[:24]}... refresh={x_account_refresh[:24]}...")
103
+
104
  cookie_parts = []
105
  if x_account:
106
  cookie_parts.append(f"x-account={x_account}")
 
134
  "customPayload": None,
135
  }
136
 
137
+ log("SEND-REQ", f"POST {CHANNEL_SEND_URL}")
138
+ log_block("SEND-REQ-BODY", "request", json.dumps(body, ensure_ascii=False, indent=2))
139
+
140
+ t0 = time.monotonic()
141
  resp = requests.post(
142
  CHANNEL_SEND_URL,
143
  headers=headers,
144
  data=json.dumps(body, ensure_ascii=False).encode("utf-8"),
145
  timeout=30,
146
  )
147
+ dt = time.monotonic() - t0
148
+ log("SEND-RES", f"status={resp.status_code} elapsed={dt:.2f}s")
149
+ log_block("SEND-RES-BODY", "response", resp.text[:2000])
150
  return resp
151
 
152
 
 
154
  # メイン
155
  # ---------------------------------------------------------------------------
156
  def main() -> None:
157
+ log("BOOT", f"CW_EMAIL={CW_EMAIL[:3]}*** / room_id={ROOM_ID} / target_chat_id={TARGET_CHAT_ID}")
158
+
159
+ # --- 1) ログイン ---
160
+ log("AUTH", "ChannelWorksClient 初期化")
161
  client = ChannelWorksClient(
162
  room_id=ROOM_ID,
163
  email=CW_EMAIL,
164
  password=CW_PASSWORD,
165
+ log_level=LOG_LEVEL, # ★ DEBUG
166
  )
167
+ log("AUTH", "sign_in + boot 実行")
168
  client.login()
169
+ log("AUTH", "login() 完了")
170
+ tokens = client.get_tokens() or {}
171
+ log("AUTH", f"tokens: {[k for k, v in tokens.items() if v]}")
172
+
173
+ # ★ manager_id が解決できているか確認(未解決だと start() で落ちる)
174
+ log("AUTH", f"room_id(client)={getattr(client, 'room_id', None)}")
175
+ log("AUTH", f"_account_id={getattr(client, '_account_id', None)}")
176
+
177
  client.start_auto_touch()
178
+ log("AUTH", "auto_touch 開始")
179
 
 
180
  my_account_id = str(getattr(client, "_account_id", "") or "")
181
+ log("AUTH", f"my_account_id={my_account_id}")
182
 
183
+ # --- 2) 受信ハンドラ ---
184
  seen_ids: set[str] = set()
185
  seen_lock = threading.Lock()
186
 
187
  def handle_message(text: str) -> None:
188
+ log("HANDLE", f"start text={text!r}")
189
  try:
190
  answer = ask_gpt(text)
191
  except Exception as exc:
192
+ log("HANDLE-ERR", f"ask_gpt 失敗: {exc!r}")
193
  traceback.print_exc()
194
  return
195
+ log("HANDLE", f"answer={answer[:100]!r}...")
196
 
197
  try:
198
  resp = send_channel_message(client, answer)
199
  if 200 <= resp.status_code < 300:
200
+ log("SEND-OK", f"status={resp.status_code}")
201
  else:
202
+ log("SEND-NG", f"status={resp.status_code} body={resp.text[:300]}")
203
  except Exception as exc:
204
+ log("SEND-ERR", f"{exc!r}")
205
  traceback.print_exc()
206
 
207
  def on_push(wrapper: dict) -> None:
208
+ # ★ まず何が来たか全部出す
209
+ log_block(
210
+ "PUSH-RAW",
211
+ f"event={wrapper.get('event')} type={wrapper.get('type')}",
212
+ json.dumps(wrapper, ensure_ascii=False, indent=2)[:4000],
213
+ )
214
+
215
  if wrapper.get("event") != "create":
216
+ log("PUSH-SKIP", f"event != create ({wrapper.get('event')})")
217
  return
218
+
219
  entity = wrapper.get("entity") or {}
220
+ chat_id = str(entity.get("chatId") or "")
221
+ person_id = str(entity.get("personId") or "")
222
+ msg_id = entity.get("id") or ""
223
+ plain = entity.get("plainText") or ""
224
+
225
+ log(
226
+ "PUSH-CHK",
227
+ f"chatId={chat_id!r} (want {TARGET_CHAT_ID!r}) "
228
+ f"personId={person_id!r} (self {my_account_id!r}) "
229
+ f"msgId={msg_id!r} plainText={plain!r}",
230
+ )
231
 
232
+ if chat_id != TARGET_CHAT_ID:
233
+ log("PUSH-SKIP", f"chatId mismatch: got={chat_id!r} want={TARGET_CHAT_ID!r}")
234
  return
235
 
 
 
236
  if person_id and my_account_id and person_id == my_account_id:
237
+ log("PUSH-SKIP", "自分のメッセージのため無視")
238
  return
239
 
 
 
240
  if msg_id:
241
  with seen_lock:
242
  if msg_id in seen_ids:
243
+ log("PUSH-SKIP", f"既出 msgId={msg_id!r}")
244
  return
245
  seen_ids.add(msg_id)
246
  if len(seen_ids) > 2000:
247
  seen_ids.clear()
248
 
249
+ if not plain.strip():
250
+ log("PUSH-SKIP", "plainText が空")
251
  return
252
 
253
+ log("PUSH-HIT", f"処理対象: {plain!r}")
254
+ threading.Thread(target=handle_message, args=(plain,), daemon=True).start()
 
 
 
255
 
256
+ # --- 3) Messenger 起動 ---
257
+ log("WS", "ChannelMessenger 初期化")
258
  messenger = ChannelMessenger(
259
  client=client,
260
+ channel_id=ROOM_ID,
261
+ group_path=GROUP_PATH,
262
+ log_level=LOG_LEVEL, # ★ DEBUG
 
263
  on_push=on_push,
264
  )
265
 
266
+ log("WS", "start() 呼び出し(WS 接続開始)")
267
+ try:
268
+ messenger.start()
269
+ except Exception as exc:
270
+ log("WS-ERR", f"start() 失敗: {exc!r}")
271
+ traceback.print_exc()
272
+ return
273
+
274
+ log("WS", f"start() 完了 running={messenger.is_running()}")
275
+
276
+ # ★ 30 秒ごとに生存確認(WS が死んでいないか)
277
+ def watchdog() -> None:
278
+ while True:
279
+ time.sleep(30)
280
+ if not messenger.is_running():
281
+ log("WATCH", "ChannelMessenger が停止しています!")
282
+ break
283
+ log("WATCH", "alive")
284
+
285
+ threading.Thread(target=watchdog, daemon=True).start()
286
+
287
  try:
288
+ log("WS", "wait() で受信待機")
289
  messenger.wait()
290
  except KeyboardInterrupt:
291
+ log("WS", "KeyboardInterrupt")
292
  finally:
293
+ log("WS", "停止処理")
294
  messenger.stop()
295
  client.stop_auto_touch()
296
+ log("WS", "終了")
297
 
298
 
299
  if __name__ == "__main__":