Corin1998 commited on
Commit
727d601
·
verified ·
1 Parent(s): 538a15d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +42 -51
app.py CHANGED
@@ -1,25 +1,20 @@
1
  import os, json, traceback
2
  from typing import List
3
- from fastapi import FastAPI, Request
4
  from fastapi.middleware.cors import CORSMiddleware
5
- from fastapi.responses import JSONResponse, PlainTextResponse, RedirectResponse
6
  import gradio as gr
7
  from dotenv import load_dotenv
8
 
9
  load_dotenv()
10
 
11
- # ========= 例外を必ず可視化するハンドラ =========
12
- async def _exception_printer(request: Request, exc: Exception):
13
  tb = "".join(traceback.format_exception(type(exc), exc, exc.__traceback__))
14
  print("=== Unhandled Exception ===\n", tb, flush=True)
15
- # 画面にも出す(暫定)
16
  return PlainTextResponse(f"Internal error\n\n{tb}", status_code=500)
17
 
18
- # ========= 疎通テスト用の最小関数 =========
19
- def ping():
20
- return "pong 🎯"
21
-
22
- # ========= 重い依存はボタン押下まで遅延 =========
23
  def _lazy_imports_for_main():
24
  from modules.utils import ensure_dirs
25
  ensure_dirs()
@@ -28,13 +23,14 @@ def _lazy_imports_for_main():
28
  from modules.emailer import build_tracking_url
29
  return index_files_and_urls, run_full_workflow, build_tracking_url
30
 
31
- def ui_main(company_name: str,
32
- company_website: str,
33
- lead_email: str,
34
- urls_text: str,
35
- files: List[gr.File] | None,
36
- custom_objective: str,
37
- temperature: float = 0.4):
 
38
  try:
39
  index_files_and_urls, run_full_workflow, build_tracking_url = _lazy_imports_for_main()
40
  except Exception:
@@ -43,11 +39,13 @@ def ui_main(company_name: str,
43
  urls = [u.strip() for u in (urls_text or "").splitlines() if u.strip()]
44
  file_paths = [f.name for f in (files or [])]
45
 
 
46
  try:
47
- idx = index_files_and_urls(file_paths=file_paths, urls=urls)
48
  except Exception:
49
- idx = "Index error:\n```\n" + traceback.format_exc() + "\n```"
50
 
 
51
  try:
52
  result = run_full_workflow(
53
  company_name=company_name,
@@ -59,40 +57,40 @@ def ui_main(company_name: str,
59
  except Exception:
60
  return "### ❌ ワークフロー実行エラー\n```\n" + traceback.format_exc() + "\n```"
61
 
62
- out = []
63
- out.append("### ✅ 企業スコア\n" + json.dumps(result.get("score", {}), ensure_ascii=False, indent=2))
 
64
  ctxs = result.get("top_contexts", [])
65
- out.append("### 🧠 抽出コンテキスト(上位)\n" + "\n\n".join([f"- {c[:300]}..." for c in ctxs]))
66
- out.append("### ✍️ 提案ドラフト\n" + result.get("proposal_markdown", ""))
67
 
68
  ex = result.get("exports", {})
69
- out.append("### 📎 エクスポート\n" + "\n".join([
70
  f"- DOCX: {ex.get('docx_path','')}",
71
  f"- PPTX: {ex.get('pptx_path','')}"
72
  ]))
73
 
74
  if lead_email:
75
  email = result.get("email", {})
76
- out.append("### ✉️ メール準備\n" + f"To: {lead_email}\nSubject: {email.get('subject','')}\n\n{email.get('body','')}")
77
  try:
78
- from modules.emailer import build_tracking_url
79
- out.append(f"(本文内の計測リンク例)\n{build_tracking_url('preview-only', {'company':company_name})}")
80
  except Exception:
81
  pass
82
 
83
- out.append("### 🤖 次アクション提案\n" + result.get("next_actions", ""))
84
- out.append("### 🧩 インデックス更新ログ\n" + idx)
85
- return "\n\n".join(out)
86
 
87
- # ========= Gradio(/ui にマウント) =========
88
  with gr.Blocks(title="営業自動化 Agent Studio") as demo:
89
- gr.Markdown("# 営業自動化 Agent Studio")
90
  with gr.Row():
91
  with gr.Column():
92
  company_name = gr.Textbox(label="企業名")
93
  company_website = gr.Textbox(label="企業サイトURL")
94
  lead_email = gr.Textbox(label="送信先メール(任意)")
95
- custom_objective = gr.Textbox(label="提案の目的/狙い(任意)")
96
  urls_text = gr.Textbox(label="RAG用URL(複数は改行)", lines=4)
97
  files = gr.File(label="RAG用ファイル(複数可)", file_count="multiple")
98
  temperature = gr.Slider(0.0, 1.0, value=0.4, step=0.05, label="生成温度")
@@ -100,51 +98,44 @@ with gr.Blocks(title="営業自動化 Agent Studio") as demo:
100
  with gr.Column():
101
  out = gr.Markdown()
102
 
 
103
  ping_btn = gr.Button("Ping")
104
- ping_out = gr.Markdown("Click Ping")
105
- ping_btn.click(fn=ping, inputs=None, outputs=ping_out)
106
 
107
  run_btn.click(
108
- fn=ui_main,
109
  inputs=[company_name, company_website, lead_email, urls_text, files, custom_objective, temperature],
110
  outputs=[out]
111
  )
112
 
113
- # ========= FastAPI(/ と /health は軽量、/ui Gradio =========
114
- app = FastAPI(title="Agent Studio - Docker (safe)")
115
  app.add_middleware(
116
  CORSMiddleware,
117
  allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"],
118
  )
119
-
120
- # 全例外をキャッチして本文にトレースを返す(暫定)
121
  app.add_exception_handler(Exception, _exception_printer)
122
 
123
  @app.get("/health")
124
  def health():
125
  return {"ok": True}
126
 
127
- @app.get("/")
128
- def root():
129
- # まずは JSON を返し、UI は /ui に配置
130
- return {"status": "running", "ui": "/ui", "health": "/health"}
131
-
132
- # クリック計測(例外も可視化)
133
  @app.get("/t/{token}")
134
  def track_click(token: str, request: Request):
135
  try:
136
  from modules.utils import verify_tracking_token, log_event
137
  payload = verify_tracking_token(token)
138
- if not payload:
139
- return JSONResponse({"error": "invalid token"}, status_code=400)
140
  ip = request.client.host if request.client else "unknown"
141
  ua = request.headers.get("User-Agent", "") if request.headers else ""
142
  log_event("click", payload, {"ip": ip, "ua": ua})
143
- redirect_to = payload.get("redirect") or os.getenv("PUBLIC_BASE_URL", "/ui")
144
  return RedirectResponse(url=redirect_to)
145
  except Exception as e:
146
  tb = "".join(traceback.format_exception(type(e), e, e.__traceback__))
147
  return PlainTextResponse(f"tracking error\n\n{tb}", status_code=500)
148
 
149
- # /ui Gradio をマウント
150
- app = gr.mount_gradio_app(app, demo, path="/ui")
 
1
  import os, json, traceback
2
  from typing import List
3
+ from fastapi import FastAPI, Request, HTTPException
4
  from fastapi.middleware.cors import CORSMiddleware
5
+ from fastapi.responses import RedirectResponse, PlainTextResponse
6
  import gradio as gr
7
  from dotenv import load_dotenv
8
 
9
  load_dotenv()
10
 
11
+ # --- 例外を画面にも出す(復旧後に不要なら削除可) ---
12
+ async def _exception_printer(request, exc: Exception):
13
  tb = "".join(traceback.format_exception(type(exc), exc, exc.__traceback__))
14
  print("=== Unhandled Exception ===\n", tb, flush=True)
 
15
  return PlainTextResponse(f"Internal error\n\n{tb}", status_code=500)
16
 
17
+ # --- 起動安定化のため重い依存は遅延 import ---
 
 
 
 
18
  def _lazy_imports_for_main():
19
  from modules.utils import ensure_dirs
20
  ensure_dirs()
 
23
  from modules.emailer import build_tracking_url
24
  return index_files_and_urls, run_full_workflow, build_tracking_url
25
 
26
+ # --- Gradio ハンドラ ---
27
+ def ui_company_score_and_proposal(company_name: str,
28
+ company_website: str,
29
+ lead_email: str,
30
+ urls_text: str,
31
+ files: List[gr.File] | None,
32
+ custom_objective: str,
33
+ temperature: float = 0.4):
34
  try:
35
  index_files_and_urls, run_full_workflow, build_tracking_url = _lazy_imports_for_main()
36
  except Exception:
 
39
  urls = [u.strip() for u in (urls_text or "").splitlines() if u.strip()]
40
  file_paths = [f.name for f in (files or [])]
41
 
42
+ # 1) インデックス
43
  try:
44
+ index_report = index_files_and_urls(file_paths=file_paths, urls=urls)
45
  except Exception:
46
+ index_report = "Index error:\n```\n" + traceback.format_exc() + "\n```"
47
 
48
+ # 2) ワークフロー
49
  try:
50
  result = run_full_workflow(
51
  company_name=company_name,
 
57
  except Exception:
58
  return "### ❌ ワークフロー実行エラー\n```\n" + traceback.format_exc() + "\n```"
59
 
60
+ # 3) 表示
61
+ outputs = []
62
+ outputs.append("### ✅ 企業スコア\n" + json.dumps(result.get("score", {}), ensure_ascii=False, indent=2))
63
  ctxs = result.get("top_contexts", [])
64
+ outputs.append("### 🧠 抽出コンテキスト(上位)\n" + "\n\n".join([f"- {c[:300]}..." for c in ctxs]))
65
+ outputs.append("### ✍️ 提案ドラフト\n" + result.get("proposal_markdown", ""))
66
 
67
  ex = result.get("exports", {})
68
+ outputs.append("### 📎 エクスポート\n" + "\n".join([
69
  f"- DOCX: {ex.get('docx_path','')}",
70
  f"- PPTX: {ex.get('pptx_path','')}"
71
  ]))
72
 
73
  if lead_email:
74
  email = result.get("email", {})
75
+ outputs.append("### ✉️ メール準備\n" + f"To: {lead_email}\nSubject: {email.get('subject','')}\n\n{email.get('body','')}")
76
  try:
77
+ outputs.append(f"(本文内の計測リンク例)\n{build_tracking_url('preview-only', {'company':company_name})}")
 
78
  except Exception:
79
  pass
80
 
81
+ outputs.append("### 🤖 次アクション提案\n" + result.get("next_actions", ""))
82
+ outputs.append("### 🧩 インデックス更新ログ\n" + index_report)
83
+ return "\n\n".join(outputs)
84
 
85
+ # --- Gradio UI(ルート / に出す) ---
86
  with gr.Blocks(title="営業自動化 Agent Studio") as demo:
87
+ gr.Markdown("# 営業自動化 Agent Studio(Hugging Face 完結)")
88
  with gr.Row():
89
  with gr.Column():
90
  company_name = gr.Textbox(label="企業名")
91
  company_website = gr.Textbox(label="企業サイトURL")
92
  lead_email = gr.Textbox(label="送信先メール(任意)")
93
+ custom_objective = gr.Textbox(label="提案の目的/狙い(任意)", placeholder="例)SaaS導入の無料PoC打診")
94
  urls_text = gr.Textbox(label="RAG用URL(複数は改行)", lines=4)
95
  files = gr.File(label="RAG用ファイル(複数可)", file_count="multiple")
96
  temperature = gr.Slider(0.0, 1.0, value=0.4, step=0.05, label="生成温度")
 
98
  with gr.Column():
99
  out = gr.Markdown()
100
 
101
+ # 疎通確認
102
  ping_btn = gr.Button("Ping")
103
+ ping_out = gr.Markdown()
104
+ ping_btn.click(lambda: "pong 🎯", None, ping_out)
105
 
106
  run_btn.click(
107
+ fn=ui_company_score_and_proposal,
108
  inputs=[company_name, company_website, lead_email, urls_text, files, custom_objective, temperature],
109
  outputs=[out]
110
  )
111
 
112
+ # --- FastAPI(/health と /t/{token})+ ルートに Gradio をマウント ---
113
+ app = FastAPI(title="Agent Studio - Docker")
114
  app.add_middleware(
115
  CORSMiddleware,
116
  allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"],
117
  )
 
 
118
  app.add_exception_handler(Exception, _exception_printer)
119
 
120
  @app.get("/health")
121
  def health():
122
  return {"ok": True}
123
 
 
 
 
 
 
 
124
  @app.get("/t/{token}")
125
  def track_click(token: str, request: Request):
126
  try:
127
  from modules.utils import verify_tracking_token, log_event
128
  payload = verify_tracking_token(token)
129
+ if payload is None:
130
+ raise HTTPException(status_code=400, detail="invalid token")
131
  ip = request.client.host if request.client else "unknown"
132
  ua = request.headers.get("User-Agent", "") if request.headers else ""
133
  log_event("click", payload, {"ip": ip, "ua": ua})
134
+ redirect_to = payload.get("redirect") or os.getenv("PUBLIC_BASE_URL", "/")
135
  return RedirectResponse(url=redirect_to)
136
  except Exception as e:
137
  tb = "".join(traceback.format_exception(type(e), e, e.__traceback__))
138
  return PlainTextResponse(f"tracking error\n\n{tb}", status_code=500)
139
 
140
+ # ルート(/)で Gradio を表示
141
+ app = gr.mount_gradio_app(app, demo, path="/")