Nyanpre commited on
Commit
f09bea5
·
verified ·
1 Parent(s): 2bad110

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +59 -43
app.py CHANGED
@@ -6,24 +6,41 @@ import io
6
 
7
  members = ["かほ", "さや", "こず", "るり", "めぐ", "つづ", "ぎん", "すず", "ひめ", "せら", "いず", "さち"]
8
 
 
 
 
 
 
 
 
 
 
 
 
9
  def generate_oracle_image(pair_name):
10
- # 画像作成 (600x400, 白背景)
11
- img = Image.new('RGB', (600, 400), color=(255, 255, 255))
 
 
 
 
12
  d = ImageDraw.Draw(img)
13
 
14
  # 枠線
15
- d.rectangle([10, 10, 590, 390], outline=(0, 0, 0), width=8)
16
 
17
- # 描画(デフォルトフォントを使用
18
- d.text((300, 140), "本日の神託", fill=(0, 0, 0), anchor="mm")
19
- d.text((300, 260), pair_name, fill=(0, 0, 0), anchor="mm")
20
 
21
  return img
22
 
23
  def get_personal_daily_oracle(device_id):
24
- seed_base = device_id if device_id else "default_fate"
 
25
  jst = timezone(timedelta(hours=9))
26
  today_str = datetime.now(jst).strftime("%Y-%m-%d")
 
27
  random.seed(f"{seed_base}_{today_str}")
28
 
29
  selected = random.sample(members, 2)
@@ -36,25 +53,31 @@ def get_personal_daily_oracle(device_id):
36
  f"<div style='font-size: 52px; font-weight: 900; letter-spacing: 2px;'>{pair_name}</div>"
37
  )
38
 
 
39
  img_result = generate_oracle_image(pair_name)
40
 
41
  # [神託HTML, メッセージ, ボタン表示, 枠表示, 画像データ]
42
  return oracle_html, "これにより、不毛なカップリング論争は終結しました。", gr.update(visible=True), gr.update(visible=True), img_result
43
 
 
44
  js_logic = """
45
  function(deviceId) {
46
  const lastDraw = localStorage.getItem('lastOracleDate');
47
  const lastPair = localStorage.getItem('lastPairText');
48
  const today = new Date().toLocaleDateString('ja-JP');
 
49
  if (lastDraw === today && lastPair) {
50
  alert("本日の神託は既に下されています。\\n明日の更新まで、今の思想を維持しなさい。");
 
51
  return [lastPair, "これにより、不毛なカップリング論争は終結しました。", { "visible": true, "__type__": "update" }, { "visible": true, "__type__": "update" }, null];
52
  }
 
53
  localStorage.setItem('lastOracleDate', today);
54
  return [null, null, null, null, null];
55
  }
56
  """
57
 
 
58
  js_save_result = """
59
  function(oracleHtml, peaceMsg, shareBtn, resultBox, img) {
60
  if (oracleHtml && oracleHtml.includes("本日の神託")) {
@@ -63,12 +86,22 @@ function(oracleHtml, peaceMsg, shareBtn, resultBox, img) {
63
  }
64
  """
65
 
 
66
  js_share_bluesky = """
67
  function() {
68
  const pairRawEl = document.getElementById('pair-raw');
69
- let pairName = pairRawEl ? pairRawEl.innerText : "運命";
 
 
 
 
 
 
 
 
 
70
  const currentUrl = window.location.href;
71
- const text = `私は「${pairName}」を信仰しています。\\n\\n画像をクリックして保存し添付して広めなさい。\\n\\n蓮ノ空聖書正典:${currentUrl}`;
72
  const intentUrl = `https://bsky.app/intent/compose?text=${encodeURIComponent(text)}`;
73
  window.open(intentUrl, '_blank');
74
  }
@@ -76,41 +109,24 @@ function() {
76
 
77
  custom_css = """
78
  .gradio-container { max-width: 600px !important; text-align: center !important; }
79
- .center-content { display: flex !important; flex-direction: column !important; align-items: center !important; padding-top: 35px !important; }
80
- h1 { margin-top: 0px !important; margin-bottom: -5px !important; font-size: 32px !important; }
81
- #doctrine { font-size: 1.5em !important; line-height: 1.4 !important; font-weight: bold !important; margin-bottom: -5px !important; }
82
- #oracle-box { color: #000 !important; background: #fff !important; border: 4px solid #000 !important; padding: 25px 10px !important; min-height: 130px !important; display: flex !important; flex-direction: column !important; justify-content: center !important; margin: 0px auto -5px auto !important; }
83
- #peace-msg { font-size: 20px !important; font-weight: bold !important; color: #d63031 !important; margin: 0px auto -5px auto !important; }
84
- .action-btn { font-size: 26px !important; font-weight: bold !important; height: 70px !important; width: 320px !important; border: 2px solid #000 !important; }
85
- #draw-btn { margin: 0px auto -5px auto !important; }
86
- #share-btn { margin: 0px auto 10px auto !important; }
87
- #result-img { max-width: 300px !important; margin: 10px auto !important; border: 1px solid #ccc; }
88
- """
89
-
90
- with gr.Blocks(title="蓮ノ空聖書正典") as demo:
91
- device_id_storage = gr.State()
92
- 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; }")
93
 
94
- with gr.Column(elem_classes="center-content"):
95
- gr.Markdown("# ⚖️ 蓮ノ空聖書正典")
96
- gr.Markdown("日付が変わるまであなたの思想は<br>統一されます。", elem_id="doctrine")
97
-
98
- result_display = gr.HTML(elem_id="oracle-box", visible=False)
99
- result_image = gr.Image(label="神託の証(保存して投稿に添付してください)", elem_id="result-img", visible=False)
100
- peace_display = gr.Markdown(elem_id="peace-msg")
101
-
102
- draw_btn = gr.Button("神託を受ける", variant="primary", elem_id="draw-btn", elem_classes="action-btn")
103
- share_btn = gr.Button("信仰を広める", variant="secondary", elem_id="share-btn", elem_classes="action-btn", visible=False)
104
 
105
- draw_btn.click(
106
- fn=get_personal_daily_oracle,
107
- inputs=[device_id_storage],
108
- outputs=[result_display, peace_display, share_btn, result_display, result_image],
109
- js=js_logic
110
- ).then(fn=None, inputs=[result_display, peace_display, share_btn, result_display, result_image], outputs=None, js=js_save_result)
111
 
112
- share_btn.click(fn=None, inputs=None, outputs=None, js=js_share_bluesky)
 
 
 
 
 
 
113
 
114
- if __name__ == "__main__":
115
- # CSSとテーマをlaunchに移動
116
- demo.launch(css=custom_css, theme=gr.themes.Monochrome())
 
6
 
7
  members = ["かほ", "さや", "こず", "るり", "めぐ", "つづ", "ぎん", "すず", "ひめ", "せら", "いず", "さち"]
8
 
9
+ # 都度フォントを読み込む負荷を避けるため、グローバルで保持
10
+ try:
11
+ # 適切な日本語フォントのパスを指定してください(例: NotoSansJP)
12
+ font_path = "/usr/share/fonts/truetype/noto/NotoSansJP-Regular.otf"
13
+ font_title = ImageFont.truetype(font_path, 32)
14
+ font_pair = ImageFont.truetype(font_path, 54)
15
+ except:
16
+ # フォントが見つからない場合のフォールバック
17
+ font_title = ImageFont.load_default()
18
+ font_pair = ImageFont.load_default()
19
+
20
  def generate_oracle_image(pair_name):
21
+ """
22
+ ペア名から神託画像を生成し、PIL Imageオブジェクトとして返す。
23
+ Pillowによる描画は非常に高速で、サーバー負荷は軽微です。
24
+ """
25
+ # 画像作成 (OGPを意識した1200x630サイズ、白背景)
26
+ img = Image.new('RGB', (1200, 630), color=(255, 255, 255))
27
  d = ImageDraw.Draw(img)
28
 
29
  # 枠線
30
+ d.rectangle([20, 20, 1180, 610], outline=(0, 0, 0), width=10)
31
 
32
+ # テキスト描画(中央揃え
33
+ d.text((600, 220), "本日の神託", fill=(0, 0, 0), font=font_title, anchor="mm")
34
+ d.text((600, 380), pair_name, fill=(0, 0, 0), font=font_pair, anchor="mm")
35
 
36
  return img
37
 
38
  def get_personal_daily_oracle(device_id):
39
+ # IDがない場合は一時的なものを使用
40
+ seed_base = device_id if device_id else str(random.random())
41
  jst = timezone(timedelta(hours=9))
42
  today_str = datetime.now(jst).strftime("%Y-%m-%d")
43
+
44
  random.seed(f"{seed_base}_{today_str}")
45
 
46
  selected = random.sample(members, 2)
 
53
  f"<div style='font-size: 52px; font-weight: 900; letter-spacing: 2px;'>{pair_name}</div>"
54
  )
55
 
56
+ # 画像をその場で生成
57
  img_result = generate_oracle_image(pair_name)
58
 
59
  # [神託HTML, メッセージ, ボタン表示, 枠表示, 画像データ]
60
  return oracle_html, "これにより、不毛なカップリング論争は終結しました。", gr.update(visible=True), gr.update(visible=True), img_result
61
 
62
+ # JS: 状態チェックと復元
63
  js_logic = """
64
  function(deviceId) {
65
  const lastDraw = localStorage.getItem('lastOracleDate');
66
  const lastPair = localStorage.getItem('lastPairText');
67
  const today = new Date().toLocaleDateString('ja-JP');
68
+
69
  if (lastDraw === today && lastPair) {
70
  alert("本日の神託は既に下されています。\\n明日の更新まで、今の思想を維持しなさい。");
71
+ # 2回目以降は画像出力をnullにする(負荷ゼロ)
72
  return [lastPair, "これにより、不毛なカップリング論争は終結しました。", { "visible": true, "__type__": "update" }, { "visible": true, "__type__": "update" }, null];
73
  }
74
+
75
  localStorage.setItem('lastOracleDate', today);
76
  return [null, null, null, null, null];
77
  }
78
  """
79
 
80
+ # JS: 結果の保存
81
  js_save_result = """
82
  function(oracleHtml, peaceMsg, shareBtn, resultBox, img) {
83
  if (oracleHtml && oracleHtml.includes("本日の神託")) {
 
86
  }
87
  """
88
 
89
+ # JS: Bluesky投稿
90
  js_share_bluesky = """
91
  function() {
92
  const pairRawEl = document.getElementById('pair-raw');
93
+ let pairName = "";
94
+
95
+ if (pairRawEl) {
96
+ pairName = pairRawEl.innerText;
97
+ } else {
98
+ const lastPair = localStorage.getItem('lastPairText') || "";
99
+ const match = lastPair.match(/>([^<]{4,})<\\/div>$/);
100
+ pairName = match ? match[1] : "運命";
101
+ }
102
+
103
  const currentUrl = window.location.href;
104
+ const text = `私は「${pairName}」を信仰しています。\\n\\n画像(神託の証)を保存して投稿に添付しなさい。\\n\\n蓮ノ空聖書正典:${currentUrl}`;
105
  const intentUrl = `https://bsky.app/intent/compose?text=${encodeURIComponent(text)}`;
106
  window.open(intentUrl, '_blank');
107
  }
 
109
 
110
  custom_css = """
111
  .gradio-container { max-width: 600px !important; text-align: center !important; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
 
113
+ /* 最上部の空白 */
114
+ .center-content {
115
+ display: flex !important;
116
+ flex-direction: column !important;
117
+ align-items: center !important;
118
+ padding-top: 35px !important;
119
+ }
 
 
 
120
 
121
+ h1 { margin-top: 0px !important; margin-bottom: -5px !important; font-size: 32px !important; }
 
 
 
 
 
122
 
123
+ /* 教義 */
124
+ #doctrine {
125
+ font-size: 1.5em !important;
126
+ line-height: 1.4 !important;
127
+ font-weight: bold !important;
128
+ margin-bottom: -5px !important;
129
+ }
130
 
131
+ /* 結果表示ボックス */
132
+ #oracle-box {