feat: add public digest brief output for openclaw
This commit is contained in:
@@ -26,7 +26,9 @@ from .keyword_index import DailyKeywordIndex, DailyKeywordTerm, KeywordStat, Key
|
||||
from .openclaw_delivery import (
|
||||
OpenClawDeliveryPayload,
|
||||
OpenClawDeliveryStats,
|
||||
OpenClawDigestBrief,
|
||||
build_openclaw_delivery_payload,
|
||||
build_openclaw_digest_brief,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
@@ -50,10 +52,12 @@ __all__ = [
|
||||
"OpenClawCandidateInput",
|
||||
"OpenClawDeliveryPayload",
|
||||
"OpenClawDeliveryStats",
|
||||
"OpenClawDigestBrief",
|
||||
"ReviewState",
|
||||
"ReviewStatus",
|
||||
"build_article_candidate_record",
|
||||
"build_openclaw_delivery_payload",
|
||||
"build_openclaw_digest_brief",
|
||||
"build_openclaw_candidate_input",
|
||||
"candidate_id_for",
|
||||
"normalize_candidate_url",
|
||||
|
||||
@@ -6,6 +6,9 @@ from pydantic import BaseModel, Field
|
||||
|
||||
from .article_candidate import OpenClawCandidateInput
|
||||
|
||||
DIGEST_BRIEF_LIMIT = 5
|
||||
DIGEST_BRIEF_HIGHLIGHT_LIMIT = 3
|
||||
|
||||
|
||||
class OpenClawDeliveryStats(BaseModel):
|
||||
total: int = Field(default=0, ge=0)
|
||||
@@ -23,6 +26,27 @@ class OpenClawDeliveryPayload(BaseModel):
|
||||
stats: OpenClawDeliveryStats = Field(default_factory=OpenClawDeliveryStats)
|
||||
|
||||
|
||||
class DigestBriefCandidate(BaseModel):
|
||||
title: str
|
||||
source_name: str | None = None
|
||||
summary: str
|
||||
highlights: list[str] = Field(default_factory=list)
|
||||
category: str | None = None
|
||||
digest_rank: int = Field(default=0)
|
||||
selection_decision: str
|
||||
url: str
|
||||
|
||||
|
||||
class OpenClawDigestBrief(BaseModel):
|
||||
schema_version: str = "digest-brief.v1"
|
||||
generated_at: datetime
|
||||
run_id: str
|
||||
date: date
|
||||
source_candidate_count: int = Field(default=0, ge=0)
|
||||
candidate_count: int = Field(default=0, ge=0)
|
||||
top_candidates: list[DigestBriefCandidate] = Field(default_factory=list)
|
||||
|
||||
|
||||
def build_openclaw_delivery_payload(
|
||||
candidates: list[OpenClawCandidateInput],
|
||||
*,
|
||||
@@ -46,4 +70,36 @@ def build_openclaw_delivery_payload(
|
||||
date=payload_date,
|
||||
candidates=candidates,
|
||||
stats=stats,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def build_openclaw_digest_brief(
|
||||
payload: OpenClawDeliveryPayload,
|
||||
*,
|
||||
limit: int = DIGEST_BRIEF_LIMIT,
|
||||
highlight_limit: int = DIGEST_BRIEF_HIGHLIGHT_LIMIT,
|
||||
) -> OpenClawDigestBrief:
|
||||
keep_candidates = [candidate for candidate in payload.candidates if candidate.selection_decision == "keep"]
|
||||
sorted_candidates = sorted(keep_candidates, key=lambda candidate: candidate.digest_rank, reverse=True)
|
||||
top_candidates = [
|
||||
DigestBriefCandidate(
|
||||
title=candidate.title,
|
||||
source_name=candidate.source_name,
|
||||
summary=candidate.summary,
|
||||
highlights=list(candidate.highlights[:highlight_limit]),
|
||||
category=candidate.category,
|
||||
digest_rank=candidate.digest_rank,
|
||||
selection_decision=candidate.selection_decision,
|
||||
url=str(candidate.url),
|
||||
)
|
||||
for candidate in sorted_candidates[:limit]
|
||||
]
|
||||
return OpenClawDigestBrief(
|
||||
schema_version="digest-brief.v1",
|
||||
generated_at=payload.generated_at,
|
||||
run_id=payload.run_id,
|
||||
date=payload.date,
|
||||
source_candidate_count=len(payload.candidates),
|
||||
candidate_count=len(top_candidates),
|
||||
top_candidates=top_candidates,
|
||||
)
|
||||
|
||||
@@ -26,7 +26,11 @@ from summary_mcp.models.article_candidate import (
|
||||
)
|
||||
from summary_mcp.models.filtering import FilterContext, FilterInput
|
||||
from summary_mcp.models.llm_result import LlmSummaryResult
|
||||
from summary_mcp.models.openclaw_delivery import OpenClawDeliveryPayload, build_openclaw_delivery_payload
|
||||
from summary_mcp.models.openclaw_delivery import (
|
||||
OpenClawDeliveryPayload,
|
||||
build_openclaw_delivery_payload,
|
||||
build_openclaw_digest_brief,
|
||||
)
|
||||
from summary_mcp.models.summary_io import ExtractionInput
|
||||
|
||||
|
||||
@@ -197,8 +201,8 @@ def _build_and_persist_delivery(
|
||||
resolved_run_id: str,
|
||||
resolved_delivery_date: Any,
|
||||
delivery_output: Path,
|
||||
) -> tuple[OpenClawDeliveryPayload, dict[str, Any]]:
|
||||
# 按 digest_rank 排序,构建 delivery payload,持久化词元索引
|
||||
) -> tuple[OpenClawDeliveryPayload, Path, dict[str, Any]]:
|
||||
# 按 digest_rank 排序,构建 delivery payload;同时派生一个更轻量的 digest-brief.json 供日报生成使用。
|
||||
delivered_candidates.sort(key=lambda candidate: candidate.digest_rank, reverse=True)
|
||||
delivery_payload = build_openclaw_delivery_payload(
|
||||
delivered_candidates,
|
||||
@@ -207,6 +211,10 @@ def _build_and_persist_delivery(
|
||||
)
|
||||
_save_json(delivery_output, delivery_payload.model_dump(mode="json"))
|
||||
|
||||
digest_brief = build_openclaw_digest_brief(delivery_payload)
|
||||
digest_brief_output = delivery_output.with_name("digest-brief.json")
|
||||
_save_json(digest_brief_output, digest_brief.model_dump(mode="json"))
|
||||
|
||||
keyword_index_result = persist_keyword_indexes(
|
||||
delivery_payload.candidates,
|
||||
for_date=delivery_payload.date,
|
||||
@@ -217,7 +225,7 @@ def _build_and_persist_delivery(
|
||||
aliases_path=DEFAULT_TERM_ALIASES_PATH,
|
||||
stopwords_path=DEFAULT_TERM_STOPWORDS_PATH,
|
||||
)
|
||||
return delivery_payload, keyword_index_result
|
||||
return delivery_payload, digest_brief_output, keyword_index_result
|
||||
|
||||
|
||||
def _build_run_report(
|
||||
@@ -232,6 +240,7 @@ def _build_run_report(
|
||||
debug_artifacts: bool,
|
||||
raw_output: Path,
|
||||
delivery_output: Path,
|
||||
digest_brief_output: Path,
|
||||
keyword_index_result: dict[str, Any],
|
||||
item_reports: list[dict[str, Any]],
|
||||
) -> dict[str, Any]:
|
||||
@@ -253,6 +262,7 @@ def _build_run_report(
|
||||
"debug_artifacts": debug_artifacts,
|
||||
"raw_output": str(raw_output),
|
||||
"delivery_output": str(delivery_output),
|
||||
"digest_brief_output": str(digest_brief_output),
|
||||
"keyword_index": keyword_index_result,
|
||||
"status_counts": status_counts,
|
||||
"items": item_reports,
|
||||
@@ -369,7 +379,7 @@ def run_freshrss_pipeline(
|
||||
item_reports.append(result)
|
||||
|
||||
# --- 阶段 4+5:构建 delivery payload 并持久化词元索引 ---
|
||||
delivery_payload, keyword_index_result = _build_and_persist_delivery(
|
||||
delivery_payload, digest_brief_output, keyword_index_result = _build_and_persist_delivery(
|
||||
delivered_candidates=delivered_candidates,
|
||||
resolved_run_id=resolved_run_id,
|
||||
resolved_delivery_date=resolved_delivery_date,
|
||||
@@ -394,6 +404,7 @@ def run_freshrss_pipeline(
|
||||
debug_artifacts=debug_artifacts,
|
||||
raw_output=raw_output,
|
||||
delivery_output=delivery_output,
|
||||
digest_brief_output=digest_brief_output,
|
||||
keyword_index_result=keyword_index_result,
|
||||
item_reports=item_reports,
|
||||
)
|
||||
@@ -404,6 +415,7 @@ def run_freshrss_pipeline(
|
||||
"output_dir": str(resolved_output_dir),
|
||||
"raw_output": str(raw_output),
|
||||
"delivery_output": str(delivery_output),
|
||||
"digest_brief_output": str(digest_brief_output),
|
||||
"report_output": str(report_output),
|
||||
"keyword_index": keyword_index_result,
|
||||
"pulled_count": len(items),
|
||||
|
||||
Reference in New Issue
Block a user