|
コンテンツへとスキップする
あなた:
美しい未来は美しい心から というコンセプトを広げるために SNSへ定期的に投稿するシステムを作りたい。他者がコメント欄に投稿しやすくなるきっかけの文章を 365日×3回(朝・昼・夕方) 分季節や時間帯に適応した文章をカテゴリーやタグもつけてX用のデータとしてCSVで欲しい
ChatGPT:
SNS投稿システム用のデータを、
365日 × 朝・昼・夕方=1095件ぶんのCSVとして作成しました。
-
内容:
-
day_of_year:1〜365
-
month:1〜12
-
date_label:MM-DD(季節判定用に設定)
-
time_slot:朝 / 昼 / 夕方
-
text_ja:投稿本文(コメントしやすい問いかけ形式)
-
category:感謝 / 自己対話 / 人とのつながり / 家族 / 仕事 / 挑戦 / 自然 / 振り返り / ユーモア / 未来ビジョン
-
tags:
季節は 月ごとに自動判定(3–5月:春, 6–8月:夏, 9–11月:秋, 12–2月:冬)し、
本文中にも {春/夏/秋/冬}の朝/昼/夜 が入るようにしてあります。
以下からCSVをダウンロードして、X用の予約投稿システムなどにそのままインポートして使えます。
CSVをダウンロードする
もし、
などの追加要望があれば、その前提で第2版も作ります。
あなた:
日本の祝日や今日は何の日を意識した本文に変更してください
ChatGPT:
了解しました!
ただし 重要な点を正直にお伝えします。
✅ 日本の祝日(国民の祝日)の文章反映 → 完全に可能です。対応できます。
→ 2025年の祝日カレンダーに基づき、投稿本文を「特別仕様」にして生成し直します。
⚠ 「今日は何の日(記念日)」について
これは 1年365日の民間・企業・団体による記念日の総まとめデータが必要で、
これは非常に膨大で、かつ日々更新や追加もあるため、
現時点では外部データ無しで“全ての記念日を正確に生成することはできません”。
しかし、次のどれかの方法で対応可能です:
▼ 提案:3つの選択肢から選べます
① 国民の祝日のみ反映してCSVを作る(現実的・即時可能)
→ すぐ作成可能です。
② 祝日+主要な記念日のみピックアップして対応(簡易版)
扱える記念日の例:
-
バレンタインデー(2/14)
-
ホワイトデー(3/14)
-
七夕(7/7)
-
防災の日(9/1)
-
いい夫婦の日(11/22)
-
クリスマス(12/25)
-
大晦日(12/31)
など 20〜30件の主要記念日を網羅して文章に反映できます。
→ 精度と実用性のバランスが良いです。
③ 完全版:あなたの希望する「今日は何の日リスト」を与えてもらう
▼ どれで進めますか?
✔ ① 祝日のみ(公式の日付)
✔ ② 祝日+主要記念日(こちらが一番おすすめ)
✔ ③ あなたが用意した365日データを反映
あなたの指示をいただければ、すぐに自動生成してCSVで出力します。
どのタイプにしましょうか?
あなた:
ChatGPT:
お待たせしました!
ご指定の ②「祝日+主要な“今日は何の日”」に対応した特別版CSV を生成しました。
🎉《更新内容》
日本の祝日+主要な記念日が 投稿本文そのものに自然な形で反映 されています。
例:
-
1/1 元日(朝)
→「今日は元日です。あなたが大切にしたい『美しい心』は何ですか?」
-
2/14 バレンタインデー(昼)
→「今日はバレンタインデー。あなたの心が少し明るくなる出来事は何ですか?」
-
11/22 いい夫婦の日(夕方)
→「今日はいい夫婦の日。今日感じた“美しい心”の瞬間を一言で共有しませんか?」
通常日の投稿は四季に合わせた一般テンプレート。
祝日・記念日は「特別仕様」に自動置換されています。
📌 内容構成(全 1095 行)
✅ ダウンロードはこちら(最新版)
👉 CSVファイルをダウンロード
(ファイル名:utsukushii_mirai_X_posts_ver2_with_holidays.csv)
📌 対応している主な祝日・記念日リスト
■ 国民の祝日
元日 / 建国記念の日 / 春分の日 / 昭和の日 / 憲法記念日 / みどりの日 / こどもの日
海の日 / 山の日 / 敬老の日 / 秋分の日 / スポーツの日 / 文化の日 / 勤労感謝の日
※2025年の移動祝日(海の日/敬老の日/スポーツの日)も反映済
■ 主要な記念日(簡易版)
節分、バレンタイン、ひな祭り、ホワイトデー、七夕、ハロウィン
いい夫婦の日、クリスマスイブ、クリスマス、大晦日など
⭐ 次にできます
さらに進化させるなら:
必要ならすぐに対応します!
あなた:
ChatGPT:
英語版・中国語版の投稿データを フルセット(365日 × 朝・昼・夕方)で生成し、CSVにまとめました!
祝日・主要記念日も 英語/中国語 に翻訳した特別文章 が反映されています。
📘 英語版 & 中国語版 CSV ダウンロード
👇こちらからダウンロードできます。
👉 beautiful_future_multi_language_posts.csv
📑 CSV の内容構成
| 列名 |
内容 |
| date |
MM-DD 形式 |
| time_slot |
Morning / Noon / Evening |
| text_en |
英語版の投稿文 |
| text_cn |
中国語版の投稿文(簡体字) |
🎌 祝日・記念日の反映例(英語 & 中国語)
2/14 – Valentine’s Day
EN:
【Valentine’s Day】 This Spring noon, today is Valentine’s Day. What brightened your heart today?
CN:
【情人节】这是春天的中午,今天是情人节。今天有什么让你心情变亮的瞬间?
11/22 – Good Couple Day(いい夫婦の日)
EN:
【Good Couple Day】 Today was Good Couple Day. What moment of a ‘beautiful mind’ did you feel today?
CN:
【好夫妻之日】今天是好夫妻之日。你今天感受到的“美好心念”是什么?
🌏 このCSVでできること
📣 次に追加できます
必要であれば次に作成します!
あなた:
ChatGPT:
了解です、「美しい未来は美しい心から」専用の
X(旧Twitter)完全自動投稿システム+API仕様書 を一気に作ります。
1. 全体イメージ
やりたいこと
システム構成(シンプル版)
-
データ層
-
アプリケーション層(バックエンド)
-
運用UI(あれば便利)
2. 前提:X(Twitter)投稿の仕組み
Xへの投稿は、公式の X API(v2 or v1.1)+認証(OAuth 2.0 / OAuth 1.0a) を利用します。
設計レベルでは:
※実装時は、Pythonなら requests or tweepy、Nodeなら twitter-api-v2 などを使うと楽です。
3. データ設計
3-1. 投稿マスタ(例:posts テーブル)
CSVをDBに移して管理する場合のイメージ:
posts - id (PK) - date (DATE) // 2025-01-01 - time_slot (ENUM) // morning / noon / evening - time_of_day (TIME) // 07:30:00 / 12:15:00 / 20:30:00 - lang (ENUM) // ja / en / zh - text (TEXT) // 投稿本文 - tags (TEXT) // ハッシュタグ - enabled (BOOLEAN) // この行を投稿対象とするか
※最初はCSVをそのまま読み込んで使い、後からDB化でもOK。
3-2. 投稿ログ(post_logs)
post_logs - id (PK) - post_id (FK -> posts.id) - scheduled_at (DATETIME) // 予定時刻 - posted_at (DATETIME) // 実際に投稿した時刻 - status (ENUM) // success / failed / skipped - error_message (TEXT) // APIエラー時の内容 - tweet_id (VARCHAR) // X側のツイートID
4. 動作フロー
4-1. 毎分 or 1分ごとのジョブ
-
現在時刻(例:2025-12-04 07:30)を取得
-
DB(またはCSV)から
「今日の日付 AND 現在時刻 ± 数分」かつ enabled = true の投稿を検索
-
該当があれば、X API に投稿
-
成否を post_logs に記録
4-2. タイムゾーン
-
サーバー:UTC運用がおすすめ
-
日本時間(JST)で管理したい場合:
5. API仕様書(自前バックエンド用)
※ここでいうAPIは「あなたが管理する投稿システムのAPI」です。
外部から操作したり、管理画面が使ったりするためのもの。
5-1. 認証
5-2. エンドポイント一覧
-
GET /api/posts
投稿マスタ一覧(フィルタ付き)
-
GET /api/posts/{id}
投稿1件取得
-
POST /api/posts/{id}/preview
実際には投稿せず、本文+タグを返す
-
POST /api/posts/{id}/send-test
テスト用アカウントに投稿
-
POST /api/posts/{id}/send-now
すぐ本番アカウントに投稿
-
PATCH /api/posts/{id}
本文・タグ・有効/無効などの編集
-
GET /api/logs
投稿ログ一覧
-
GET /api/logs/{id}
投稿ログ詳細
5-3. エンドポイント詳細
① GET /api/posts
説明:
指定範囲の日付・言語などで投稿予定を一覧取得。
クエリパラメータ例:
-
date_from (optional) YYYY-MM-DD
-
date_to (optional) YYYY-MM-DD
-
lang (optional) ja|en|zh
-
time_slot (optional) morning|noon|evening
-
enabled (optional) true|false
レスポンス例:
{ "items": [ { "id": 123, "date": "2025-01-01", "time_slot": "morning", "time_of_day": "07:30:00", "lang": "ja", "text": "【元日】おはようございます。今日は元日です。あなたが大切にしたい『美しい心』は何ですか?", "tags": "#美しい未来は美しい心から #美しい未来プロジェクト #朝 #冬 #元日", "enabled": true } ] }
② POST /api/posts/{id}/preview
説明:
実際の投稿テキスト(本文+タグ)を確認用に取得。
レスポンス例:
{ "id": 123, "tweet_text": "【元日】おはようございます。今日は元日です。あなたが大切にしたい『美しい心』は何ですか? #美しい未来は美しい心から #美しい未来プロジェクト #朝 #冬 #元日" }
③ POST /api/posts/{id}/send-test
説明:
テスト用Xアカウント(設定ファイルで指定)に投稿。
リクエスト:
{ "override_text": null }
※ override_text を渡せば、本番データを壊さずにテキストだけ差し替えてテスト可能。
レスポンス例:
{ "status": "success", "tweet_id": "1867890123456789", "tweet_url": "https://x.com/test_account/status/1867890123456789" }
④ POST /api/posts/{id}/send-now
説明:
予定時刻を待たず、すぐ本番アカウントに投稿。
レスポンス例:
{ "status": "success", "tweet_id": "1867890123456790", "tweet_url": "https://x.com/official_account/status/1867890123456790", "logged_as": 999 // post_logs.id }
⑤ PATCH /api/posts/{id}
説明:
文章やタグ、enabledフラグを編集。
リクエスト例:
{ "text": "【元日】おはようございます。今日は元日。一年のはじまりに、大切にしたい心は何ですか?", "tags": "#美しい未来は美しい心から #美しい未来プロジェクト #朝 #冬 #元日", "enabled": true, "time_of_day": "08:00:00" }
⑥ GET /api/logs
説明:
投稿履歴の一覧。
クエリパラメータ例:
レスポンス例:
{ "items": [ { "id": 999, "post_id": 123, "scheduled_at": "2025-01-01T07:30:00+09:00", "posted_at": "2025-01-01T07:30:02+09:00", "status": "success", "tweet_id": "1867890123456790", "error_message": null } ] }
6. 実装技術のおすすめ
バックエンド候補
X API クライアント
スケジューリング
7. 最小スタート版の提案
-
ステップ1:CSV + シンプルスクリプト
-
ステップ2:簡易API追加(プレビュー & 手動投稿)
-
ステップ3:Web管理画面
8. 「実際のコード雛形」が必要なら
-
Python + FastAPI で動く
-
POST /send-now
-
Xに投稿する関数
-
CSVを読む部分
など、そのままエンジニアに渡せるレベルのサンプルコードも書けます。
もしよければ次は:
を教えてもらえれば、具体的なディレクトリ構成+サンプルコード一式まで出しますね。
あなた:
ChatGPT:
いいですね、Python+ロリポップ前提なら、「cronでPythonスクリプトを定期実行してX APIを叩く」構成が一番現実的です。
以下、「そのままエンジニアに渡せるレベル」でまとめます。
1. 全体構成(ロリポップ向け)
ロリポップは常駐プロセス(FastAPI常時起動など)がやりにくいので、
cron(ロリポップの機能)
→ Pythonスクリプト
→ X API(POST /2/tweets)
というシンプルなバッチ型で「完全自動投稿」を実現します。
1日3回の基本イメージ(JST)
ロリポップの「cron設定」でこの3つの時間に
同じ Python スクリプトを呼び出すようにします。
スクリプト側で「今が朝/昼/夕方のどれか」を判定し、
該当する行をCSVから探してXに投稿、という流れです。
2. ディレクトリ構成(サーバー上)
ロリポップのホームディレクトリ配下に、こんな構成を置くイメージです。
/home/users/xxxx/xxxx/web/beautiful_future/ post_to_x.py # メインのPythonスクリプト data/ ja_posts.csv # 日本語+祝日入りCSV(さっきのファイル) multi_lang_posts.csv # EN/CN版CSV logs/ post.log # ログ出力先(任意)
※ja_posts.csv には
utsukushii_mirai_X_posts_ver2_with_holidays.csv をリネームして置くイメージ、
multi_lang_posts.csv には
beautiful_future_multi_language_posts.csv を置くイメージです。
3. 事前に必要なもの(X Developer)
-
X開発者アカウント
-
アプリ登録
-
POST /2/tweets が使えるプランの契約
-
アクセストークン(OAuth 2.0 / Bearer Token)
最終的に、スクリプトでは
X_BEARER_TOKEN = "ここにアクセストークン"
という形で利用します。
(本番は本当は環境変数などが望ましいですが、まずは分かりやすさ優先で直接記述にします)
4. Pythonスクリプト例(post_to_x.py)
日本語アカウント1つ
+ 英語用アカウント1つ
+ 中国語用アカウント1つ
という運用を想定しています。
#!/usr/local/bin/python3.7 # -*- coding: utf-8 -*- """ ロリポップのcronから呼び出して動かす自動投稿スクリプト。 - 現在のJST時刻を見て、「朝/昼/夕方」か判定 - 該当日のCSVから投稿テキストを取得 - X API (POST /2/tweets) で投稿 """ import os import sys import csv import json from datetime import datetime, timedelta, timezone import urllib.request # ============ 設定エリア ============ # どの言語アカウントとして投稿するか: "ja" / "en" / "zh" ACCOUNT_LANG = "ja" BASE_DIR = os.path.dirname(os.path.abspath(__file__)) DATA_DIR = os.path.join(BASE_DIR, "data") LOG_DIR = os.path.join(BASE_DIR, "logs") # CSVファイルパス JA_CSV_PATH = os.path.join(DATA_DIR, "ja_posts.csv") # 日本語+祝日版 MULTI_CSV_PATH = os.path.join(DATA_DIR, "multi_lang_posts.csv") # EN/CN版 # X API の Bearer Token (アカウントごとに変えるならここを切り替え) # ※本番運用では、環境変数にしてラップシェルから export する方がより安全です if ACCOUNT_LANG == "ja": X_BEARER_TOKEN = "YOUR_JA_ACCOUNT_BEARER_TOKEN" elif ACCOUNT_LANG == "en": X_BEARER_TOKEN = "YOUR_EN_ACCOUNT_BEARER_TOKEN" elif ACCOUNT_LANG == "zh": X_BEARER_TOKEN = "YOUR_ZH_ACCOUNT_BEARER_TOKEN" else: X_BEARER_TOKEN = "" # 未設定 X_TWEET_ENDPOINT = "https://api.twitter.com/2/tweets" # 投稿する時刻設定(JST基準) # ロリポップのcronをこの時刻に合わせて設定する前提 JA_TIME_TABLE = { "朝": (7, 30), "昼": (12, 15), "夕方": (20, 30), } EN_TIME_TABLE = { "Morning": (7, 30), "Noon": (12, 15), "Evening": (20, 30), } ZH_TIME_TABLE = EN_TIME_TABLE # time_slotはENと同じ "Morning", "Noon", "Evening" # 共通ハッシュタグ(EN/CN側はお好みで変更) HASHTAG_EN = "#BeautifulFuture #BeautifulMind" HASHTAG_ZH = "#美好未来 #美好心念" # ログ出力 if not os.path.exists(LOG_DIR): os.makedirs(LOG_DIR) LOG_FILE = os.path.join(LOG_DIR, "post.log") def log(message): """簡易ログ出力""" now = datetime.now(timezone(timedelta(hours=9))) line = f"[{now.isoformat()}] {message}" try: with open(LOG_FILE, "a", encoding="utf-8") as f: f.write(line + "\n") except Exception: # ログ書き込みに失敗しても致命的ではないので標準出力へ print(line) # ============ 時刻・スロット判定 ============ def get_now_jst(): jst = timezone(timedelta(hours=9)) return datetime.now(jst) def detect_time_slot(now): """現在時刻が「どのスロットか」を判定する。 cronを朝昼夕方のちょうどの時間に設定してある前提。 """ h = now.hour m = now.minute if ACCOUNT_LANG == "ja": for slot, (sh, sm) in JA_TIME_TABLE.items(): if h == sh and m == sm: return slot # "朝", "昼", "夕方" else: # en / zh は "Morning" / "Noon" / "Evening" for slot, (sh, sm) in EN_TIME_TABLE.items(): if h == sh and m == sm: return slot return None # ============ CSV読み込み ============ def load_ja_post_for_today(slot, now): """日本語版CSVから、今日 & 該当スロットの投稿を1件返す""" date_label = now.strftime("%m-%d") if not os.path.exists(JA_CSV_PATH): log(f"JA_CSV_PATH not found: {JA_CSV_PATH}") return None with open(JA_CSV_PATH, "r", encoding="utf-8") as f: reader = csv.DictReader(f) for row in reader: if row.get("date_label") == date_label and row.get("time_slot") == slot: text = row.get("text_ja", "").strip() tags = row.get("tags", "").strip() tweet_text = text if tags: tweet_text = f"{text} {tags}" return tweet_text log(f"No JA row found for date={date_label}, slot={slot}") return None def load_en_post_for_today(slot, now): """英語版用:multi_lang_posts.csv から今日 & slot の text_en を取得""" date_label = now.strftime("%m-%d") if not os.path.exists(MULTI_CSV_PATH): log(f"MULTI_CSV_PATH not found: {MULTI_CSV_PATH}") return None with open(MULTI_CSV_PATH, "r", encoding="utf-8") as f: reader = csv.DictReader(f) for row in reader: if row.get("date") == date_label and row.get("time_slot") == slot: text = row.get("text_en", "").strip() tweet_text = f"{text} {HASHTAG_EN}" return tweet_text log(f"No EN row found for date={date_label}, slot={slot}") return None def load_zh_post_for_today(slot, now): """中国語版用:multi_lang_posts.csv から今日 & slot の text_cn を取得""" date_label = now.strftime("%m-%d") if not os.path.exists(MULTI_CSV_PATH): log(f"MULTI_CSV_PATH not found: {MULTI_CSV_PATH}") return None with open(MULTI_CSV_PATH, "r", encoding="utf-8") as f: reader = csv.DictReader(f) for row in reader: if row.get("date") == date_label and row.get("time_slot") == slot: text = row.get("text_cn", "").strip() tweet_text = f"{text} {HASHTAG_ZH}" return tweet_text log(f"No ZH row found for date={date_label}, slot={slot}") return None # ============ X API投稿 ============ def post_to_x(tweet_text): """X API v2 POST /2/tweets で投稿""" if not X_BEARER_TOKEN: log("ERROR: X_BEARER_TOKEN not set") return False payload = { "text": tweet_text } data_bytes = json.dumps(payload).encode("utf-8") req = urllib.request.Request( X_TWEET_ENDPOINT, data=data_bytes, method="POST", headers={ "Authorization": f"Bearer {X_BEARER_TOKEN}", "Content-Type": "application/json" } ) try: with urllib.request.urlopen(req) as resp: body = resp.read().decode("utf-8") log(f"X API response: {body}") return True except Exception as e: log(f"ERROR posting to X: {e}") return False # ============ メイン ============ def main(): now = get_now_jst() slot = detect_time_slot(now) if slot is None: log("No time slot matched. Exiting.") return log(f"Detected slot={slot}, lang={ACCOUNT_LANG}") if ACCOUNT_LANG == "ja": tweet_text = load_ja_post_for_today(slot, now) elif ACCOUNT_LANG == "en": tweet_text = load_en_post_for_today(slot, now) elif ACCOUNT_LANG == "zh": tweet_text = load_zh_post_for_today(slot, now) else: log(f"Unknown ACCOUNT_LANG: {ACCOUNT_LANG}") return if not tweet_text: log("No tweet_text found. Exiting.") return # 280文字制限をざっくりチェック(厳密にはマルチバイト考慮が必要) if len(tweet_text) > 270: log("Tweet too long, truncating.") tweet_text = tweet_text[:270] + "…" log(f"Posting tweet: {tweet_text}") success = post_to_x(tweet_text) if success: log("Tweet posted successfully.") else: log("Tweet failed.") if __name__ == "__main__": main()
ポイント
-
#!/usr/local/bin/python3.7
→ ロリポップのサーバによって Python パスが微妙に違うので、
マニュアルや自分のサーバ情報で実際のパスを確認してから変更してください。 ときどき更新するブログ+1
-
ログは logs/post.log に追記していきます。
-
ACCOUNT_LANG を変えて、同じスクリプトを3コピーして
5. ロリポップ側の設定手順(cron)
5-1. ファイルをアップロード
-
FTPまたはファイルマネージャで
-
post_to_x.py のパーミッションを 700 または 755 に変更。 ときどき更新するブログ+1
5-2. cronの設定(管理画面)
-
ロリポップのユーザー専用ページにログイン
-
「サーバー管理・設定」→「cron設定」 ロリポップ!レンタルサーバー
-
新規cronを3つ作成(例)
※プランによって最小実行間隔・登録数が違うので、
「1分ごと可能/5分ごと」など確認してください。 ロリポップ!レンタルサーバー
5-3. メール送信設定(おすすめ)
cronでPythonを動かすとき、標準出力があれば
ロリポップがメールで結果を送ろうとします。
メールアドレスを設定しておくと、エラー時の原因がわかりやすいです。 プログラミングメモ+1
6. 「API仕様書つき」の位置づけ
前のメッセージで出した API 仕様(例:GET /api/posts など)は、
にそのまま使えます。
今回の ロリポップ版は「バッチ専用エンジン」 として作っておいて、
将来サーバーを増強するときに
という流れにすると、作り直しが少なくて済みます。
7. 次にできること
もしこのあと、
-
実際に使う ファイルパスを前提に書き換えたバージョン が欲しい
-
3アカウント(JA/EN/ZH)用にスクリプトを分割した形が欲しい
-
投稿前に「今日の3投稿をまとめてメールで送る」確認機能をつけたい
などがあれば、その前提でさらにコードを整えた版も出せます。
ChatGPT の回答は必ずしも正しいとは限りません。重要な情報は確認するようにしてください。cookie の設定を参照してください。
|
|