Corin1998 commited on
Commit
e89ec77
·
verified ·
1 Parent(s): 69990ff

Upload 3 files

Browse files
Files changed (3) hide show
  1. README.md +28 -12
  2. app.py +106 -0
  3. requirements.txt +19 -0
README.md CHANGED
@@ -1,12 +1,28 @@
1
- ---
2
- title: Agent Studio
3
- emoji: 🏆
4
- colorFrom: pink
5
- colorTo: pink
6
- sdk: gradio
7
- sdk_version: 5.46.1
8
- app_file: app.py
9
- pinned: false
10
- ---
11
-
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 営業自動化 Agent Studio (HF Spaces)
2
+
3
+ ## セットアップ
4
+ 1. 本リポジトリ構成でファイルを用意(`app.py` がエントリ)。
5
+ 2. Hugging Face Spaces で **Python** Space を作成し、上記ファイルをアップロード。
6
+ 3. **Variables/Secrets** に `.env.example` の内容を登録(少なくとも `PUBLIC_BASE_URL`, `TRACKING_SECRET` 推奨)。
7
+ 4. 必要であれば SMTP 設定を投入(メール送信を使う場合)。
8
+
9
+ ## できること
10
+ - 企業スコア → RAG(URL/ファイル)→ 提案ドラフト生成(LLM)→ DOCX/PPTXエクスポート
11
+ - メール本文の生成(トラッキングリンク挿入)
12
+ - `/t/{token}` へのアクセスでクリックログを `data/events.jsonl` に蓄積
13
+
14
+ ## LLM
15
+ - 既定は `google/flan-t5-base`(軽量)。必要なら `HF_LOCAL_MODEL_ID` を `mistralai/Mistral-7B-Instruct-v0.3` などに変更。
16
+ - Inference API を使う場合は `USE_HF_INFERENCE_API=true` と `HF_API_TOKEN` を設定。
17
+
18
+ ## 使い方
19
+ - UIに企業名・URL・(任意で)送信先メール、RAG用URLやファイルを指定→「ワークフロー実行」
20
+ - `data/` に `proposal_*.docx` と `proposal_*.pptx` が出力されます
21
+ - クリックログは `data/events.jsonl` をご確認ください
22
+
23
+ ## 送信
24
+ - 実運用では `modules/emailer.py` の `send_email` を呼ぶAPIやUIボタンを追加してください(デモでは本文プレビューのみ)。
25
+
26
+ ## 注意
27
+ - 無断クロールを避けるため、RAGのURL投入は対象サイトの規約に従ってください。
28
+ - 機密ファイルの取り扱いには十分ご注意ください。
app.py ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ from pathlib import Path
4
+ from typing import Optional, List
5
+
6
+ from fastapi import FastAPI, Request, HTTPException
7
+ from fastapi.responses import PlainTextResponse, RedirectResponse
8
+ import gradio as gr
9
+ from dotenv import load_dotenv
10
+
11
+ from modules.workflow import run_full_workflow
12
+ from modules.rag_indexer import index_files_and_urls
13
+ from modules.rag_retriever import retrieve_contexts
14
+ from modules.emailer import build_tracking_url
15
+ from modules.utils import ensure_dirs, verify_tracking_token, log_event
16
+
17
+ load_dotenv()
18
+ ensure_dirs()
19
+
20
+ app = FastAPI(title="Agent Studio")
21
+
22
+ ### ===== Gradio UI =====
23
+ def ui_company_score_and_proposal(company_name: str,
24
+ company_website: str,
25
+ lead_email: str,
26
+ urls_text: str,
27
+ files: List[gr.File] | None,
28
+ custom_objective: str,
29
+ temperature: float = 0.4):
30
+ urls = [u.strip() for u in urls_text.splitlines() if u.strip()] if urls_text else []
31
+ file_paths = [f.name for f in (files or [])]
32
+
33
+ # 1) インデックス更新(アップロードとURL)
34
+ index_report = index_files_and_urls(file_paths=file_paths, urls=urls)
35
+
36
+ # 2) ワークフロー実行(スコア→RAG→提案→次アクション)
37
+ result = run_full_workflow(
38
+ company_name=company_name,
39
+ company_website=company_website,
40
+ lead_email=lead_email,
41
+ objective=custom_objective,
42
+ temperature=temperature
43
+ )
44
+
45
+ # 3) 出力まとめ
46
+ outputs = []
47
+ outputs.append("### ✅ 企業スコア\n" + json.dumps(result["score"], ensure_ascii=False, indent=2))
48
+ outputs.append("### 🧠 抽出コンテキスト(上位)\n" + "\n\n".join([f"- {c[:300]}..." for c in result["top_contexts"]]))
49
+ outputs.append("### ✍️ 提案ドラフト\n" + result["proposal_markdown"])
50
+ outputs.append("### 📎 エクスポート\n" + "\n".join([
51
+ f"- DOCX: {result['exports']['docx_path']}",
52
+ f"- PPTX: {result['exports']['pptx_path']}"
53
+ ]))
54
+ if lead_email:
55
+ outputs.append("### ✉️ メール準備\n" + f"To: {lead_email}\nSubject: {result['email']['subject']}\n\n{result['email']['body']}")
56
+ outputs.append(f"(本文内のトラッキングリンク例)\n{build_tracking_url('preview-only', {'company':company_name})}")
57
+
58
+ outputs.append("### 🤖 次アクション提案\n" + result["next_actions"])
59
+ outputs.append("### 🧩 インデックス更新ログ\n" + index_report)
60
+
61
+ return "\n\n".join(outputs)
62
+
63
+ with gr.Blocks(title="Agent Studio") as demo:
64
+ gr.Markdown("# 営業自動化 Agent Studio")
65
+ with gr.Row():
66
+ with gr.Column():
67
+ company_name = gr.Textbox(label="企業名", placeholder="例)Acme Corp")
68
+ company_website = gr.Textbox(label="企業サイトURL", placeholder="例)https://www.acme.com")
69
+ lead_email = gr.Textbox(label="送信先メール(任意)", placeholder="例)lead@acme.com")
70
+ custom_objective = gr.Textbox(label="提案の目的/狙い(任意)", placeholder="例)SaaS導入の無料PoC打診")
71
+ urls_text = gr.Textbox(label="RAG用URL(複数は改行)", lines=4)
72
+ files = gr.File(label="RAG用ファイル(複数可)", file_count="multiple")
73
+ temperature = gr.Slider(0.0, 1.0, value=0.4, step=0.05, label="生成温度")
74
+ run_btn = gr.Button("ワークフロー実行", variant="primary")
75
+ with gr.Column():
76
+ out = gr.Markdown(label="結果")
77
+
78
+ run_btn.click(
79
+ fn=ui_company_score_and_proposal,
80
+ inputs=[company_name, company_website, lead_email, urls_text, files, custom_objective, temperature],
81
+ outputs=[out]
82
+ )
83
+
84
+ # HF Spacesは "app" 変数をエクスポートしている必要あり
85
+ # FastAPIにGradioをマウント(ルートに表示)
86
+ from fastapi.middleware.cors import CORSMiddleware
87
+ app.add_middleware(
88
+ CORSMiddleware,
89
+ allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"]
90
+ )
91
+ app = gr.mount_gradio_app(app, demo, path="/")
92
+
93
+ ### ===== クリックトラッキング・エンドポイント =====
94
+ @app.get("/t/{token}", response_class=PlainTextResponse)
95
+ def track_click(token: str, request: Request):
96
+ # token署名検証 & ペイロード取得
97
+ payload = verify_tracking_token(token)
98
+ if payload is None:
99
+ raise HTTPException(status_code=400, detail="invalid token")
100
+ # ログ
101
+ ip = request.client.host if request.client else "unknown"
102
+ ua = request.headers.get("User-Agent", "")
103
+ log_event(event_type="click", payload=payload, meta={"ip": ip, "ua": ua})
104
+ # 遷移先URL(ペイロードにredirectがあればそこへ、なければUIトップへ)
105
+ redirect_to = payload.get("redirect") or os.getenv("PUBLIC_BASE_URL", "/")
106
+ return RedirectResponse(url=redirect_to)
requirements.txt ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ fastapi==0.111.1
2
+ uvicorn==0.30.6
3
+ gradio==4.44.1
4
+
5
+ transformers==4.44.2
6
+ torch>=2.1.0
7
+ sentence-transformers==3.0.1
8
+ faiss-cpu==1.8.0.post1
9
+
10
+ python-docx==1.1.2
11
+ python-pptx==0.6.23
12
+
13
+ beautifulspup4==4.12.3
14
+ requests==2.32.3
15
+ readability-lxml==0.8.1
16
+ lxml==5.3.0
17
+ tldextract==5.1.2
18
+ python-dotenv==1.0.1
19
+ pydantic==2.9.2