buggggg
This commit is contained in:
1 parent
e54f42c0eb
commit
b8d3a549df
3 files changed
+74
-6
No files matched your search
@@ -256,6 +256,10 @@ export function AIWritingProvider({ children }: { children: ReactNode }) {
|
||||
const stream = streamRef.current;
|
||||
if (!stream) return;
|
||||
try {
|
||||
// 所见即所得:用户在表单选了什么 materialSource,前端就原样传过去。
|
||||
// 三个合法值:knowledge_base / skill / notebook,后端 state.py 接受任意 str。
|
||||
// 与 material_source 独立的 notebook_search_space_id / notebook_source_ids
|
||||
// 控制是否真的去笔记后端拉素材(仅当用户选了"我的笔记"模式时由表单填充)。
|
||||
await stream.submit(
|
||||
{
|
||||
user_intent: request.userIntent,
|
||||
@@ -266,7 +270,9 @@ export function AIWritingProvider({ children }: { children: ReactNode }) {
|
||||
word_count_target: request.wordCountTarget,
|
||||
keyword_count: Math.max(1, Math.min(10, request.keywordCount)),
|
||||
writing_mode: request.writingMode === 'strict' ? 'strict' : 'loose',
|
||||
material_source: request.materialSource === 'skill' ? 'skill' : 'knowledge_base',
|
||||
material_source: request.materialSource,
|
||||
notebook_search_space_id: request.noteSearchSpaceId ?? null,
|
||||
notebook_source_ids: request.noteSourceIds ?? null,
|
||||
revision_count: 0,
|
||||
max_revisions: 3,
|
||||
status: 'researching',
|
||||
|
||||
@@ -291,6 +291,17 @@ export default function StudioNotebookDetailPage() {
|
||||
await send(text, selectedSourceIds);
|
||||
};
|
||||
|
||||
// Clarification 卡片的「发送」按钮回调。MessageList 内部把用户选中的选项 +
|
||||
// 自由文本合并成一段 answer 传过来,这里走和普通发送同一条 send() 链路,
|
||||
// 把当前选中的来源也一并带上,保持上下文一致。
|
||||
const handleClarificationSubmit = useCallback(
|
||||
async (answer: string) => {
|
||||
if (isStreaming) return;
|
||||
await send(answer, selectedSourceIds);
|
||||
},
|
||||
[send, selectedSourceIds, isStreaming],
|
||||
);
|
||||
|
||||
const handleBackToList = () => {
|
||||
setActiveThreadId(null);
|
||||
setThreadId(undefined);
|
||||
@@ -655,6 +666,7 @@ export default function StudioNotebookDetailPage() {
|
||||
thread={thread}
|
||||
paddingBottom={120}
|
||||
extraRehypePlugins={citationRehypePlugins}
|
||||
onClarificationSubmit={handleClarificationSubmit}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
+55
-5
@@ -109,20 +109,42 @@ async def _search_notebook(
|
||||
"""从笔记 API 按关键词检索内容,返回 source_type='notebook' 的 Material 列表。"""
|
||||
import httpx # 懒导入:仅在笔记模式下才需要
|
||||
|
||||
# 入参全 dump(token 只打长度,不打明文,防止泄漏到日志)
|
||||
logger.info(
|
||||
"[notebook-search] called keywords=%s search_space_id=%s source_ids=%s token_len=%d",
|
||||
keywords,
|
||||
search_space_id,
|
||||
source_ids,
|
||||
len(token) if token else 0,
|
||||
)
|
||||
|
||||
base = (os.getenv("DEER_FLOW_NOTEBOOK_API_BASE") or "").rstrip("/")
|
||||
if not base:
|
||||
logger.warning("DEER_FLOW_NOTEBOOK_API_BASE not set, skipping notebook search")
|
||||
# 改成 error 级别,warning 在很多部署里默认会被过滤掉看不到
|
||||
logger.error(
|
||||
"[notebook-search] DEER_FLOW_NOTEBOOK_API_BASE not set, skipping notebook search. "
|
||||
"请在后端启动环境里设这个环境变量(指向笔记后端根地址,例如 http://localhost:8003)。"
|
||||
)
|
||||
return []
|
||||
|
||||
full_url = f"{base}{_NOTEBOOK_SEARCH_PATH}"
|
||||
logger.info("[notebook-search] base=%s full_url=%s", base, full_url)
|
||||
|
||||
results: list[Material] = []
|
||||
mat_idx = 0
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=20) as client:
|
||||
for kw in keywords[:_NOTEBOOK_MAX_KEYWORDS]:
|
||||
logger.info("[notebook-search] POST kw=%r body=%s", kw, {
|
||||
"query": kw,
|
||||
"source_ids": source_ids,
|
||||
"search_space_id": search_space_id,
|
||||
"top_k": _NOTEBOOK_TOP_K,
|
||||
})
|
||||
try:
|
||||
# /mentioned-documents/search 接口无需鉴权,不传 Authorization header
|
||||
resp = await client.post(
|
||||
f"{base}{_NOTEBOOK_SEARCH_PATH}",
|
||||
headers={"Authorization": f"Bearer {token}"},
|
||||
full_url,
|
||||
json={
|
||||
"query": kw,
|
||||
"source_ids": source_ids,
|
||||
@@ -130,10 +152,29 @@ async def _search_notebook(
|
||||
"top_k": _NOTEBOOK_TOP_K,
|
||||
},
|
||||
)
|
||||
logger.info(
|
||||
"[notebook-search] kw=%r http_status=%d body_len=%d",
|
||||
kw,
|
||||
resp.status_code,
|
||||
len(resp.content or b""),
|
||||
)
|
||||
if resp.status_code >= 400:
|
||||
# 把错误响应体打出来,方便定位 401 / 422 等
|
||||
logger.error(
|
||||
"[notebook-search] kw=%r HTTP %d response: %s",
|
||||
kw,
|
||||
resp.status_code,
|
||||
(resp.text or "")[:1000],
|
||||
)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
# 解析 documents 列表,每个 chunk 作为独立素材
|
||||
documents: list[dict] = data.get("documents") if isinstance(data, dict) else []
|
||||
logger.info(
|
||||
"[notebook-search] kw=%r parsed documents=%d",
|
||||
kw,
|
||||
len(documents or []),
|
||||
)
|
||||
for doc in documents or []:
|
||||
doc_title: str = doc.get("title") or "笔记文档"
|
||||
doc_url: str = doc.get("url") or ""
|
||||
@@ -154,10 +195,11 @@ async def _search_notebook(
|
||||
url=doc_url,
|
||||
))
|
||||
except Exception as e:
|
||||
logger.warning("notebook search kw=%r failed: %s", kw, e)
|
||||
logger.warning("[notebook-search] kw=%r failed: %s", kw, e, exc_info=True)
|
||||
except Exception as e:
|
||||
logger.warning("notebook search client error: %s", e)
|
||||
logger.warning("[notebook-search] client error: %s", e, exc_info=True)
|
||||
|
||||
logger.info("[notebook-search] done — returning %d materials", len(results))
|
||||
return results
|
||||
|
||||
|
||||
@@ -250,6 +292,7 @@ async def researcher_node(state: AIWritingState, config: RunnableConfig) -> dict
|
||||
# Step 1.5: 笔记检索(如果传入了 notebook_search_space_id)
|
||||
notebook_search_space_id: int | None = state.get("notebook_search_space_id")
|
||||
notebook_materials: list[Material] = []
|
||||
|
||||
if notebook_search_space_id:
|
||||
notebook_source_ids: list[int] = state.get("notebook_source_ids") or []
|
||||
notebook_token: str = cfg.get("notebook_token") or ""
|
||||
@@ -369,6 +412,13 @@ async def researcher_node(state: AIWritingState, config: RunnableConfig) -> dict
|
||||
# 技能模式不再走下面的并发/合并逻辑,all_results_nested 留空、跳过 web 通用搜索
|
||||
all_results_nested: list = []
|
||||
# 把已收集到的素材挂在 raw_materials_pre,下方合并阶段直接挪过去
|
||||
elif material_source == "notebook" and notebook_search_space_id:
|
||||
# ── 纯笔记模式 ──
|
||||
# 用户在表单选了「我的笔记」作为素材来源 → 跳过 web/intranet 检索,
|
||||
# 仅使用 Step 1.5 已拉取的 notebook_materials。
|
||||
# 与 UI 文案"从笔记本中检索素材"对齐。
|
||||
_emit(f"仅使用笔记素材,跳过 web/intranet 检索({len(notebook_materials)} 条)")
|
||||
all_results_nested = []
|
||||
else:
|
||||
# ── 常规 web/intranet 模式 ──
|
||||
provider = get_search_provider(ai_writing_config)
|
||||
|
||||
Reference in new issue
Block a user