-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Add opt-in publish to understand-quickly registry #517
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -115,7 +115,42 @@ class WikiExportRequest(BaseModel): | |||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||
| repo_url: str = Field(..., description="URL of the repository") | ||||||||||||||||||||||||||||||||||||||
| pages: List[WikiPage] = Field(..., description="List of wiki pages to export") | ||||||||||||||||||||||||||||||||||||||
| format: Literal["markdown", "json"] = Field(..., description="Export format (markdown or json)") | ||||||||||||||||||||||||||||||||||||||
| format: Literal["markdown", "json", "graph"] = Field( | ||||||||||||||||||||||||||||||||||||||
| ..., | ||||||||||||||||||||||||||||||||||||||
| description=( | ||||||||||||||||||||||||||||||||||||||
| "Export format. 'markdown' / 'json' are the existing wiki dumps; " | ||||||||||||||||||||||||||||||||||||||
| "'graph' emits a generic@1 knowledge graph for the " | ||||||||||||||||||||||||||||||||||||||
| "looptech-ai/understand-quickly registry." | ||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||
| publish: bool = Field( | ||||||||||||||||||||||||||||||||||||||
| False, | ||||||||||||||||||||||||||||||||||||||
| description=( | ||||||||||||||||||||||||||||||||||||||
| "If true, after producing the export also fire a " | ||||||||||||||||||||||||||||||||||||||
| "repository_dispatch event at looptech-ai/understand-quickly " | ||||||||||||||||||||||||||||||||||||||
| "so the registry resyncs the entry. Opt-in; requires " | ||||||||||||||||||||||||||||||||||||||
| "UNDERSTAND_QUICKLY_TOKEN in the server env. No-ops cleanly " | ||||||||||||||||||||||||||||||||||||||
| "if the token is missing." | ||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||
| repo: Optional[str] = Field( | ||||||||||||||||||||||||||||||||||||||
| None, | ||||||||||||||||||||||||||||||||||||||
| description=( | ||||||||||||||||||||||||||||||||||||||
| "Optional 'owner/repo' override for the registry id. If " | ||||||||||||||||||||||||||||||||||||||
| "omitted, derived from `repo_url`. Must match the owner/repo " | ||||||||||||||||||||||||||||||||||||||
| "implied by `repo_url` when set — mismatches are rejected to " | ||||||||||||||||||||||||||||||||||||||
| "prevent dispatching syncs for unrelated entries." | ||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||
| commit: Optional[str] = Field( | ||||||||||||||||||||||||||||||||||||||
| None, | ||||||||||||||||||||||||||||||||||||||
| description=( | ||||||||||||||||||||||||||||||||||||||
| "Optional 40-hex git commit SHA to embed in the graph " | ||||||||||||||||||||||||||||||||||||||
| "metadata. If omitted, the server attempts to resolve HEAD " | ||||||||||||||||||||||||||||||||||||||
| "from its local checkout (best-effort) and otherwise leaves " | ||||||||||||||||||||||||||||||||||||||
| "`metadata.commit` unset." | ||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # --- Model Configuration Models --- | ||||||||||||||||||||||||||||||||||||||
| class Model(BaseModel): | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -227,7 +262,7 @@ async def get_model_config(): | |||||||||||||||||||||||||||||||||||||
| @app.post("/export/wiki") | ||||||||||||||||||||||||||||||||||||||
| async def export_wiki(request: WikiExportRequest): | ||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||
| Export wiki content as Markdown or JSON. | ||||||||||||||||||||||||||||||||||||||
| Export wiki content as Markdown, JSON, or a knowledge graph. | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| Args: | ||||||||||||||||||||||||||||||||||||||
| request: The export request containing wiki pages and format | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -245,24 +280,73 @@ async def export_wiki(request: WikiExportRequest): | |||||||||||||||||||||||||||||||||||||
| # Get current timestamp for the filename | ||||||||||||||||||||||||||||||||||||||
| timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| publish_status: Optional[Dict[str, Any]] = None | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| headers: Dict[str, str] = {} | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| if request.format == "markdown": | ||||||||||||||||||||||||||||||||||||||
| # Generate Markdown content | ||||||||||||||||||||||||||||||||||||||
| content = generate_markdown_export(request.repo_url, request.pages) | ||||||||||||||||||||||||||||||||||||||
| filename = f"{repo_name}_wiki_{timestamp}.md" | ||||||||||||||||||||||||||||||||||||||
| media_type = "text/markdown" | ||||||||||||||||||||||||||||||||||||||
| elif request.format == "graph": | ||||||||||||||||||||||||||||||||||||||
| # generic@1 knowledge graph for looptech-ai/understand-quickly. | ||||||||||||||||||||||||||||||||||||||
| from api.publish import ( | ||||||||||||||||||||||||||||||||||||||
| build_graph_payload, | ||||||||||||||||||||||||||||||||||||||
| derive_owner_repo, | ||||||||||||||||||||||||||||||||||||||
| git_head_sha, | ||||||||||||||||||||||||||||||||||||||
| publish as publish_to_registry, | ||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+293
to
+298
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you apply the suggestion to include the commit SHA, ensure you also import the
Suggested change
|
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| derived_owner_repo = derive_owner_repo(request.repo_url) | ||||||||||||||||||||||||||||||||||||||
| commit = request.commit or git_head_sha() | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| payload = build_graph_payload( | ||||||||||||||||||||||||||||||||||||||
| [page.model_dump() for page in request.pages], | ||||||||||||||||||||||||||||||||||||||
| repo_url=request.repo_url, | ||||||||||||||||||||||||||||||||||||||
| commit=commit, | ||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+303
to
+307
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pass the
Suggested change
Comment on lines
+303
to
+307
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The PR description mentions that
Suggested change
|
||||||||||||||||||||||||||||||||||||||
| content = json.dumps(payload, indent=2) | ||||||||||||||||||||||||||||||||||||||
| filename = f"{repo_name}_graph_{timestamp}.json" | ||||||||||||||||||||||||||||||||||||||
| media_type = "application/json" | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| if request.publish: | ||||||||||||||||||||||||||||||||||||||
| # Reject explicit `repo` overrides that don't match the | ||||||||||||||||||||||||||||||||||||||
| # derived owner/repo from `repo_url`. Without this an | ||||||||||||||||||||||||||||||||||||||
| # unauthenticated client could trigger a sync-entry | ||||||||||||||||||||||||||||||||||||||
| # dispatch for any registry id once the server is | ||||||||||||||||||||||||||||||||||||||
| # configured with a token. | ||||||||||||||||||||||||||||||||||||||
| if request.repo and derived_owner_repo and request.repo != derived_owner_repo: | ||||||||||||||||||||||||||||||||||||||
| raise HTTPException( | ||||||||||||||||||||||||||||||||||||||
| status_code=400, | ||||||||||||||||||||||||||||||||||||||
| detail=( | ||||||||||||||||||||||||||||||||||||||
| f"`repo` override ({request.repo!r}) does not " | ||||||||||||||||||||||||||||||||||||||
| f"match owner/repo derived from `repo_url` " | ||||||||||||||||||||||||||||||||||||||
| f"({derived_owner_repo!r})." | ||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||
| owner_repo = request.repo or derived_owner_repo | ||||||||||||||||||||||||||||||||||||||
| publish_status = await asyncio.to_thread( | ||||||||||||||||||||||||||||||||||||||
| publish_to_registry, payload, owner_repo=owner_repo | ||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||
| headers["X-Understand-Quickly-Dispatched"] = ( | ||||||||||||||||||||||||||||||||||||||
| "true" if publish_status.get("dispatched") else "false" | ||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||
| if publish_status.get("reason"): | ||||||||||||||||||||||||||||||||||||||
| headers["X-Understand-Quickly-Reason"] = str( | ||||||||||||||||||||||||||||||||||||||
| publish_status["reason"] | ||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+312
to
+337
|
||||||||||||||||||||||||||||||||||||||
| else: # JSON format | ||||||||||||||||||||||||||||||||||||||
| # Generate JSON content | ||||||||||||||||||||||||||||||||||||||
| content = generate_json_export(request.repo_url, request.pages) | ||||||||||||||||||||||||||||||||||||||
| filename = f"{repo_name}_wiki_{timestamp}.json" | ||||||||||||||||||||||||||||||||||||||
| media_type = "application/json" | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # Create response with appropriate headers for file download | ||||||||||||||||||||||||||||||||||||||
| headers["Content-Disposition"] = f"attachment; filename={filename}" | ||||||||||||||||||||||||||||||||||||||
| response = Response( | ||||||||||||||||||||||||||||||||||||||
| content=content, | ||||||||||||||||||||||||||||||||||||||
| media_type=media_type, | ||||||||||||||||||||||||||||||||||||||
| headers={ | ||||||||||||||||||||||||||||||||||||||
| "Content-Disposition": f"attachment; filename={filename}" | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| headers=headers, | ||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| return response | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To fully support the
commitmetadata field in the generated graph (as mentioned in the PR description and implemented inbuild_graph_payload), consider adding acommitfield to theWikiExportRequestmodel. This allows the caller (e.g., a CI workflow or an orchestrator) to provide the specific git SHA associated with the wiki content.