Corin1998 commited on
Commit
c0f7869
·
verified ·
1 Parent(s): 55288af

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +100 -60
app.py CHANGED
@@ -1,4 +1,4 @@
1
- import os, json, traceback
2
  from typing import List
3
  from fastapi import FastAPI, Request, HTTPException
4
  from fastapi.middleware.cors import CORSMiddleware
@@ -8,13 +8,20 @@ from dotenv import load_dotenv
8
 
9
  load_dotenv()
10
 
11
- # --- 例外を画面にも表示(デバッグ用。不要になれば削除OK) ---
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,7 +30,7 @@ def _lazy_imports_for_main():
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,
@@ -33,8 +40,11 @@ def ui_company_score_and_proposal(company_name: 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:
37
- return "### ❌ 初期化エラー\n```\n" + traceback.format_exc() + "\n```"
 
 
38
 
39
  urls = [u.strip() for u in (urls_text or "").splitlines() if u.strip()]
40
  file_paths = [f.name for f in (files or [])]
@@ -42,8 +52,11 @@ def ui_company_score_and_proposal(company_name: str,
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:
@@ -54,62 +67,89 @@ def ui_company_score_and_proposal(company_name: str,
54
  objective=custom_objective,
55
  temperature=temperature
56
  )
 
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="生成温度")
97
- run_btn = gr.Button("ワークフロー実行", variant="primary")
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(/ = UI、/ui も / へ転送、/t と /health はAPI) ---
 
 
 
 
 
 
 
 
 
113
  app = FastAPI(title="Agent Studio - Docker (root UI)")
114
  app.add_middleware(
115
  CORSMiddleware,
@@ -121,12 +161,11 @@ app.add_exception_handler(Exception, _exception_printer)
121
  def health():
122
  return {"ok": True}
123
 
124
- # /ui に来た人も UI(/)へ転送しておく
125
  @app.get("/ui")
126
  def old_ui():
 
127
  return RedirectResponse(url="/")
128
 
129
- # クリック計測
130
  @app.get("/t/{token}")
131
  def track_click(token: str, request: Request):
132
  try:
@@ -141,7 +180,8 @@ def track_click(token: str, request: Request):
141
  return RedirectResponse(url=redirect_to)
142
  except Exception as e:
143
  tb = "".join(traceback.format_exception(type(e), e, e.__traceback__))
 
144
  return PlainTextResponse(f"tracking error\n\n{tb}", status_code=500)
145
 
146
- # ルート(/)で Gradio を表示
147
  app = gr.mount_gradio_app(app, demo, path="/")
 
1
+ import os, json, traceback, io
2
  from typing import List
3
  from fastapi import FastAPI, Request, HTTPException
4
  from fastapi.middleware.cors import CORSMiddleware
 
8
 
9
  load_dotenv()
10
 
11
+ # ========= 内部ログ用バッファ(画面で見られるようにする) =========
12
+ _APP_LOG = io.StringIO()
13
+
14
+ def _log(msg: str):
15
+ print(msg, flush=True)
16
+ _APP_LOG.write(msg + "\n")
17
+
18
+ # ========= 例外は必ず画面にも表示(Internal Server Error対策) =========
19
+ async def _exception_printer(request: Request, exc: Exception):
20
  tb = "".join(traceback.format_exception(type(exc), exc, exc.__traceback__))
21
+ _log("=== Unhandled Exception ===\n" + tb)
22
  return PlainTextResponse(f"Internal error\n\n{tb}", status_code=500)
23
 
24
+ # ========= 重い依存は遅延インポート =========
25
  def _lazy_imports_for_main():
26
  from modules.utils import ensure_dirs
27
  ensure_dirs()
 
30
  from modules.emailer import build_tracking_url
31
  return index_files_and_urls, run_full_workflow, build_tracking_url
32
 
33
+ # ========= Gradio コールバック =========
34
  def ui_company_score_and_proposal(company_name: str,
35
  company_website: str,
36
  lead_email: str,
 
40
  temperature: float = 0.4):
41
  try:
42
  index_files_and_urls, run_full_workflow, build_tracking_url = _lazy_imports_for_main()
43
+ _log("[init] lazy imports loaded")
44
  except Exception:
45
+ tb = traceback.format_exc()
46
+ _log("[error] init failed\n" + tb)
47
+ return "### ❌ 初期化エラー\n```\n" + tb + "\n```"
48
 
49
  urls = [u.strip() for u in (urls_text or "").splitlines() if u.strip()]
50
  file_paths = [f.name for f in (files or [])]
 
52
  # 1) インデックス
53
  try:
54
  index_report = index_files_and_urls(file_paths=file_paths, urls=urls)
55
+ _log(f"[index] {index_report}")
56
  except Exception:
57
+ tb = traceback.format_exc()
58
+ _log("[error] index failed\n" + tb)
59
+ index_report = "Index error:\n```\n" + tb + "\n```"
60
 
61
  # 2) ワークフロー
62
  try:
 
67
  objective=custom_objective,
68
  temperature=temperature
69
  )
70
+ _log("[workflow] finished")
71
  except Exception:
72
+ tb = traceback.format_exc()
73
+ _log("[error] workflow failed\n" + tb)
74
+ return "### ❌ ワークフロー実行エラー\n```\n" + tb + "\n```"
75
 
76
  # 3) 表示
77
  outputs = []
78
+ try:
79
+ outputs.append("### 企業スコア\n" + json.dumps(result.get("score", {}), ensure_ascii=False, indent=2))
80
+ ctxs = result.get("top_contexts", [])
81
+ outputs.append("### 🧠 抽出コンテキスト(上位)\n" + "\n\n".join([f"- {c[:300]}..." for c in ctxs]))
82
+ outputs.append("### ✍️ 提案ドラフト\n" + result.get("proposal_markdown", ""))
83
+
84
+ ex = result.get("exports", {})
85
+ outputs.append("### 📎 エクスポート\n" + "\n".join([
86
+ f"- DOCX: {ex.get('docx_path','')}",
87
+ f"- PPTX: {ex.get('pptx_path','')}"
88
+ ]))
89
+
90
+ if lead_email:
91
+ email = result.get("email", {})
92
+ outputs.append("### ✉️ メール準備\n" + f"To: {lead_email}\nSubject: {email.get('subject','')}\n\n{email.get('body','')}")
93
+ try:
94
+ outputs.append(f"(本文内の計測リンク例)\n{build_tracking_url('preview-only', {'company':company_name})}")
95
+ except Exception:
96
+ pass
97
+
98
+ outputs.append("### 🤖 次アクション提案\n" + result.get("next_actions", ""))
99
+ outputs.append("### 🧩 インデックス更新ログ\n" + index_report)
100
+ except Exception:
101
+ tb = traceback.format_exc()
102
+ _log("[error] render failed\n" + tb)
103
+ outputs.append("### ⚠️ 出力整形エラー\n```\n" + tb + "\n```")
104
+
105
  return "\n\n".join(outputs)
106
 
107
+ def get_health_text():
108
+ return "OK"
109
+
110
+ def get_runtime_log():
111
+ try:
112
+ return "```\n" + _APP_LOG.getvalue() + "\n```"
113
+ except Exception:
114
+ return "(ログを取得できませんでした)"
115
+
116
+ # ========= Gradio UI(ルート / に表示) =========
117
  with gr.Blocks(title="営業自動化 Agent Studio") as demo:
118
+ gr.Markdown("## 営業自動化 Agent Studio(Space内で完結)")
119
+
120
+ with gr.Tab("アプリ"):
121
+ with gr.Row():
122
+ with gr.Column():
123
+ company_name = gr.Textbox(label="企業名")
124
+ company_website = gr.Textbox(label="企業サイトURL")
125
+ lead_email = gr.Textbox(label="送信先メール(任意)")
126
+ custom_objective = gr.Textbox(label="提案の目的/狙い(任意)", placeholder="例)SaaS導入の無料PoC打診")
127
+ urls_text = gr.Textbox(label="RAG用URL(複数は改行)", lines=4)
128
+ files = gr.File(label="RAG用ファイル(複数可)", file_count="multiple")
129
+ temperature = gr.Slider(0.0, 1.0, value=0.4, step=0.05, label="生成温度")
130
+ run_btn = gr.Button("ワークフロー実行", variant="primary")
131
+ ping_btn = gr.Button("Ping(疎通)")
132
+ with gr.Column():
133
+ out = gr.Markdown()
134
+ ping_out = gr.Markdown()
135
+
136
+ run_btn.click(
137
+ fn=ui_company_score_and_proposal,
138
+ inputs=[company_name, company_website, lead_email, urls_text, files, custom_objective, temperature],
139
+ outputs=[out]
140
+ )
141
+ ping_btn.click(lambda: "pong 🎯", None, ping_out)
142
+
143
+ with gr.Tab("ステータス / ログ"):
144
+ health_btn = gr.Button("ヘルスチェック")
145
+ health_out = gr.Markdown()
146
+ log_btn = gr.Button("アプリログを表示")
147
+ log_out = gr.Markdown(value="(ここに実行ログが表示されます)")
148
+
149
+ health_btn.click(fn=get_health_text, inputs=None, outputs=health_out)
150
+ log_btn.click(fn=get_runtime_log, inputs=None, outputs=log_out)
151
+
152
+ # ========= FastAPI(/ はUI、/t と /health はAPI。/ui に来た人は / へ転送) =========
153
  app = FastAPI(title="Agent Studio - Docker (root UI)")
154
  app.add_middleware(
155
  CORSMiddleware,
 
161
  def health():
162
  return {"ok": True}
163
 
 
164
  @app.get("/ui")
165
  def old_ui():
166
+ # 旧リンクで来た場合も Space 内で完結して同じページを表示
167
  return RedirectResponse(url="/")
168
 
 
169
  @app.get("/t/{token}")
170
  def track_click(token: str, request: Request):
171
  try:
 
180
  return RedirectResponse(url=redirect_to)
181
  except Exception as e:
182
  tb = "".join(traceback.format_exception(type(e), e, e.__traceback__))
183
+ _log("[error] tracking failed\n" + tb)
184
  return PlainTextResponse(f"tracking error\n\n{tb}", status_code=500)
185
 
186
+ # ルート(/)で Gradio を表示(Space内完結)
187
  app = gr.mount_gradio_app(app, demo, path="/")