Agent_studio / app.py
Corin1998's picture
Upload 3 files
e89ec77 verified
raw
history blame
4.99 kB
import os
import json
from pathlib import Path
from typing import Optional, List
from fastapi import FastAPI, Request, HTTPException
from fastapi.responses import PlainTextResponse, RedirectResponse
import gradio as gr
from dotenv import load_dotenv
from modules.workflow import run_full_workflow
from modules.rag_indexer import index_files_and_urls
from modules.rag_retriever import retrieve_contexts
from modules.emailer import build_tracking_url
from modules.utils import ensure_dirs, verify_tracking_token, log_event
load_dotenv()
ensure_dirs()
app = FastAPI(title="Agent Studio")
### ===== Gradio UI =====
def ui_company_score_and_proposal(company_name: str,
company_website: str,
lead_email: str,
urls_text: str,
files: List[gr.File] | None,
custom_objective: str,
temperature: float = 0.4):
urls = [u.strip() for u in urls_text.splitlines() if u.strip()] if urls_text else []
file_paths = [f.name for f in (files or [])]
# 1) インデックス更新(アップロードとURL)
index_report = index_files_and_urls(file_paths=file_paths, urls=urls)
# 2) ワークフロー実行(スコア→RAG→提案→次アクション)
result = run_full_workflow(
company_name=company_name,
company_website=company_website,
lead_email=lead_email,
objective=custom_objective,
temperature=temperature
)
# 3) 出力まとめ
outputs = []
outputs.append("### ✅ 企業スコア\n" + json.dumps(result["score"], ensure_ascii=False, indent=2))
outputs.append("### 🧠 抽出コンテキスト(上位)\n" + "\n\n".join([f"- {c[:300]}..." for c in result["top_contexts"]]))
outputs.append("### ✍️ 提案ドラフト\n" + result["proposal_markdown"])
outputs.append("### 📎 エクスポート\n" + "\n".join([
f"- DOCX: {result['exports']['docx_path']}",
f"- PPTX: {result['exports']['pptx_path']}"
]))
if lead_email:
outputs.append("### ✉️ メール準備\n" + f"To: {lead_email}\nSubject: {result['email']['subject']}\n\n{result['email']['body']}")
outputs.append(f"(本文内のトラッキングリンク例)\n{build_tracking_url('preview-only', {'company':company_name})}")
outputs.append("### 🤖 次アクション提案\n" + result["next_actions"])
outputs.append("### 🧩 インデックス更新ログ\n" + index_report)
return "\n\n".join(outputs)
with gr.Blocks(title="Agent Studio") as demo:
gr.Markdown("# 営業自動化 Agent Studio")
with gr.Row():
with gr.Column():
company_name = gr.Textbox(label="企業名", placeholder="例)Acme Corp")
company_website = gr.Textbox(label="企業サイトURL", placeholder="例)https://www.acme.com")
lead_email = gr.Textbox(label="送信先メール(任意)", placeholder="例)lead@acme.com")
custom_objective = gr.Textbox(label="提案の目的/狙い(任意)", placeholder="例)SaaS導入の無料PoC打診")
urls_text = gr.Textbox(label="RAG用URL(複数は改行)", lines=4)
files = gr.File(label="RAG用ファイル(複数可)", file_count="multiple")
temperature = gr.Slider(0.0, 1.0, value=0.4, step=0.05, label="生成温度")
run_btn = gr.Button("ワークフロー実行", variant="primary")
with gr.Column():
out = gr.Markdown(label="結果")
run_btn.click(
fn=ui_company_score_and_proposal,
inputs=[company_name, company_website, lead_email, urls_text, files, custom_objective, temperature],
outputs=[out]
)
# HF Spacesは "app" 変数をエクスポートしている必要あり
# FastAPIにGradioをマウント(ルートに表示)
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"]
)
app = gr.mount_gradio_app(app, demo, path="/")
### ===== クリックトラッキング・エンドポイント =====
@app.get("/t/{token}", response_class=PlainTextResponse)
def track_click(token: str, request: Request):
# token署名検証 & ペイロード取得
payload = verify_tracking_token(token)
if payload is None:
raise HTTPException(status_code=400, detail="invalid token")
# ログ
ip = request.client.host if request.client else "unknown"
ua = request.headers.get("User-Agent", "")
log_event(event_type="click", payload=payload, meta={"ip": ip, "ua": ua})
# 遷移先URL(ペイロードにredirectがあればそこへ、なければUIトップへ)
redirect_to = payload.get("redirect") or os.getenv("PUBLIC_BASE_URL", "/")
return RedirectResponse(url=redirect_to)