| import gradio as gr |
| import httpx |
| import json |
|
|
| def build_ui(fastapi_app): |
| base = "" |
|
|
| async def do_summarize(platforms, keywords_csv, brand, limit, language): |
| keywords = [k.strip() for k in keywords_csv.split(",") if k.strip()] |
| async with httpx.AsyncClient() as client: |
| r = await client.post(f"{base}/api/summarize_trends", json={ |
| "platforms": platforms, "keywords": keywords, "brand": brand, |
| "limit": int(limit), "language": language |
| }) |
| r.raise_for_status() |
| data = r.json() |
| items = data["items"] |
| summary = data["summary"] |
| return json.dumps(items, ensure_ascii=False, indent=2), summary |
|
|
| async def do_generate_plan(brand, language, platforms, keywords_csv, start_date, tone, cta, image_style_hint): |
| keywords = [k.strip() for k in keywords_csv.split(",") if k.strip()] |
| async with httpx.AsyncClient() as client: |
| r = await client.post(f"{base}/api/generate_week_plan", json={ |
| "brand": brand, "language": language, "platforms": platforms, |
| "keywords": keywords, "start_date": (start_date or None), |
| "tone": tone, "cta": cta, "image_style_hint": image_style_hint |
| }) |
| r.raise_for_status() |
| posts = r.json() |
| return json.dumps(posts, ensure_ascii=False, indent=2) |
|
|
| async def do_list_calendar(): |
| async with httpx.AsyncClient() as client: |
| r = await client.get(f"{base}/api/calendar") |
| r.raise_for_status() |
| return json.dumps(r.json(), ensure_ascii=False, indent=2) |
|
|
| async def do_approve(post_id): |
| async with httpx.AsyncClient() as client: |
| r = await client.post(f"{base}/api/approve_post/{int(post_id)}") |
| r.raise_for_status() |
| return json.dumps(r.json(), ensure_ascii=False, indent=2) |
|
|
| async def do_schedule(post_id, iso): |
| async with httpx.AsyncClient() as client: |
| r = await client.post(f"{base}/api/schedule_post/{int(post_id)}", json={"scheduled_at": iso}) |
| r.raise_for_status() |
| return json.dumps(r.json(), ensure_ascii=False, indent=2) |
|
|
| async def save_keywords(keywords_csv): |
| keywords = [k.strip() for k in keywords_csv.split(",") if k.strip()] |
| async with httpx.AsyncClient() as client: |
| r = await client.post(f"{base}/api/keywords", json={"keywords": keywords}) |
| r.raise_for_status() |
| return "保存しました" |
|
|
| async def load_keywords(): |
| async with httpx.AsyncClient() as client: |
| r = await client.get(f"{base}/api/keywords") |
| r.raise_for_status() |
| data = r.json() |
| return ", ".join(data.get("keywords", [])) |
|
|
| with gr.Blocks(title="SNS運用AIライト") as demo: |
| gr.Markdown("## SNS運用AIライト — 競合/トレンド要約 → 1週間案 → 承認 → 予約投稿") |
|
|
| with gr.Tab("1) トレンド要約"): |
| platforms = gr.CheckboxGroup(choices=["x","instagram"], value=["x","instagram"], label="対象プラットフォーム") |
| keywords = gr.Textbox(label="監視キーワード(カンマ区切り)", placeholder="自社名, 競合名, 業界ワード") |
| brand = gr.Textbox(label="ブランド名(任意)", placeholder="HitC Inc. など") |
| limit = gr.Slider(5, 50, step=1, value=20, label="取得件数(疑似/本API対応)") |
| language = gr.Dropdown(["ja","en"], value="ja", label="出力言語") |
| btn = gr.Button("トレンド要約を実行") |
| items_json = gr.Code(label="取得結果(JSON)", language="json") |
| summary = gr.Textbox(label="要約", lines=12) |
| btn.click(do_summarize, [platforms, keywords, brand, limit, language], [items_json, summary]) |
|
|
| with gr.Tab("2) 1週間の投稿案生成"): |
| brand2 = gr.Textbox(label="ブランド名", placeholder="HitC Inc.") |
| language2 = gr.Dropdown(["ja","en"], value="ja", label="言語") |
| platforms2 = gr.CheckboxGroup(choices=["x","instagram"], value=["x","instagram"], label="プラットフォーム") |
| keywords2 = gr.Textbox(label="キーワード(任意/カンマ区切り)") |
| start_date = gr.Textbox(label="開始日(ISO, 任意)", placeholder="2025-09-01") |
| tone = gr.Textbox(label="トーン", value="プロフェッショナルで親しみやすい") |
| cta = gr.Textbox(label="CTA", value="詳細はこちら") |
| imgstyle = gr.Textbox(label="画像ラフのスタイルヒント", value="ミニマル、端的なタイポ、ブランドカラー意識") |
| btn2 = gr.Button("投稿案を生成 & DB保存") |
| posts_json = gr.Code(label="投稿案(DBにdraft保存)", language="json") |
| btn2.click(do_generate_plan, [brand2, language2, platforms2, keywords2, start_date, tone, cta, imgstyle], [posts_json]) |
|
|
| with gr.Tab("3) 承認・予約・カレンダー"): |
| gr.Markdown("承認→予約→公開(APScheduler)が動きます。") |
| post_id = gr.Number(label="Post ID") |
| approve_btn = gr.Button("承認する") |
| schedule_iso = gr.Textbox(label="予約日時(ISO, 例: 2025-09-01T09:00:00Z)") |
| schedule_btn = gr.Button("予約に登録") |
| out = gr.Code(label="レスポンス", language="json") |
| approve_btn.click(do_approve, [post_id], [out]) |
| schedule_btn.click(do_schedule, [post_id, schedule_iso], [out]) |
|
|
| cal_btn = gr.Button("カレンダー取得") |
| cal_json = gr.Code(label="カレンダー", language="json") |
| cal_btn.click(do_list_calendar, [], [cal_json]) |
|
|
| with gr.Tab("設定"): |
| kw_in = gr.Textbox(label="監視キーワード(カンマ区切り)") |
| load_btn = gr.Button("読み込み") |
| save_btn = gr.Button("保存") |
| msg = gr.Textbox(label="メッセージ") |
| load_btn.click(load_keywords, [], [kw_in]) |
| save_btn.click(save_keywords, [kw_in], [msg]) |
|
|
| return demo |
|
|