Corin1998 commited on
Commit
54aec3b
·
verified ·
1 Parent(s): 1834142

Update ui.py

Browse files
Files changed (1) hide show
  1. ui.py +104 -44
ui.py CHANGED
@@ -1,66 +1,126 @@
1
  import gradio as gr
2
- import httpx
3
  import json
 
 
 
 
4
 
5
  def build_ui(fastapi_app):
6
- base = "" # 同一プロセスなので相対パスでOK
7
-
8
  async def do_summarize(platforms, keywords_csv, brand, limit, language):
9
  keywords = [k.strip() for k in keywords_csv.split(",") if k.strip()]
10
- async with httpx.AsyncClient() as client:
11
- r = await client.post(f"{base}/api/summarize_trends", json={
12
- "platforms": platforms, "keywords": keywords, "brand": brand,
13
- "limit": int(limit), "language": language
14
- })
15
- r.raise_for_status()
16
- data = r.json()
17
- items = data["items"]
18
- summary = data["summary"]
19
  return json.dumps(items, ensure_ascii=False, indent=2), summary
20
 
21
  async def do_generate_plan(brand, language, platforms, keywords_csv, start_date, tone, cta, image_style_hint):
22
  keywords = [k.strip() for k in keywords_csv.split(",") if k.strip()]
23
- async with httpx.AsyncClient() as client:
24
- r = await client.post(f"{base}/api/generate_week_plan", json={
25
- "brand": brand, "language": language, "platforms": platforms,
26
- "keywords": keywords, "start_date": (start_date or None),
27
- "tone": tone, "cta": cta, "image_style_hint": image_style_hint
28
- })
29
- r.raise_for_status()
30
- posts = r.json()
31
- return json.dumps(posts, ensure_ascii=False, indent=2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
 
33
  async def do_list_calendar():
34
- async with httpx.AsyncClient() as client:
35
- r = await client.get(f"{base}/api/calendar")
36
- r.raise_for_status()
37
- return json.dumps(r.json(), ensure_ascii=False, indent=2)
 
 
 
 
 
 
 
 
 
 
38
 
39
  async def do_approve(post_id):
40
- async with httpx.AsyncClient() as client:
41
- r = await client.post(f"{base}/api/approve_post/{int(post_id)}")
42
- r.raise_for_status()
43
- return json.dumps(r.json(), ensure_ascii=False, indent=2)
 
 
 
 
 
 
 
 
 
44
 
45
  async def do_schedule(post_id, iso):
46
- async with httpx.AsyncClient() as client:
47
- r = await client.post(f"{base}/api/schedule_post/{int(post_id)}", json={"scheduled_at": iso})
48
- r.raise_for_status()
49
- return json.dumps(r.json(), ensure_ascii=False, indent=2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
 
51
  async def save_keywords(keywords_csv):
52
- keywords = [k.strip() for k in keywords_csv.split(",") if k.strip()]
53
- async with httpx.AsyncClient() as client:
54
- r = await client.post(f"{base}/api/keywords", json={"keywords": keywords})
55
- r.raise_for_status()
56
- return "保存しました"
 
 
 
 
 
57
 
58
  async def load_keywords():
59
- async with httpx.AsyncClient() as client:
60
- r = await client.get(f"{base}/api/keywords")
61
- r.raise_for_status()
62
- data = r.json()
63
- return ", ".join(data.get("keywords", []))
 
64
 
65
  with gr.Blocks(title="SNS運用AIライト") as demo:
66
  gr.Markdown("## SNS運用AIライト — 競合/トレンド要約 → 1週間案 → 承認 → 予約投稿")
@@ -93,7 +153,7 @@ def build_ui(fastapi_app):
93
  gr.Markdown("承認→予約→公開(APScheduler)が動きます。")
94
  post_id = gr.Number(label="Post ID")
95
  approve_btn = gr.Button("承認する")
96
- schedule_iso = gr.Textbox(label="予約日時(ISO, 例: 2025-09-01T09:00:00Z)")
97
  schedule_btn = gr.Button("予約に登録")
98
  out = gr.Code(label="レスポンス", language="json")
99
  approve_btn.click(do_approve, [post_id], [out])
 
1
  import gradio as gr
 
2
  import json
3
+ from db import SessionLocal, Post, Keyword
4
+ from services.llm import summarize_trends_llm, generate_week_plan_llm
5
+ from services.trend_monitor import fetch_trend_samples
6
+ from services.scheduler import schedule_post_job
7
 
8
  def build_ui(fastapi_app):
 
 
9
  async def do_summarize(platforms, keywords_csv, brand, limit, language):
10
  keywords = [k.strip() for k in keywords_csv.split(",") if k.strip()]
11
+ items = await fetch_trend_samples(platforms, keywords, int(limit))
12
+ summary = await summarize_trends_llm(items, brand, language)
 
 
 
 
 
 
 
13
  return json.dumps(items, ensure_ascii=False, indent=2), summary
14
 
15
  async def do_generate_plan(brand, language, platforms, keywords_csv, start_date, tone, cta, image_style_hint):
16
  keywords = [k.strip() for k in keywords_csv.split(",") if k.strip()]
17
+ posts = await generate_week_plan_llm(
18
+ brand=brand,
19
+ language=language,
20
+ platforms=platforms,
21
+ keywords=keywords,
22
+ start_date=(start_date or None),
23
+ tone=tone,
24
+ cta=cta,
25
+ image_style_hint=image_style_hint,
26
+ )
27
+ # DB保存
28
+ session = SessionLocal()
29
+ try:
30
+ out = []
31
+ for p in posts:
32
+ post = Post(
33
+ platform=p.platform,
34
+ scheduled_at=p.scheduled_at,
35
+ text=p.text,
36
+ image_prompt=p.image_prompt,
37
+ status="draft",
38
+ )
39
+ session.add(post)
40
+ session.flush()
41
+ out.append({
42
+ "id": post.id,
43
+ "platform": post.platform,
44
+ "scheduled_at": post.scheduled_at,
45
+ "text": post.text,
46
+ "image_prompt": post.image_prompt,
47
+ "status": post.status,
48
+ })
49
+ session.commit()
50
+ return json.dumps(out, ensure_ascii=False, indent=2)
51
+ finally:
52
+ session.close()
53
 
54
  async def do_list_calendar():
55
+ session = SessionLocal()
56
+ try:
57
+ posts = session.query(Post).order_by(Post.scheduled_at.asc().nulls_last()).all()
58
+ out = [{
59
+ "id": p.id,
60
+ "platform": p.platform,
61
+ "scheduled_at": p.scheduled_at,
62
+ "text": p.text,
63
+ "image_prompt": p.image_prompt,
64
+ "status": p.status,
65
+ } for p in posts]
66
+ return json.dumps({"events": out}, ensure_ascii=False, indent=2)
67
+ finally:
68
+ session.close()
69
 
70
  async def do_approve(post_id):
71
+ session = SessionLocal()
72
+ try:
73
+ post = session.get(Post, int(post_id))
74
+ if not post:
75
+ return json.dumps({"error": "post not found"}, ensure_ascii=False)
76
+ post.status = "approved"
77
+ session.commit()
78
+ return json.dumps({
79
+ "id": post.id, "platform": post.platform, "scheduled_at": post.scheduled_at,
80
+ "text": post.text, "image_prompt": post.image_prompt, "status": post.status
81
+ }, ensure_ascii=False, indent=2)
82
+ finally:
83
+ session.close()
84
 
85
  async def do_schedule(post_id, iso):
86
+ session = SessionLocal()
87
+ try:
88
+ post = session.get(Post, int(post_id))
89
+ if not post:
90
+ return json.dumps({"error": "post not found"}, ensure_ascii=False)
91
+ if post.status != "approved":
92
+ return json.dumps({"error": "post must be approved before scheduling"}, ensure_ascii=False)
93
+ post.scheduled_at = iso
94
+ post.status = "scheduled"
95
+ session.commit()
96
+ # 予約ジョブ登録
97
+ schedule_post_job(post.id, post.platform, post.text, post.image_prompt, post.scheduled_at)
98
+ return json.dumps({
99
+ "id": post.id, "platform": post.platform, "scheduled_at": post.scheduled_at,
100
+ "text": post.text, "image_prompt": post.image_prompt, "status": post.status
101
+ }, ensure_ascii=False, indent=2)
102
+ finally:
103
+ session.close()
104
 
105
  async def save_keywords(keywords_csv):
106
+ kws = [k.strip() for k in keywords_csv.split(",") if k.strip()]
107
+ session = SessionLocal()
108
+ try:
109
+ session.query(Keyword).delete()
110
+ for kw in kws:
111
+ session.add(Keyword(text=kw))
112
+ session.commit()
113
+ return "保存しました"
114
+ finally:
115
+ session.close()
116
 
117
  async def load_keywords():
118
+ session = SessionLocal()
119
+ try:
120
+ kws = [k.text for k in session.query(Keyword).all()]
121
+ return ", ".join(kws)
122
+ finally:
123
+ session.close()
124
 
125
  with gr.Blocks(title="SNS運用AIライト") as demo:
126
  gr.Markdown("## SNS運用AIライト — 競合/トレンド要約 → 1週間案 → 承認 → 予約投稿")
 
153
  gr.Markdown("承認→予約→公開(APScheduler)が動きます。")
154
  post_id = gr.Number(label="Post ID")
155
  approve_btn = gr.Button("承認する")
156
+ schedule_iso = gr.Textbox(label="予約日時(ISO, 例: 2025-09-01T09:00:00Z または +09:00)")
157
  schedule_btn = gr.Button("予約に登録")
158
  out = gr.Code(label="レスポンス", language="json")
159
  approve_btn.click(do_approve, [post_id], [out])