Corin1998 commited on
Commit
9364bd4
·
verified ·
1 Parent(s): e8cc220

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +60 -25
app.py CHANGED
@@ -2,9 +2,10 @@ import os
2
  import json
3
  import gradio as gr
4
  from fastapi import FastAPI
 
5
 
6
 
7
- # ---- 遅延インポート(起動高速化 & 依存衝突を回避) ----
8
  def _lazy_imports_for_main():
9
  from modules.utils import ensure_dirs # noqa: F401
10
  from modules.rag_indexer import index_files_and_urls
@@ -14,6 +15,36 @@ def _lazy_imports_for_main():
14
  return index_files_and_urls, run_full_workflow
15
 
16
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  # ---- UI コールバック ----
18
  def ui_company_score_and_proposal(
19
  company_name,
@@ -21,32 +52,33 @@ def ui_company_score_and_proposal(
21
  lead_email,
22
  objective,
23
  urls_text,
24
- files, # gr.File(file_count="multiple")
25
  ):
26
  """
27
  戻り値順:
28
  score_json(str), contexts_text(str), proposal_text(str),
29
- docx_path(str), pptx_path(str), next_actions(str), index_report(str)
30
  """
31
  index_files_and_urls, run_full_workflow = _lazy_imports_for_main()
32
 
33
- # URL & ファイル
34
  urls = [u.strip() for u in (urls_text or "").splitlines() if u.strip()]
35
  file_paths = []
36
  if files:
 
37
  if isinstance(files, list):
38
- file_paths = [getattr(f, "name", None) or f for f in files if f]
39
  else:
40
- file_paths = [getattr(files, "name", None) or files]
41
  file_paths = [p for p in file_paths if p]
42
 
43
- # インデックス(失敗しても先へ進む
44
  try:
45
  index_report = index_files_and_urls(file_paths=file_paths, urls=urls)
46
  except Exception as e:
47
  index_report = f"Index error:\n\n{e}"
48
 
49
- # メイン処理
50
  result = run_full_workflow(
51
  company_name=company_name or "(未入力)",
52
  company_website=company_website or "",
@@ -60,24 +92,26 @@ def ui_company_score_and_proposal(
60
  proposal_text = result.get("proposal_markdown", "")
61
  next_actions = result.get("next_actions", "")
62
 
63
- # 出力ファイル(/tmp下を想定
64
  docx_path = result.get("exports", {}).get("docx_path", "")
65
  pptx_path = result.get("exports", {}).get("pptx_path", "")
 
 
66
 
67
  return (
68
  score_json,
69
  contexts_text,
70
  proposal_text,
71
- docx_path,
72
- pptx_path,
73
  next_actions,
74
  index_report,
75
  )
76
 
77
 
78
- # ---- Gradio UI ----
79
- with gr.Blocks(title="営業自動化 Agent Studio", theme=gr.themes.Soft()) as demo:
80
- gr.Markdown("## 営業自動化 Agent Studio(Space内完結・ダウンロード)")
81
 
82
  with gr.Row():
83
  with gr.Column():
@@ -91,36 +125,37 @@ with gr.Blocks(title="営業自動化 Agent Studio", theme=gr.themes.Soft()) as
91
  lines=4,
92
  placeholder="https://example.com\nhttps://example.com/blog/post1",
93
  )
94
- # Files なく File(multiple) を使用(スキーマを単純化)
95
- files = gr.File(label="インデックス対象ファイル(任意・テキスト/MD推奨)", file_count="multiple")
96
 
97
  run_btn = gr.Button("ワークフロー実行", variant="primary")
98
 
99
  with gr.Column():
100
- # Code/Markdown ではなく Textbox に統一してスキーマ安定化
101
  score_json = gr.Textbox(label="✅ 企業スコア(JSON)", lines=10, interactive=False)
102
  contexts_text = gr.Textbox(label="🧠 抽出コンテキスト(上位)", lines=8, interactive=False)
103
  proposal_text = gr.Textbox(label="✍️ 提案ドラフト(Markdownテキスト)", lines=16)
104
 
105
- with gr.Row():
106
- # 出力は安定の gr.File(パスを返せばダウンロード可能)
107
- docx_file = gr.File(label="DOCX ダウンロード")
108
- pptx_file = gr.File(label="PPTX ダウンロード")
109
 
110
  next_actions = gr.Textbox(label="🤖 次アクション提案", lines=4, interactive=False)
111
  index_report = gr.Textbox(label="🧩 インデックス更新ログ", lines=4, interactive=False)
112
 
113
  run_btn.click(
114
  fn=ui_company_score_and_proposal,
115
- inputs=[company_name, company_website, lead_email, objective, urls_text, files],
116
- outputs=[score_json, contexts_text, proposal_text, docx_file, pptx_file, next_actions, index_report],
117
  )
118
 
119
- # ---- FastAPI にマウント(Spaces は uvicorn app:app で起動)----
 
120
  app = FastAPI()
 
 
 
121
  app = gr.mount_gradio_app(app, demo.queue(), path="/")
122
 
123
  if __name__ == "__main__":
124
  import uvicorn
125
-
126
  uvicorn.run(app, host="0.0.0.0", port=int(os.getenv("PORT", "7860")))
 
2
  import json
3
  import gradio as gr
4
  from fastapi import FastAPI
5
+ from starlette.staticfiles import StaticFiles
6
 
7
 
8
+ # ---- 遅延インポート ----
9
  def _lazy_imports_for_main():
10
  from modules.utils import ensure_dirs # noqa: F401
11
  from modules.rag_indexer import index_files_and_urls
 
15
  return index_files_and_urls, run_full_workflow
16
 
17
 
18
+ # ---- ユーティリティ ----
19
+ EXPORT_DIR = "/tmp/agent_studio/exports"
20
+ os.makedirs(EXPORT_DIR, exist_ok=True) # 静的配信用に事前作成
21
+
22
+ def _link_or_note(path_str):
23
+ """
24
+ 生成されたファイルパスから /files の相対URLを返す。
25
+ 存在しなければ理由を文字列で返す。
26
+ """
27
+ if not path_str:
28
+ return "(まだ生成されていません)"
29
+ fname = os.path.basename(path_str)
30
+ full = os.path.join(EXPORT_DIR, fname)
31
+ if os.path.exists(full):
32
+ # Hugging Face Space 上では相対リンクでOK
33
+ return f"/files/{fname}"
34
+ # modules 側が別ディレクトリで作った場合もあるので存在チェック
35
+ if os.path.exists(path_str):
36
+ # もし別パスにあるなら公開用にコピーしてリンク化
37
+ try:
38
+ import shutil
39
+ dst = os.path.join(EXPORT_DIR, os.path.basename(path_str))
40
+ if path_str != dst:
41
+ shutil.copy2(path_str, dst)
42
+ return f"/files/{os.path.basename(path_str)}"
43
+ except Exception as e:
44
+ return f"(生成済みだが公開に失敗: {e})"
45
+ return "(パスが無効です)"
46
+
47
+
48
  # ---- UI コールバック ----
49
  def ui_company_score_and_proposal(
50
  company_name,
 
52
  lead_email,
53
  objective,
54
  urls_text,
55
+ files, # gr.File(multiple=True) は使わないが、値は受ける
56
  ):
57
  """
58
  戻り値順:
59
  score_json(str), contexts_text(str), proposal_text(str),
60
+ docx_link(str), pptx_link(str), next_actions(str), index_report(str)
61
  """
62
  index_files_and_urls, run_full_workflow = _lazy_imports_for_main()
63
 
64
+ # URL & ファイルパス抽出(SpaceのUI都合で来ることがあるため防御的に扱う)
65
  urls = [u.strip() for u in (urls_text or "").splitlines() if u.strip()]
66
  file_paths = []
67
  if files:
68
+ # ここには通常来ないが、互換のため残す(path or tempfileオブジェクト)
69
  if isinstance(files, list):
70
+ file_paths = [getattr(f, "name", None) or str(f) for f in files if f]
71
  else:
72
+ file_paths = [getattr(files, "name", None) or str(files)]
73
  file_paths = [p for p in file_paths if p]
74
 
75
+ # インデックス更新(失敗しても継続
76
  try:
77
  index_report = index_files_and_urls(file_paths=file_paths, urls=urls)
78
  except Exception as e:
79
  index_report = f"Index error:\n\n{e}"
80
 
81
+ # メイン処理(提案ドラフトなど)
82
  result = run_full_workflow(
83
  company_name=company_name or "(未入力)",
84
  company_website=company_website or "",
 
92
  proposal_text = result.get("proposal_markdown", "")
93
  next_actions = result.get("next_actions", "")
94
 
95
+ # 生成物を /files 信できる相対リンクに変換(テキストで返す
96
  docx_path = result.get("exports", {}).get("docx_path", "")
97
  pptx_path = result.get("exports", {}).get("pptx_path", "")
98
+ docx_link = _link_or_note(docx_path)
99
+ pptx_link = _link_or_note(pptx_path)
100
 
101
  return (
102
  score_json,
103
  contexts_text,
104
  proposal_text,
105
+ docx_link,
106
+ pptx_link,
107
  next_actions,
108
  index_report,
109
  )
110
 
111
 
112
+ # ---- Gradio UI(すべて Textbox / Button のみ)----
113
+ with gr.Blocks(title="営業自動化 Agent Studio", analytics_enabled=False, theme=gr.themes.Soft()) as demo:
114
+ gr.Markdown("## 営業自動化 Agent Studio(Space内完結・リンクでダウンロード)")
115
 
116
  with gr.Row():
117
  with gr.Column():
 
125
  lines=4,
126
  placeholder="https://example.com\nhttps://example.com/blog/post1",
127
  )
128
+ # NOTICE: ファイル型コンポーネントはスキーマ問題回避のため配置しない
129
+ dummy_files = gr.Textbox(visible=False) # 互換のためダミー
130
 
131
  run_btn = gr.Button("ワークフロー実行", variant="primary")
132
 
133
  with gr.Column():
 
134
  score_json = gr.Textbox(label="✅ 企業スコア(JSON)", lines=10, interactive=False)
135
  contexts_text = gr.Textbox(label="🧠 抽出コンテキスト(上位)", lines=8, interactive=False)
136
  proposal_text = gr.Textbox(label="✍️ 提案ドラフト(Markdownテキスト)", lines=16)
137
 
138
+ # ここはテキストでリンクを表示(/files/xxx)
139
+ docx_link = gr.Textbox(label="📎 DOCX ダウンロードリンク", interactive=False)
140
+ pptx_link = gr.Textbox(label="📎 PPTX ダウンロードリンク", interactive=False)
 
141
 
142
  next_actions = gr.Textbox(label="🤖 次アクション提案", lines=4, interactive=False)
143
  index_report = gr.Textbox(label="🧩 インデックス更新ログ", lines=4, interactive=False)
144
 
145
  run_btn.click(
146
  fn=ui_company_score_and_proposal,
147
+ inputs=[company_name, company_website, lead_email, objective, urls_text, dummy_files],
148
+ outputs=[score_json, contexts_text, proposal_text, docx_link, pptx_link, next_actions, index_report],
149
  )
150
 
151
+
152
+ # ---- FastAPI / 静的ファイル公開(/files -> /tmp/agent_studio/exports)----
153
  app = FastAPI()
154
+ # 生成物を静的公開。相対リンク /files/xxx でダウンロード可能。
155
+ app.mount("/files", StaticFiles(directory=EXPORT_DIR), name="files")
156
+ # Gradio をルートにマウント
157
  app = gr.mount_gradio_app(app, demo.queue(), path="/")
158
 
159
  if __name__ == "__main__":
160
  import uvicorn
 
161
  uvicorn.run(app, host="0.0.0.0", port=int(os.getenv("PORT", "7860")))