izuemon commited on
Commit
f108c05
·
verified ·
1 Parent(s): 6b161aa

Update turbowarp-server/qr-converter.py

Browse files
Files changed (1) hide show
  1. turbowarp-server/qr-converter.py +194 -239
turbowarp-server/qr-converter.py CHANGED
@@ -1,281 +1,236 @@
1
- import time
2
- import random
3
  import requests
4
  from PIL import Image
5
  from io import BytesIO
6
- import scratchcommunication
 
 
7
 
8
- # --- Scratchクラウド接続 ---
9
  PROJECT_ID = "1293416663"
10
- print(f"[INFO] Connecting to Scratch project {PROJECT_ID}...")
 
11
  tw = scratchcommunication.TwCloudConnection(
12
  project_id=PROJECT_ID,
13
  username="server",
14
  contact_info="contact"
15
  )
16
- print("[INFO] Connected successfully.")
17
 
18
- def get_var(name):
19
- try:
20
- value = tw.get_variable(name=name, name_literal=False)
21
-
22
- # デバッグ用に生の値を出力
23
- print(f"[DEBUG] Raw value of '{name}': {value} (type: {type(value).__name__})")
24
-
25
- # Noneの場合は"0"として扱う
26
- if value is None:
27
- print(f"[WARNING] Variable '{name}' is None, treating as '0'")
28
- return "0"
29
-
30
- # 様々な型を文字列に変換
31
- if isinstance(value, (int, float)):
32
- value = str(int(value))
33
- print(f"[GET] Variable '{name}' converted from number to string: '{value}'")
34
- elif not isinstance(value, str):
35
- value = str(value)
36
- print(f"[GET] Variable '{name}' converted from {type(value).__name__} to string: '{value}'")
37
-
38
- # 表示用に切り詰め
39
- display_value = value[:50] + "..." if len(value) > 50 else value
40
- print(f"[GET] Variable '{name}' = '{display_value}'")
41
- return value
42
- except Exception as e:
43
- print(f"[ERROR] Failed to get variable '{name}': {e}")
44
- return "0"
45
 
46
- def set_var(name, value):
47
- try:
48
- tw.set_variable(name=name, value=value, name_literal=False)
49
- print(f"[SET] Variable '{name}' = '{value[:50]}...'" if len(value) > 50 else f"[SET] Variable '{name}' = '{value}'")
50
- return True
51
- except Exception as e:
52
- print(f"[ERROR] Failed to set variable '{name}': {e}")
53
- return None
54
-
55
- # --- n-chars.txt の読み込み ---
56
- print("[INFO] Loading n-chars.txt...")
57
- with open("turbowarp-server/n-chars.txt", "r", encoding="utf-8") as f:
58
- n_chars = [line.strip() for line in f]
59
- print(f"[INFO] Loaded {len(n_chars)} characters.")
60
-
61
- def encode_prompt(prompt):
62
- """プロンプト文字列を数字列にエンコード(半角スペースは96として特別処理)"""
63
- encoded = ""
64
  for char in prompt:
65
- if char == " ":
66
- encoded += "96"
67
  else:
68
- try:
69
- idx = n_chars.index(char)
70
- encoded += f"{idx:02d}"
71
- except ValueError:
72
- print(f"[WARNING] Character '{char}' not found in n_chars, skipping")
73
- continue
74
- print(f"[ENCODE] Prompt encoded to length {len(encoded)}")
75
- return encoded
76
 
77
- def decode_prompt(encoded_str):
78
- """クラウド変の数字列を元にプロンプト文字列復号(96は半角スペスとして処理)"""
79
- chars = []
80
- i = 0
81
- while i < len(encoded_str):
82
- idx = int(encoded_str[i:i+2])
83
- if idx == 96:
84
- chars.append(" ")
85
- elif idx < len(n_chars):
86
- chars.append(n_chars[idx])
87
  else:
88
- print(f"[WARNING] Invalid index {idx} at position {i}")
89
- i += 2
90
- decoded = "".join(chars)
91
- print(f"[DECODE] Encoded prompt -> '{decoded[:50]}...'")
92
- return decoded
93
 
94
- def rgb_to_scratch_number(rgb):
95
- """RGBを6桁の10進数に換 (R:00-99, G:00-99, B:00-99)"""
96
- r, g, b = rgb
97
- # 各色を0-99の範囲に収める(元が0-255の場合)
98
- r_scaled = int(r * 99 / 255)
99
- g_scaled = int(g * 99 / 255)
100
- b_scaled = int(b * 99 / 255)
101
- return f"{r_scaled:02d}{g_scaled:02d}{b_scaled:02d}"
 
 
 
 
 
102
 
103
  def generate_image(prompt):
104
- """APIから352x352の画像生成"""
105
- seed = random.randint(0, 999999)
106
- print(f"[INFO] Generating image with prompt: '{prompt[:50]}...', seed={seed}")
107
  params = {
108
  "prompt": prompt,
109
  "negative_prompt": "nsfw, low quality",
 
 
110
  "width": 352,
111
  "height": 352,
112
- "num_inference_steps": 2,
113
- "guidance_scale": 0,
114
- "seed": seed,
115
- "randomize_seed": "true"
116
  }
117
- resp = requests.get("https://izuemon-pixart-alpha-pixart-sigma-xl-2-1024-ms.hf.space/gen", params=params)
118
- resp.raise_for_status()
119
- img = Image.open(BytesIO(resp.content))
120
- print(f"[INFO] Image generated: size={img.size}, mode={img.mode}")
121
- return img
122
-
123
- def resize_and_encode(img):
124
- """90x90にリサイズして6桁の数字列に変換(各ピクセル6桁)"""
125
- img = img.resize((90, 90))
126
- print("[INFO] Resized image to 90x90.")
127
 
128
- encoded = ""
129
- total_pixels = 0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
 
131
- for y in range(90):
132
- for x in range(90):
133
- pixel = img.getpixel((x, y))
134
- # RGB取得(RGBA場合はRGBのみ使用
135
- if len(pixel) >= 3:
136
- r, g, b = pixel[:3]
137
- else:
138
- r, g, b = pixel, pixel, pixel
139
- encoded += rgb_to_scratch_number((r, g, b))
140
- total_pixels += 1
141
 
142
- expected_length = total_pixels * 6
143
- print(f"[INFO] Encoded {total_pixels} pixels to string of length {len(encoded)} (expected: {expected_length})")
144
- return encoded
145
 
146
- def split_packets(data, max_length=9998):
147
- """10000文字制限合わせて分割(先頭 '10' 含む)"""
 
 
 
148
  packets = []
149
- idx = 0
150
- total_length = len(data)
151
- expected_packets = (total_length + max_length - 1) // max_length
152
 
153
- while idx < len(data):
154
- chunk = data[idx:idx + max_length]
155
- packets.append(chunk)
156
- idx += max_length
157
 
158
- print(f"[INFO] Data length: {total_length}, max packet size: {max_length}")
159
- print(f"[INFO] Expected {expected_packets} packets, actual {len(packets)} packets")
160
- return packets
161
-
162
- # --- メインループ ---
163
- print("[INFO] Starting main loop...")
164
- last_processed_id = ""
165
-
166
- # 初期化
167
- set_var("n0", "0")
168
- set_var("n1", "0")
169
- time.sleep(1)
170
-
171
- while True:
172
- try:
173
- n1 = get_var("n1")
174
- n0 = get_var("n0")
175
 
176
- print(f"[DEBUG] n0='{n0}', n1='{n1[:30]}...' if n1 and len(n1)>30 else n1")
 
177
 
178
- is_n0_free = (n0 == "0")
179
- print(f"[DEBUG] is_n0_free: {is_n0_free}")
 
 
 
 
180
 
181
- if n1 and len(n1) >= 3 and n1[0] == "0":
182
- user_id = n1[1:3]
183
- request_data = n1
184
-
185
- print(f"[INFO] Received request from user {user_id}")
186
- print(f"[INFO] Request data length: {len(request_data)}")
187
-
188
- if request_data == last_processed_id:
189
- print("[INFO] Already processed, marking as read...")
190
- marked_as_read = "01" + request_data[2:]
191
- set_var("n1", marked_as_read)
192
- time.sleep(0.1)
193
- continue
 
 
 
 
 
194
 
195
- if is_n0_free:
196
- print("[INFO] n0 is free, starting processing...")
 
197
 
198
- # 処理中フラグ
199
- set_var("n0", "1")
200
-
201
- # リクエストを既読に
202
- marked_as_read = "01" + request_data[2:]
203
- set_var("n1", marked_as_read)
204
-
205
- # プロンプトをデコード
206
- encoded_prompt = request_data[3:]
207
- print(f"[INFO] Encoded prompt length: {len(encoded_prompt)}")
208
- prompt = decode_prompt(encoded_prompt)
209
- print(f"[INFO] Decoded prompt: '{prompt}'")
210
-
211
- # 画像生成とエンコード
212
- img = generate_image(prompt)
213
- scratch_data = resize_and_encode(img)
214
-
215
- # パケット分割
216
- packets = split_packets(scratch_data)
217
- print(f"[INFO] Will send {len(packets)} packets")
218
-
219
- # パケット送信
220
- for i, pkt in enumerate(packets):
221
- packet_num = i + 1
222
- print(f"[INFO] Sending packet {packet_num}/{len(packets)} (size: {len(pkt)} chars)")
223
-
224
- # パケット送信
225
- set_var("n1", "10" + pkt)
226
 
227
- if i < len(packets) - 1:
228
- # ACK待ち
229
- print(f"[INFO] Waiting for ACK for packet {packet_num}...")
230
- ack_timeout = 0
231
- ack_received = False
232
- while ack_timeout < 50:
233
- current_n1 = get_var("n1")
234
- if current_n1 == "11":
235
- print(f"[INFO] Received ACK for packet {packet_num}")
236
- ack_received = True
237
- break
238
- time.sleep(0.2)
239
- ack_timeout += 1
240
 
241
- if not ack_received:
242
- print(f"[ERROR] ACK timeout for packet {packet_num}")
243
- set_var("n0", "0")
244
- break
245
- else:
246
- # 完了待ち
247
- print("[INFO] Waiting for completion '99'...")
248
- complete_timeout = 0
249
- complete_received = False
250
- while complete_timeout < 50:
251
- current_n1 = get_var("n1")
252
- if current_n1 == "99":
253
- print("[INFO] Received completion signal")
254
- complete_received = True
255
- break
256
- time.sleep(0.2)
257
- complete_timeout += 1
258
 
259
- if not complete_received:
260
- print("[ERROR] Completion timeout")
261
-
262
- # 完了
263
- print("[INFO] Transmission complete. Resetting n0.")
264
- set_var("n0", "0")
265
- last_processed_id = request_data
266
- print(f"[INFO] Set last_processed_id")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
267
 
268
- else:
269
- print("[INFO] n0 is busy, waiting...")
270
- else:
271
- if n1:
272
- print(f"[DEBUG] n1 condition not met: first char='{n1[0] if n1 else 'None'}', length={len(n1) if n1 else 0}")
273
- else:
274
- print("[DEBUG] n1 is None or empty")
275
 
276
- except Exception as e:
277
- print(f"[ERROR] Exception in main loop: {e}")
278
- import traceback
279
- traceback.print_exc()
280
-
281
- time.sleep(0.3)
 
 
 
 
 
 
 
1
+ import scratchcommunication
 
2
  import requests
3
  from PIL import Image
4
  from io import BytesIO
5
+ import time
6
+ import random
7
+ import math
8
 
 
9
  PROJECT_ID = "1293416663"
10
+
11
+ # 接続設定
12
  tw = scratchcommunication.TwCloudConnection(
13
  project_id=PROJECT_ID,
14
  username="server",
15
  contact_info="contact"
16
  )
 
17
 
18
+ # n-chars.txtの読み込み
19
+ def load_char_map():
20
+ char_map = {}
21
+ with open("turbowarp-server/n-chars.txt", "r", encoding="utf-8") as f:
22
+ lines = f.readlines()
23
+ for i, line in enumerate(lines):
24
+ char = line.strip()
25
+ if char: # 空行をスキップ
26
+ char_map[char] = str(i).zfill(2) # 00-99の2桁に
27
+ return char_map
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
+ def encode_prompt(prompt, char_map):
30
+ """プロンプトを数字列にエンコード"""
31
+ encoded = []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  for char in prompt:
33
+ if char in char_map:
34
+ encoded.append(char_map[char])
35
  else:
36
+ # 未知の文字はスペース(または適当な文字)として処理
37
+ encoded.append(char_map.get(" ", "00"))
38
+ return "".join(encoded)
 
 
 
 
 
39
 
40
+ def decode_prompt(encoded_str, char_map):
41
+ """数字列をプロンプトにデコ"""
42
+ # 文字マップの逆引きを作成
43
+ reverse_map = {v: k for k, v in char_map.items()}
44
+ decoded = []
45
+ for i in range(0, len(encoded_str), 2):
46
+ code = encoded_str[i:i+2]
47
+ if code in reverse_map:
48
+ decoded.append(reverse_map[code])
 
49
  else:
50
+ decoded.append("?")
51
+ return "".join(decoded)
 
 
 
52
 
53
+ def get_var(name):
54
+ """クラウド数の取得(安全版)"""
55
+ try:
56
+ return tw.get_variable(name=name, name_literal=False)
57
+ except Exception:
58
+ return None
59
+
60
+ def set_var(name, value):
61
+ """クラウド変数の設定(安全版)"""
62
+ try:
63
+ return tw.set_variable(name=name, value=value, name_literal=False)
64
+ except Exception:
65
+ return None
66
 
67
  def generate_image(prompt):
68
+ """画像生成APIを呼び出し、画像データを取得"""
69
+ url = "https://izuemon-pixart-alpha-pixart-sigma-xl-2-1024-ms.hf.space/gen"
70
+
71
  params = {
72
  "prompt": prompt,
73
  "negative_prompt": "nsfw, low quality",
74
+ "seed": random.randint(0, 2**32 - 1),
75
+ "randomize_seed": "true",
76
  "width": 352,
77
  "height": 352,
78
+ "guidance_scale": 0, # CFG=0
79
+ "num_inference_steps": 2
 
 
80
  }
 
 
 
 
 
 
 
 
 
 
81
 
82
+ try:
83
+ response = requests.get(url, params=params, timeout=30)
84
+ if response.status_code == 200:
85
+ return Image.open(BytesIO(response.content))
86
+ else:
87
+ print(f"画像生成エラー: {response.status_code}")
88
+ return None
89
+ except Exception as e:
90
+ print(f"画像生成例外: {e}")
91
+ return None
92
+
93
+ def resize_image(image, size=(90, 90)):
94
+ """画像をリサイズ"""
95
+ return image.resize(size, Image.Resampling.LANCZOS)
96
+
97
+ def image_to_rgb_string(image):
98
+ """画像をRGB文字列に変換(000000-999999の形式)"""
99
+ pixels = []
100
+ width, height = image.size
101
 
102
+ for y in range(height):
103
+ for x in range(width):
104
+ r, g, b = image.getpixel((x, y))
105
+ # RGBを6桁数値に変換(例: 255,255,255 -> 255255255
106
+ rgb_value = f"{r:03d}{g:03d}{b:03d}"
107
+ pixels.append(rgb_value)
 
 
 
 
108
 
109
+ return "".join(pixels)
 
 
110
 
111
+ def send_packets(data, prefix="10"):
112
+ """データをパケットに分割して送信"""
113
+ max_chars = 9998 # 10000文字制限のため
114
+
115
+ # データを分割
116
  packets = []
117
+ for i in range(0, len(data), max_chars):
118
+ packets.append(data[i:i+max_chars])
 
119
 
120
+ total_packets = len(packets)
 
 
 
121
 
122
+ for packet_index, packet_data in enumerate(packets):
123
+ # パケット番号を付加(例: 10_0, 10_1...)
124
+ packet_value = f"{prefix}_{packet_index}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
 
126
+ # データを送信(クラウド変数は文字列として扱う)
127
+ set_var(packet_value, packet_data)
128
 
129
+ # 次のパケットを送信するまで待機(ack確認)
130
+ while True:
131
+ ack = get_var("11")
132
+ if ack == str(packet_index):
133
+ break
134
+ time.sleep(0.1)
135
 
136
+ # 0.5秒間隔を空ける
137
+ time.sleep(0.5)
138
+
139
+ # 送信完了を通知
140
+ set_var("10_complete", "1")
141
+ time.sleep(0.5)
142
+
143
+ def process_request():
144
+ """メイン処理:リクエストの監視と処理"""
145
+ char_map = load_char_map()
146
+ last_n1_value = None
147
+
148
+ print("サーバー起動完了。リクエストを監視中...")
149
+
150
+ while True:
151
+ try:
152
+ # n1の監視
153
+ n1_value = get_var("n1")
154
 
155
+ if n1_value is not None and n1_value != last_n1_value:
156
+ # 文字列として扱う
157
+ n1_str = str(n1_value)
158
 
159
+ # 有効な形式かチェック(少なくとも2文字以上)
160
+ if len(n1_str) >= 2:
161
+ msg_type = n1_str[0] # 0: ID送信, 1: レスポンス返信
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
 
163
+ # 受信メッセージ(ID送信)の場合
164
+ if msg_type == "0":
165
+ print("リクエストを受信しました")
 
 
 
 
 
 
 
 
 
 
166
 
167
+ # ビジー状態に設定
168
+ set_var("n0", "1")
169
+ time.sleep(0.1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
 
171
+ try:
172
+ # IDを取得(3桁目以降)
173
+ encoded_data = n1_str[2:] if len(n1_str) > 2 else ""
174
+
175
+ if encoded_data:
176
+ # 既読に設定
177
+ # 2文字目を1に変更(既読)
178
+ new_n1 = "1" + n1_str[1:2] + encoded_data
179
+ set_var("n1", new_n1)
180
+ time.sleep(0.1)
181
+
182
+ # プロンプトをデコード
183
+ prompt = decode_prompt(encoded_data, char_map)
184
+ print(f"プロンプト: {prompt}")
185
+
186
+ # 画像生成
187
+ print("画像生成中...")
188
+ image = generate_image(prompt)
189
+
190
+ if image:
191
+ # リサイズ
192
+ resized = resize_image(image, (90, 90))
193
+
194
+ # RGB文字列に変換
195
+ rgb_data = image_to_rgb_string(resized)
196
+
197
+ # データの先頭に "10" を付加
198
+ full_data = "10" + rgb_data
199
+
200
+ # パケット分割送信
201
+ print("データ送信中...")
202
+ send_packets(full_data)
203
+
204
+ print("処理完了")
205
+ else:
206
+ print("画像生成に失敗しました")
207
+ # エラー通知
208
+ set_var("10_error", "1")
209
+ time.sleep(0.5)
210
+ else:
211
+ print("データが空です")
212
+
213
+ except Exception as e:
214
+ print(f"処理中エラー: {e}")
215
+ set_var("10_error", "1")
216
+ time.sleep(0.5)
217
+
218
+ finally:
219
+ # ビジー状態を解除
220
+ set_var("n0", "0")
221
+ time.sleep(0.1)
222
 
223
+ last_n1_value = n1_value
 
 
 
 
 
 
224
 
225
+ # 適度な間隔で監視
226
+ time.sleep(0.1)
227
+
228
+ except KeyboardInterrupt:
229
+ print("\nサーバーを停止します")
230
+ break
231
+ except Exception as e:
232
+ print(f"監視ループエラー: {e}")
233
+ time.sleep(1)
234
+
235
+ if __name__ == "__main__":
236
+ process_request()