Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,5 @@ obsidian:
auto_export_on_save: true
auto_sync_tracks: true
export_limit: 200
track_moc_filename: "_MOC.md"
group_tracks_in_folders: true
13 changes: 13 additions & 0 deletions config/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ class ObsidianConfig(BaseModel):
auto_export_on_save: bool = True
auto_sync_tracks: bool = True
export_limit: int = 200
track_moc_filename: str = "_MOC.md"
group_tracks_in_folders: bool = True


class CollabHostConfig(BaseModel):
Expand Down Expand Up @@ -334,6 +336,8 @@ def load_environment_variables(self) -> None:
obsidian_auto_export = os.getenv("PAPERBOT_OBSIDIAN_AUTO_EXPORT")
obsidian_auto_sync_tracks = os.getenv("PAPERBOT_OBSIDIAN_AUTO_SYNC_TRACKS")
obsidian_export_limit = os.getenv("PAPERBOT_OBSIDIAN_EXPORT_LIMIT")
obsidian_track_moc_filename = os.getenv("PAPERBOT_OBSIDIAN_TRACK_MOC_FILENAME")
obsidian_group_tracks = os.getenv("PAPERBOT_OBSIDIAN_GROUP_TRACKS_IN_FOLDERS")
if re_enabled is not None:
self.report_engine.enabled = re_enabled.lower() in ("1", "true", "yes", "on")
if re_api:
Expand Down Expand Up @@ -393,6 +397,15 @@ def load_environment_variables(self) -> None:
"Ignoring invalid PAPERBOT_OBSIDIAN_EXPORT_LIMIT=%r; expected an integer",
obsidian_export_limit,
)
if obsidian_track_moc_filename:
self.obsidian.track_moc_filename = obsidian_track_moc_filename
if obsidian_group_tracks is not None:
self.obsidian.group_tracks_in_folders = obsidian_group_tracks.lower() in (
"1",
"true",
"yes",
"on",
)

# Collab host LLM
host_api = os.getenv("PAPERBOT_HOST_API_KEY")
Expand Down
2 changes: 2 additions & 0 deletions src/paperbot/api/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
research,
paperscool,
newsletter,
obsidian,
harvest,
model_endpoints,
studio_chat,
Expand Down Expand Up @@ -80,6 +81,7 @@ async def health_check():
app.include_router(research.router, prefix="/api", tags=["Research"])
app.include_router(paperscool.router, prefix="/api", tags=["PapersCool"])
app.include_router(newsletter.router, prefix="/api", tags=["Newsletter"])
app.include_router(obsidian.router, prefix="/api", tags=["Obsidian"])
app.include_router(harvest.router, prefix="/api", tags=["Harvest"])
app.include_router(model_endpoints.router, prefix="/api", tags=["Model Endpoints"])
app.include_router(studio_chat.router, prefix="/api", tags=["Studio Chat"])
Expand Down
2 changes: 2 additions & 0 deletions src/paperbot/api/routes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
research,
paperscool,
newsletter,
obsidian,
model_endpoints,
repro_context,
feed,
Expand All @@ -36,6 +37,7 @@
"research",
"paperscool",
"newsletter",
"obsidian",
"model_endpoints",
"repro_context",
"feed",
Expand Down
86 changes: 86 additions & 0 deletions src/paperbot/api/routes/obsidian.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
from __future__ import annotations

from pathlib import Path
from typing import List, Optional

from fastapi import APIRouter, HTTPException
from pydantic import BaseModel, Field

from config.settings import create_settings
from paperbot.infrastructure.exporters import ObsidianReportExporter

router = APIRouter()


class ObsidianReportCitationRequest(BaseModel):
title: str = Field(..., min_length=1, max_length=500)
year: Optional[int] = None
authors: List[str] = Field(default_factory=list)
relevant_finding: str = ""
doi: Optional[str] = None
arxiv_id: Optional[str] = None
semantic_scholar_id: Optional[str] = None
id: Optional[str] = None


class ObsidianReportSectionRequest(BaseModel):
title: str = Field(..., min_length=1, max_length=200)
content: str = ""
cited_papers: List[ObsidianReportCitationRequest] = Field(default_factory=list)


class ObsidianMethodComparisonRequest(BaseModel):
name: str = Field(..., min_length=1, max_length=120)
paper: str = Field(..., min_length=1, max_length=500)
pros: str = ""
cons: str = ""


class ObsidianExportReportRequest(BaseModel):
title: str = Field(..., min_length=1, max_length=300)
vault_path: Optional[str] = None
root_dir: Optional[str] = None
track_name: Optional[str] = Field(default=None, max_length=128)
workflow_type: str = "research"
summary: str = ""
key_insight: str = ""
sections: List[ObsidianReportSectionRequest] = Field(default_factory=list)
methods: List[ObsidianMethodComparisonRequest] = Field(default_factory=list)
trends: str = ""
future_directions: str = ""
references: List[ObsidianReportCitationRequest] = Field(default_factory=list)
tags: List[str] = Field(default_factory=list)


class ObsidianExportReportResponse(BaseModel):
vault_path: str
root_dir: str
title: str
note_path: str


@router.post("/obsidian/export-report", response_model=ObsidianExportReportResponse)
def export_obsidian_report(req: ObsidianExportReportRequest) -> ObsidianExportReportResponse:
settings = create_settings()
obsidian_config = settings.obsidian

vault_value = str(req.vault_path or obsidian_config.vault_path or "").strip()
if not vault_value:
raise HTTPException(
status_code=400,
detail="vault_path is required. Pass it in the request or configure obsidian.vault_path.",
)

exporter = ObsidianReportExporter()
try:
result = exporter.export_report_note(
vault_path=Path(vault_value),
report=req.model_dump(),
root_dir=str(req.root_dir or obsidian_config.root_dir or "PaperBot"),
track_moc_filename=getattr(obsidian_config, "track_moc_filename", "_MOC.md"),
group_tracks_in_folders=getattr(obsidian_config, "group_tracks_in_folders", True),
)
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc

return ObsidianExportReportResponse(**result)
2 changes: 2 additions & 0 deletions src/paperbot/application/ports/vault_exporter_port.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@ def export_library_snapshot(
track: Optional[Dict[str, Any]] = None,
root_dir: str = "PaperBot",
paper_template_path: Optional[Path] = None,
track_moc_filename: str = "_MOC.md",
group_tracks_in_folders: bool = True,
) -> Dict[str, Any]: ...
5 changes: 5 additions & 0 deletions src/paperbot/infrastructure/api_clients/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@
"""

from .base import APIClient
from .citation_graph import CitationGraph, CitationGraphClient, CitationGraphEdge, CitationGraphNode
from .github_client import GitHubRadarClient
from .semantic_scholar import SemanticScholarClient
from .x_client import XRecentSearchClient

__all__ = [
"APIClient",
"CitationGraph",
"CitationGraphClient",
"CitationGraphEdge",
"CitationGraphNode",
"GitHubRadarClient",
"SemanticScholarClient",
"XRecentSearchClient",
Expand Down
Loading
Loading