Skip to main content

Endoc SDK: A note-taking app SDK powered by LLMs

Project description

Endoc SDK Logo

Powered by Endoc

Endoc SDK

Endoc SDK is a Python library for advanced paper search, PDF import, summarization, and note management via a GraphQL API. It uses Pydantic for data validation, returning all responses as typed Python objects.

Features

  • PDF Import: Upload local PDFs (single file, multiple files, or entire folders) with auto-fetched full paper data including title, authors, abstract, parsed sections, and references.
  • Document Search: Search and filter papers using ranking variables and keywords.
  • Single Paper: Retrieve detailed paper data by ID from any collection.
  • Paginated Search: Retrieve paginated search results with highlighting.
  • Summarization: Generate summaries for individual papers.
  • Title Search: Find papers by title.
  • Note Library: Retrieve papers associated with a note.
  • Custom Services: Extend the client with your own composite functions.

Installation

pip install endoc

Setup

  1. Obtain your API key at endoc.ethz.ch:

    • Sign up with your Switch Edu-ID credentials.
    • Go to AccountDeveloper APIGenerate.
    • Copy the API key.
  2. Create a .env file in your project root:

    ENDOC_API_KEY=your_api_key_here
    
  3. Load environment variables:

    pip install python-dotenv
    
    from dotenv import load_dotenv
    load_dotenv()
    
  4. Instantiate the client:

    from endoc import EndocClient
    
    client = EndocClient(api_key="your_api_key_here")
    # or, if ENDOC_API_KEY is set in .env:
    client = EndocClient(api_key=None)
    
  5. (Optional) Override the GraphQL endpoint:

    ENDOC_GRAPHQL_URL=http://localhost:9000/graphql
    

    The SDK resolves the URL in this order: ENDOC_GRAPHQL_URLSTAGING_GRAPHQL_URLPROD_GRAPHQL_URLhttps://endoc.ethz.ch/graphql.

Usage

PDF Import

Upload PDFs and get back rich paper objects with full metadata, parsed sections, and references.

from endoc import EndocClient

client = EndocClient(api_key="your_key")

# Single file
result = client.import_pdf(path="paper.pdf")

# Multiple files
result = client.import_pdf(paths=["paper1.pdf", "paper2.pdf"])

# Entire folder
result = client.import_pdf(folder="Papers/", recursive=True)

# Access the result
print(result.status)       # "success"
print(len(result.papers))  # number of uploaded papers

paper = result.papers[0]
print(paper.title)         # "Enhancing Academic Networking..."
print(paper.authors)       # [Author(GivenName="Grigor", FamilyName="Dochev"), ...]
print(paper.sections)      # list of parsed sections
print(paper.references)    # list of extracted references
print(paper.fullbody)      # raw full body text
print(paper.abstract)      # abstract text
print(paper.doi)           # DOI string
print(paper.year)          # publication year

Parameters:

Parameter Type Default Description
path str | Path Single PDF file path
paths list List of PDF file paths
folder str | Path Directory containing PDFs
base64_list list Raw base64-encoded PDF strings
recursive bool False Scan subfolders (folder mode)
max_file_mb int 50 Skip files larger than this
batch_size int 10 Upload in batches of this size
include_references bool False Include matched reference papers

Return type: ImportResult with .status, .message, .papers (list of ImportedPaper), and .bookmarks (raw bookmark IDs).

Document Search

result = client.document_search(
    ranking_variable="BERT",
    keywords=["AvailableField:Content.Fullbody_Parsed"],
)

print(result.status)
print(result.response.search_stats.nMatchingDocuments)

for paper in result.response.paper_list[:5]:
    print(f"{paper.collection}/{paper.id_value}")

Single Paper

Retrieve full paper data by ID. Works with any collection (S2AG, PMCOA, UserUploaded, etc.).

# From Semantic Scholar
result = client.single_paper("221802394")
print(result.response.Title)

# From a user-uploaded paper
result = client.single_paper(
    id_value="1001",
    collection="UserUploaded",
    id_field="id_int",
    id_type="int",
)
print(result.response.Title)
print(result.response.Content.Fullbody_Parsed)

Paginated Search

result = client.paginated_search(
    paper_list=[{
        "collection": "S2AG",
        "id_field": "id_int",
        "id_type": "int",
        "id_value": "221802394",
    }],
    keywords=["machine learning"],
)

print(result.status)
print(len(result.response))

Summarize Paper

result = client.summarize("221802394")

print(result.status)
for sentence in result.response:
    print(f"[{sentence.tag}] {sentence.sentence_text}")

Title Search

result = client.title_search(titles=["Attention Is All You Need"])

for paper in result.response:
    if paper.found:
        print(f"{paper.Title}{paper.collection}/{paper.id_value}")

Note Library

Retrieve papers associated with a note. Find your note ID from the URL, e.g. https://endoc.ethz.ch/note/679a1e2e5b25cf001a7c7157679a1e2e5b25cf001a7c7157.

result = client.get_note_library("679a1e2e5b25cf001a7c7157")

for paper in result.response:
    print(f"{paper.id_collection}/{paper.id_value}")

Extending the Client

Using the decorator

from endoc import register_service

@register_service("combined_search")
def combined_search(self, paper_list, id_value):
    paginated = self.paginated_search(paper_list, keywords=["example"])
    single = self.single_paper(id_value)
    return {"paginated": paginated, "single": single}

result = client.combined_search(paper_list, "221802394")

Using the method

def my_search(paper_list, id_value):
    paginated = client.paginated_search(paper_list, keywords=["custom"])
    single = client.single_paper(id_value)
    return {"paginated": paginated, "single": single}

client.register_service("my_search", my_search)
result = client.my_search(paper_list, "221802394")

Package Structure

endoc/
├── __init__.py
├── client.py              # Low-level GraphQL API client
├── decorators.py          # @register_service decorator
├── endoc_client.py        # High-level EndocClient with all methods
├── exceptions.py          # SDK exception hierarchy
├── queries.py             # GraphQL queries and mutations
├── utils.py               # Shared utilities
├── models/
│   ├── document_search.py
│   ├── note_library.py
│   ├── paginated_search.py
│   ├── pdf_import.py      # ImportResult, ImportedPaper, ImportedBookmark
│   ├── single_paper.py
│   ├── summarization.py
│   └── title_search.py
└── services/
    ├── document_search.py
    ├── get_note_library.py
    ├── paginated_search.py
    ├── pdf_import.py
    ├── single_paper_search.py
    ├── summarization.py
    └── title_search.py

Environment Variables

Variable Required Description
ENDOC_API_KEY Yes Your Endoc API key
ENDOC_GRAPHQL_URL No Override the GraphQL endpoint

Testing

pip install pytest
python -m pytest

Tests are in tests/unit/ with fixtures in tests/fixtures/. Shared setup lives in tests/conftest.py.

Contributing

Contributions are welcome. Please open issues or submit pull requests on the GitHub repository. Include tests for any new functionality.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

endoc-1.8.0.tar.gz (16.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

endoc-1.8.0-py3-none-any.whl (19.7 kB view details)

Uploaded Python 3

File details

Details for the file endoc-1.8.0.tar.gz.

File metadata

  • Download URL: endoc-1.8.0.tar.gz
  • Upload date:
  • Size: 16.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for endoc-1.8.0.tar.gz
Algorithm Hash digest
SHA256 93580bef0fb68fabf5d8658363f0741e6c9a1e0ceb5beffda57b5bb6d5af5254
MD5 1a8254db867290ce17a199afed24e48a
BLAKE2b-256 28b87dfa929094d9f336cf51d5fb7e4f7c5a58f777df7fbb4c1572a0747ae159

See more details on using hashes here.

Provenance

The following attestation bundles were made for endoc-1.8.0.tar.gz:

Publisher: python-publish.yml on science-editor/endoc-sdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file endoc-1.8.0-py3-none-any.whl.

File metadata

  • Download URL: endoc-1.8.0-py3-none-any.whl
  • Upload date:
  • Size: 19.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for endoc-1.8.0-py3-none-any.whl
Algorithm Hash digest
SHA256 69fe4f492c2970343d24b918af409efce7349195b2459e149ec9546d71cdf8dd
MD5 6351008c933a9c42e423959f7b185fce
BLAKE2b-256 6b05342fe0bb0aa231da1c43f99d8c725cc18f40a01f3f619a2c8002f643d9bd

See more details on using hashes here.

Provenance

The following attestation bundles were made for endoc-1.8.0-py3-none-any.whl:

Publisher: python-publish.yml on science-editor/endoc-sdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page