Nyanpre commited on
Commit
eee3c6d
·
verified ·
1 Parent(s): 3c49cd3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +35 -82
app.py CHANGED
@@ -3,66 +3,72 @@ import random
3
  from datetime import datetime, timedelta, timezone
4
  from PIL import Image, ImageDraw, ImageFont
5
  import io
 
6
 
7
- # 12名の聖職者リスト
8
  members = ["かほ", "さや", "こず", "るり", "めぐ", "つづ", "ぎん", "すず", "ひめ", "せら", "いず", "さち"]
9
 
10
- # フォント設定(日本語フォントがない場合はデフォルトを使用)
11
- try:
12
- font_path = "/usr/share/fonts/truetype/noto/NotoSansJP-Regular.otf"
13
- font_title = ImageFont.truetype(font_path, 36)
14
- font_pair = ImageFont.truetype(font_path, 60)
15
- except:
16
- font_title = ImageFont.load_default()
17
- font_pair = ImageFont.load_default()
 
 
 
 
 
 
 
18
 
19
  def generate_oracle_image(pair_name):
20
- # 画像作成 (1000x500, 白背景)
21
  img = Image.new('RGB', (1000, 500), color=(255, 255, 255))
22
  d = ImageDraw.Draw(img)
23
- # 聖典らしい太い外枠
 
24
  d.rectangle([20, 20, 980, 480], outline=(0, 0, 0), width=12)
 
 
 
 
 
25
  # テキスト描画
26
- d.text((500, 160), "本日の神託", fill=(0, 0, 0), font=font_title, anchor="mm")
27
- d.text((500, 320), pair_name, fill=(0, 0, 0), font=font_pair, anchor="mm")
 
28
  return img
29
 
30
  def get_personal_daily_oracle(device_id):
31
  seed_base = device_id if device_id else str(random.random())
32
  jst = timezone(timedelta(hours=9))
33
  today_str = datetime.now(jst).strftime("%Y-%m-%d")
34
-
35
  random.seed(f"{seed_base}_{today_str}")
36
 
37
  selected = random.sample(members, 2)
38
  random.shuffle(selected)
39
  pair_name = f"{selected[0]}{selected[1]}"
40
 
41
- # 画像生成
42
  img_result = generate_oracle_image(pair_name)
43
-
44
- # ペア名を隠し要素として渡すためのHTML(Bluesky投稿用)
45
  pair_raw_html = f"<div id='pair-raw' style='display:none;'>{pair_name}</div>"
46
 
47
  return pair_raw_html, img_result, "これにより、不毛なカップリング論争は終結しました。", gr.update(visible=True), gr.update(visible=True)
48
 
49
- # JS: 状態チェック
50
  js_logic = """
51
  function(deviceId) {
52
  const lastDraw = localStorage.getItem('lastOracleDate');
53
  const today = new Date().toLocaleDateString('ja-JP');
54
-
55
  if (lastDraw === today) {
56
  alert("本日の神託は既に下されています。\\n明日の更新まで、今の思想を維持しなさい。");
57
- // Python側の処理をスキップさせるため、入力を空にするなどの制御はGradio側で行う
58
- // ここではフラグチェックのみ
59
  }
60
  localStorage.setItem('lastOracleDate', today);
61
  return [null, null, null, null, null];
62
  }
63
  """
64
 
65
- # JS: Bluesky投稿(隠しHTMLからペア名を取得)
66
  js_share_bluesky = """
67
  function() {
68
  const pairRawEl = document.getElementById('pair-raw');
@@ -76,79 +82,27 @@ function() {
76
 
77
  custom_css = """
78
  .gradio-container { max-width: 600px !important; text-align: center !important; }
79
-
80
- .center-content {
81
- display: flex !important;
82
- flex-direction: column !important;
83
- align-items: center !important;
84
- padding-top: 40px !important;
85
- }
86
-
87
  h1 { margin-top: 0px !important; margin-bottom: -5px !important; font-size: 32px !important; }
88
-
89
- #doctrine {
90
- font-size: 1.5em !important;
91
- line-height: 1.4 !important;
92
- font-weight: bold !important;
93
- margin-bottom: -5px !important;
94
- }
95
-
96
- /* 画像表示エリアのスタイル */
97
- #result-img {
98
- border: none !important;
99
- margin: 0px auto -5px auto !important;
100
- background: transparent !important;
101
- }
102
- #result-img img {
103
- border: 4px solid #000 !important;
104
- max-width: 100% !important;
105
- }
106
-
107
- #peace-msg {
108
- font-size: 20px !important;
109
- font-weight: bold !important;
110
- color: #d63031 !important;
111
- margin: 0px auto -5px auto !important;
112
- }
113
-
114
- .action-btn {
115
- font-size: 26px !important;
116
- font-weight: bold !important;
117
- height: 70px !important;
118
- width: 320px !important;
119
- border: 2px solid #000 !important;
120
- }
121
-
122
  #draw-btn { margin: 0px auto -5px auto !important; }
123
  #share-btn { margin: 0px auto 10px auto !important; }
124
  """
125
 
126
  with gr.Blocks(title="蓮ノ空聖書正典") as demo:
127
  device_id_storage = gr.State()
128
-
129
- demo.load(None, None, device_id_storage, js="""
130
- () => {
131
- let id = localStorage.getItem('cp_oracle_device_id');
132
- if(!id) {
133
- id = Math.random().toString(36).substring(2, 15);
134
- localStorage.setItem('cp_oracle_device_id', id);
135
- }
136
- return id;
137
- }
138
- """)
139
 
140
  with gr.Column(elem_classes="center-content"):
141
  gr.Markdown("# ⚖️ 蓮ノ空聖書正典")
142
  gr.Markdown("日付が変わるまであなたの思想は<br>統一されます。", elem_id="doctrine")
143
-
144
- # 非表示のペア名保持用
145
  pair_raw_display = gr.HTML(visible=False)
146
-
147
- # 結果画像
148
  result_image = gr.Image(label=None, elem_id="result-img", visible=False, type="pil", interactive=False)
149
-
150
  peace_display = gr.Markdown(elem_id="peace-msg")
151
-
152
  draw_btn = gr.Button("神託を受ける", variant="primary", elem_id="draw-btn", elem_classes="action-btn")
153
  share_btn = gr.Button("信仰を広める", variant="secondary", elem_id="share-btn", elem_classes="action-btn", visible=False)
154
 
@@ -158,7 +112,6 @@ with gr.Blocks(title="蓮ノ空聖書正典") as demo:
158
  outputs=[pair_raw_display, result_image, peace_display, share_btn, result_image],
159
  js=js_logic
160
  )
161
-
162
  share_btn.click(fn=None, inputs=None, outputs=None, js=js_share_bluesky)
163
 
164
  if __name__ == "__main__":
 
3
  from datetime import datetime, timedelta, timezone
4
  from PIL import Image, ImageDraw, ImageFont
5
  import io
6
+ import os
7
 
 
8
  members = ["かほ", "さや", "こず", "るり", "めぐ", "つづ", "ぎん", "すず", "ひめ", "せら", "いず", "さち"]
9
 
10
+ def get_font(size):
11
+ """環境内の日本語フォントを探して読み込む"""
12
+ # Hugging FaceのDebian環境で一般的な日本語フォントパスのリスト
13
+ font_paths = [
14
+ "/usr/share/fonts/truetype/noto/NotoSansJP-Regular.otf",
15
+ "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc",
16
+ "/usr/share/fonts/truetype/fonts-japanese-gothic.ttf"
17
+ ]
18
+
19
+ for path in font_paths:
20
+ if os.path.exists(path):
21
+ return ImageFont.truetype(path, size)
22
+
23
+ # 見つからない場合はデフォルト(ただし日本語は化ける可能性あり)
24
+ return ImageFont.load_default()
25
 
26
  def generate_oracle_image(pair_name):
27
+ # 画像作成
28
  img = Image.new('RGB', (1000, 500), color=(255, 255, 255))
29
  d = ImageDraw.Draw(img)
30
+
31
+ # 枠線
32
  d.rectangle([20, 20, 980, 480], outline=(0, 0, 0), width=12)
33
+
34
+ # フォント取得
35
+ font_t = get_font(40)
36
+ font_p = get_font(80)
37
+
38
  # テキスト描画
39
+ d.text((500, 160), "本日の神託", fill=(0, 0, 0), font=font_t, anchor="mm")
40
+ d.text((500, 320), pair_name, fill=(0, 0, 0), font=font_p, anchor="mm")
41
+
42
  return img
43
 
44
  def get_personal_daily_oracle(device_id):
45
  seed_base = device_id if device_id else str(random.random())
46
  jst = timezone(timedelta(hours=9))
47
  today_str = datetime.now(jst).strftime("%Y-%m-%d")
 
48
  random.seed(f"{seed_base}_{today_str}")
49
 
50
  selected = random.sample(members, 2)
51
  random.shuffle(selected)
52
  pair_name = f"{selected[0]}{selected[1]}"
53
 
 
54
  img_result = generate_oracle_image(pair_name)
 
 
55
  pair_raw_html = f"<div id='pair-raw' style='display:none;'>{pair_name}</div>"
56
 
57
  return pair_raw_html, img_result, "これにより、不毛なカップリング論争は終結しました。", gr.update(visible=True), gr.update(visible=True)
58
 
59
+ # --- 以下、JS・CSS・Blocks構成は前回と同様 ---
60
  js_logic = """
61
  function(deviceId) {
62
  const lastDraw = localStorage.getItem('lastOracleDate');
63
  const today = new Date().toLocaleDateString('ja-JP');
 
64
  if (lastDraw === today) {
65
  alert("本日の神託は既に下されています。\\n明日の更新まで、今の思想を維持しなさい。");
 
 
66
  }
67
  localStorage.setItem('lastOracleDate', today);
68
  return [null, null, null, null, null];
69
  }
70
  """
71
 
 
72
  js_share_bluesky = """
73
  function() {
74
  const pairRawEl = document.getElementById('pair-raw');
 
82
 
83
  custom_css = """
84
  .gradio-container { max-width: 600px !important; text-align: center !important; }
85
+ .center-content { display: flex !important; flex-direction: column !important; align-items: center !important; padding-top: 40px !important; }
 
 
 
 
 
 
 
86
  h1 { margin-top: 0px !important; margin-bottom: -5px !important; font-size: 32px !important; }
87
+ #doctrine { font-size: 1.5em !important; line-height: 1.4 !important; font-weight: bold !important; margin-bottom: -5px !important; }
88
+ #result-img { border: none !important; margin: 0px auto -5px auto !important; background: transparent !important; }
89
+ #result-img img { border: 4px solid #000 !important; max-width: 100% !important; }
90
+ #peace-msg { font-size: 20px !important; font-weight: bold !important; color: #d63031 !important; margin: 0px auto -5px auto !important; }
91
+ .action-btn { font-size: 26px !important; font-weight: bold !important; height: 70px !important; width: 320px !important; border: 2px solid #000 !important; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  #draw-btn { margin: 0px auto -5px auto !important; }
93
  #share-btn { margin: 0px auto 10px auto !important; }
94
  """
95
 
96
  with gr.Blocks(title="蓮ノ空聖書正典") as demo:
97
  device_id_storage = gr.State()
98
+ demo.load(None, None, device_id_storage, js="() => { let id = localStorage.getItem('cp_oracle_device_id'); if(!id){ id = Math.random().toString(36).substring(2, 15); localStorage.setItem('cp_oracle_device_id', id); } return id; }")
 
 
 
 
 
 
 
 
 
 
99
 
100
  with gr.Column(elem_classes="center-content"):
101
  gr.Markdown("# ⚖️ 蓮ノ空聖書正典")
102
  gr.Markdown("日付が変わるまであなたの思想は<br>統一されます。", elem_id="doctrine")
 
 
103
  pair_raw_display = gr.HTML(visible=False)
 
 
104
  result_image = gr.Image(label=None, elem_id="result-img", visible=False, type="pil", interactive=False)
 
105
  peace_display = gr.Markdown(elem_id="peace-msg")
 
106
  draw_btn = gr.Button("神託を受ける", variant="primary", elem_id="draw-btn", elem_classes="action-btn")
107
  share_btn = gr.Button("信仰を広める", variant="secondary", elem_id="share-btn", elem_classes="action-btn", visible=False)
108
 
 
112
  outputs=[pair_raw_display, result_image, peace_display, share_btn, result_image],
113
  js=js_logic
114
  )
 
115
  share_btn.click(fn=None, inputs=None, outputs=None, js=js_share_bluesky)
116
 
117
  if __name__ == "__main__":