Spaces:
Sleeping
Sleeping
File size: 6,033 Bytes
2309f1e 4fc9f3a 2309f1e be9db67 2309f1e be9db67 2309f1e be9db67 2309f1e be9db67 2309f1e 4fc9f3a 2309f1e 4fc9f3a 2309f1e 4fc9f3a 2309f1e be9db67 2309f1e 4fc9f3a 2309f1e 4fc9f3a 2309f1e 4fc9f3a 2309f1e 4fc9f3a 2309f1e 4fc9f3a 2309f1e 4fc9f3a 2309f1e 4fc9f3a |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# modules/workflow.py
import os
from typing import Dict, Any, List
# =========================
# retriever のロード(相対 → 絶対 → フォールバック実装)
# =========================
def _fallback_retrieve_contexts(query: str, top_k: int = 5) -> List[str]:
"""
フォールバックの簡易 RAG:
- modules.utils.data_dir()/chunks.jsonl を読み込み
- キーワード一致スコアで上位を返す(埋め込みなし)
"""
import json
from pathlib import Path
try:
# 遅延 import(循環回避 & 起動高速化)
from modules.utils import data_dir, ensure_dirs
ensure_dirs()
p = data_dir() / "chunks.jsonl"
if not p.exists():
return []
rows = []
with open(p, "r", encoding="utf-8") as f:
for line in f:
line = line.strip()
if not line:
continue
try:
obj = json.loads(line)
if isinstance(obj, dict) and obj.get("text"):
rows.append(obj)
except Exception:
continue
if not rows:
return []
# ごく簡易なキーワード一致スコア
q = (query or "").lower()
def score(t: str) -> int:
t = (t or "").lower()
s = 0
for w in q.split():
if w and w in t:
s += 1
return s
scored = sorted(rows, key=lambda r: score(str(r.get("text",""))), reverse=True)
top = scored[:max(1, int(top_k))]
out = []
for r in top:
txt = str(r.get("text","")).strip()
src = r.get("source")
out.append(f"{txt}\n[source] {src}" if src else txt)
return out
except Exception:
return []
# まず相対 import を試す
try:
from .rag_retriever import retrieve_contexts # type: ignore
except Exception:
# 絶対 import
try:
from modules.rag_retriever import retrieve_contexts # type: ignore
except Exception:
# 最後の手段: フォールバックを使う
retrieve_contexts = _fallback_retrieve_contexts # type: ignore
# exporters / utils は相対を優先
try:
from .exporters import export_docx, export_pptx
from .utils import ensure_dirs, export_dir, make_tracking_token
except Exception:
from modules.exporters import export_docx, export_pptx # type: ignore
from modules.utils import ensure_dirs, export_dir, make_tracking_token # type: ignore
def _score_company(company_name: str, website: str, contexts: List[str]) -> Dict[str, Any]:
"""
デモ用の簡易スコア(実運用では独自ロジック/モデルと差し替え可)
"""
score = 50
if website:
score += 10
if contexts:
score += min(40, len(contexts) * 5)
return {
"company": company_name,
"website": website,
"score": min(score, 95),
"factors": {
"has_website": bool(website),
"ctx_hits": len(contexts),
},
}
def _draft_proposal_md(company_name: str, objective: str, contexts: List[str]) -> str:
bullets = "\n".join([f"- {c[:200]}..." for c in contexts[:5]])
obj = objective or "商談化のための初回提案"
return f"""# 提案ドラフト({company_name} 向け)
## 目的
{obj}
## 背景インサイト(上位抜粋)
{bullets if bullets else '- (まだインデックスが空です)'}
## 提案骨子
1. 現状の課題仮説を確認
2. PoC スコープのすり合わせ
3. 成果指標(KPI)とスケジュール
4. 次のアクション
"""
def _draft_email(company_name: str) -> Dict[str, str]:
subject = f"{company_name}様向けご提案(ドラフト)"
body = (
f"{company_name} ご担当者様\n\n"
"お世話になっております。簡易の提案ドラフトを共有いたします。\n"
"ご確認の上、ご意見いただけますと幸いです。\n\n"
"何卒よろしくお願いいたします。"
)
return {"subject": subject, "body": body}
def run_full_workflow(
company_name: str,
company_website: str,
lead_email: str,
objective: str,
temperature: float = 0.4,
) -> Dict[str, Any]:
"""
app.py から呼ばれるメイン処理。
- RAG で上位コンテキスト取得(retriever が無い場合はフォールバック)
- 簡易スコアリング
- 提案ドラフト生成
- DOCX/PPTX にエクスポート
- メール文面と次アクションの素案
"""
ensure_dirs()
query = f"{company_name} {objective or ''}".strip()
top_contexts = retrieve_contexts(query, top_k=5)
score = _score_company(company_name, company_website, top_contexts)
proposal_md = _draft_proposal_md(company_name, objective, top_contexts)
# エクスポート先パス
out_dir = export_dir()
docx_path = os.path.join(out_dir, f"{company_name}_proposal.docx")
pptx_path = os.path.join(out_dir, f"{company_name}_proposal.pptx")
# 出力
export_docx(proposal_md, docx_path)
export_pptx(proposal_md, pptx_path)
email = _draft_email(company_name)
# 次アクション(ダミー)
next_actions = (
"- 先方の課題確認ミーティング候補日程を提案する\n"
"- PoC スコープの要件一覧を作成して共有\n"
"- 競合比較の要点を 3 点に要約\n"
)
# 計測リンクの例(app.py の /t/{token} で受ける想定)
tracking_token = make_tracking_token({"company": company_name, "redirect": "/"})
return {
"score": score,
"top_contexts": top_contexts,
"proposal_markdown": proposal_md,
"exports": {"docx_path": docx_path, "pptx_path": pptx_path},
"email": email,
"next_actions": next_actions,
"tracking_token": tracking_token,
}
|