paperlypdf 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- paperlypdf-0.1.0/PKG-INFO +111 -0
- paperlypdf-0.1.0/README.md +97 -0
- paperlypdf-0.1.0/paperlypdf/__init__.py +6 -0
- paperlypdf-0.1.0/paperlypdf/client.py +157 -0
- paperlypdf-0.1.0/paperlypdf.egg-info/PKG-INFO +111 -0
- paperlypdf-0.1.0/paperlypdf.egg-info/SOURCES.txt +9 -0
- paperlypdf-0.1.0/paperlypdf.egg-info/dependency_links.txt +1 -0
- paperlypdf-0.1.0/paperlypdf.egg-info/requires.txt +1 -0
- paperlypdf-0.1.0/paperlypdf.egg-info/top_level.txt +1 -0
- paperlypdf-0.1.0/pyproject.toml +24 -0
- paperlypdf-0.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: paperlypdf
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python client for Paperly — turn prompts or CSV/Excel files into polished, downloadable PDF reports.
|
|
5
|
+
License: MIT
|
|
6
|
+
Project-URL: Homepage, https://saas-pdf-kappa.vercel.app
|
|
7
|
+
Keywords: pdf,report,ai,generator,document,paperly
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Topic :: Office/Business
|
|
11
|
+
Requires-Python: >=3.8
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
Requires-Dist: requests>=2.25
|
|
14
|
+
|
|
15
|
+
# Paperly Python SDK
|
|
16
|
+
|
|
17
|
+
Turn a prompt — or a CSV/Excel file — into a polished, downloadable **PDF report**
|
|
18
|
+
in a few lines of Python. The AI builds a designed, multi-page document
|
|
19
|
+
(table of contents, tables, summary section) and renders it to PDF — no manual
|
|
20
|
+
formatting.
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install paperlypdf
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Quickstart
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from paperlypdf import PaperlyPdf
|
|
30
|
+
|
|
31
|
+
client = PaperlyPdf(api_key="pdf_YOUR_API_KEY")
|
|
32
|
+
|
|
33
|
+
pdf = client.generate_to_pdf(
|
|
34
|
+
"Write a quarterly sales analysis for Q2 2026.",
|
|
35
|
+
length="standard", # concise | standard | in-depth
|
|
36
|
+
output_path="report.pdf",
|
|
37
|
+
)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
That's it — submit, poll, download. `report.pdf` lands on disk.
|
|
41
|
+
|
|
42
|
+
## Data file → PDF report (the killer use case)
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
import csv
|
|
46
|
+
import io
|
|
47
|
+
from paperlypdf import PaperlyPdf
|
|
48
|
+
|
|
49
|
+
client = PaperlyPdf(api_key="pdf_YOUR_API_KEY")
|
|
50
|
+
|
|
51
|
+
def csv_as_text(path):
|
|
52
|
+
with open(path, encoding="utf-8-sig") as f:
|
|
53
|
+
rows = list(csv.DictReader(f))
|
|
54
|
+
out = io.StringIO()
|
|
55
|
+
out.write(f"Source: {path} ({len(rows)} rows)\n\n")
|
|
56
|
+
for row in rows:
|
|
57
|
+
out.write(" | ".join(f"{k}: {v}" for k, v in row.items()))
|
|
58
|
+
out.write("\n")
|
|
59
|
+
return out.getvalue()
|
|
60
|
+
|
|
61
|
+
client.generate_to_pdf(
|
|
62
|
+
"Organize this data into a clean business report with tables, "
|
|
63
|
+
"then add an analysis section with concrete recommendations.",
|
|
64
|
+
file_text=csv_as_text("sales.csv"),
|
|
65
|
+
length="standard",
|
|
66
|
+
output_path="sales_report.pdf",
|
|
67
|
+
)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
For Excel (`.xlsx`) use pandas to read and pass a text representation the same way:
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
import pandas as pd
|
|
74
|
+
client.generate_to_pdf("Summarize this into a clean report.", file_text=pd.read_excel("orders.xlsx").to_string())
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Low-level API
|
|
78
|
+
|
|
79
|
+
| Method | Purpose |
|
|
80
|
+
|---|---|
|
|
81
|
+
| `generate(prompt, length, mode, file_text, clarify, answers)` | Submit a job — returns `jobId` |
|
|
82
|
+
| `get_job(job_id)` | Poll status: `pending` / `running` / `done` / `failed` |
|
|
83
|
+
| `wait(job_id)` | Block until `done` (raises on `failed` or timeout) |
|
|
84
|
+
| `download(job_id, output_path)` | Fetch the finished PDF (bytes) |
|
|
85
|
+
| `generate_to_pdf(...)` | All of the above in one call |
|
|
86
|
+
| `me()` | API-key info: balance, usage, caps |
|
|
87
|
+
|
|
88
|
+
### Handling clarifying questions
|
|
89
|
+
|
|
90
|
+
Pass `clarify=True` and the API may ask questions first:
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
res = client.generate("I need a document about ice cream.", clarify=True)
|
|
94
|
+
if res.get("needsInput"):
|
|
95
|
+
print(res["questions"]) # -> ask the user, then retry with answers:
|
|
96
|
+
res = client.generate("I need a document about ice cream.",
|
|
97
|
+
clarify=True,
|
|
98
|
+
answers=["Tutorial", "Beginner home cooks", "3 sections"])
|
|
99
|
+
job = client.wait(res["jobId"])
|
|
100
|
+
client.download(job["jobId"], "out.pdf")
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Errors
|
|
104
|
+
|
|
105
|
+
Non-2xx responses raise `PaperlyError` with the server's error message. Failed
|
|
106
|
+
jobs raise `PaperlyError` too. Jobs expire after 30 minutes.
|
|
107
|
+
|
|
108
|
+
## Pricing
|
|
109
|
+
|
|
110
|
+
Prepaid, pay-as-you-go: `concise` $0.30 · `standard` $0.30 · `in-depth` $1.00,
|
|
111
|
+
plus $0.10 per 100K characters of file data. No subscription.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Paperly Python SDK
|
|
2
|
+
|
|
3
|
+
Turn a prompt — or a CSV/Excel file — into a polished, downloadable **PDF report**
|
|
4
|
+
in a few lines of Python. The AI builds a designed, multi-page document
|
|
5
|
+
(table of contents, tables, summary section) and renders it to PDF — no manual
|
|
6
|
+
formatting.
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
pip install paperlypdf
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Quickstart
|
|
13
|
+
|
|
14
|
+
```python
|
|
15
|
+
from paperlypdf import PaperlyPdf
|
|
16
|
+
|
|
17
|
+
client = PaperlyPdf(api_key="pdf_YOUR_API_KEY")
|
|
18
|
+
|
|
19
|
+
pdf = client.generate_to_pdf(
|
|
20
|
+
"Write a quarterly sales analysis for Q2 2026.",
|
|
21
|
+
length="standard", # concise | standard | in-depth
|
|
22
|
+
output_path="report.pdf",
|
|
23
|
+
)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
That's it — submit, poll, download. `report.pdf` lands on disk.
|
|
27
|
+
|
|
28
|
+
## Data file → PDF report (the killer use case)
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
import csv
|
|
32
|
+
import io
|
|
33
|
+
from paperlypdf import PaperlyPdf
|
|
34
|
+
|
|
35
|
+
client = PaperlyPdf(api_key="pdf_YOUR_API_KEY")
|
|
36
|
+
|
|
37
|
+
def csv_as_text(path):
|
|
38
|
+
with open(path, encoding="utf-8-sig") as f:
|
|
39
|
+
rows = list(csv.DictReader(f))
|
|
40
|
+
out = io.StringIO()
|
|
41
|
+
out.write(f"Source: {path} ({len(rows)} rows)\n\n")
|
|
42
|
+
for row in rows:
|
|
43
|
+
out.write(" | ".join(f"{k}: {v}" for k, v in row.items()))
|
|
44
|
+
out.write("\n")
|
|
45
|
+
return out.getvalue()
|
|
46
|
+
|
|
47
|
+
client.generate_to_pdf(
|
|
48
|
+
"Organize this data into a clean business report with tables, "
|
|
49
|
+
"then add an analysis section with concrete recommendations.",
|
|
50
|
+
file_text=csv_as_text("sales.csv"),
|
|
51
|
+
length="standard",
|
|
52
|
+
output_path="sales_report.pdf",
|
|
53
|
+
)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
For Excel (`.xlsx`) use pandas to read and pass a text representation the same way:
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
import pandas as pd
|
|
60
|
+
client.generate_to_pdf("Summarize this into a clean report.", file_text=pd.read_excel("orders.xlsx").to_string())
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Low-level API
|
|
64
|
+
|
|
65
|
+
| Method | Purpose |
|
|
66
|
+
|---|---|
|
|
67
|
+
| `generate(prompt, length, mode, file_text, clarify, answers)` | Submit a job — returns `jobId` |
|
|
68
|
+
| `get_job(job_id)` | Poll status: `pending` / `running` / `done` / `failed` |
|
|
69
|
+
| `wait(job_id)` | Block until `done` (raises on `failed` or timeout) |
|
|
70
|
+
| `download(job_id, output_path)` | Fetch the finished PDF (bytes) |
|
|
71
|
+
| `generate_to_pdf(...)` | All of the above in one call |
|
|
72
|
+
| `me()` | API-key info: balance, usage, caps |
|
|
73
|
+
|
|
74
|
+
### Handling clarifying questions
|
|
75
|
+
|
|
76
|
+
Pass `clarify=True` and the API may ask questions first:
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
res = client.generate("I need a document about ice cream.", clarify=True)
|
|
80
|
+
if res.get("needsInput"):
|
|
81
|
+
print(res["questions"]) # -> ask the user, then retry with answers:
|
|
82
|
+
res = client.generate("I need a document about ice cream.",
|
|
83
|
+
clarify=True,
|
|
84
|
+
answers=["Tutorial", "Beginner home cooks", "3 sections"])
|
|
85
|
+
job = client.wait(res["jobId"])
|
|
86
|
+
client.download(job["jobId"], "out.pdf")
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Errors
|
|
90
|
+
|
|
91
|
+
Non-2xx responses raise `PaperlyError` with the server's error message. Failed
|
|
92
|
+
jobs raise `PaperlyError` too. Jobs expire after 30 minutes.
|
|
93
|
+
|
|
94
|
+
## Pricing
|
|
95
|
+
|
|
96
|
+
Prepaid, pay-as-you-go: `concise` $0.30 · `standard` $0.30 · `in-depth` $1.00,
|
|
97
|
+
plus $0.10 per 100K characters of file data. No subscription.
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"""Minimal Python client for the Paperly PDF API.
|
|
2
|
+
|
|
3
|
+
Turn a prompt — or a CSV/Excel file — into a polished, downloadable PDF report.
|
|
4
|
+
|
|
5
|
+
from paperlypdf import PaperlyPdf
|
|
6
|
+
|
|
7
|
+
client = PaperlyPdf(api_key="pdf_...")
|
|
8
|
+
client.generate_to_pdf(
|
|
9
|
+
"Write a quarterly sales analysis for Q2 2026.",
|
|
10
|
+
length="standard",
|
|
11
|
+
output_path="report.pdf",
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
The API is a simple submit → poll → download flow, so nothing fancy is needed
|
|
15
|
+
here: this module just wraps the four endpoints with retries-free polling and
|
|
16
|
+
clean error messages.
|
|
17
|
+
"""
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import time
|
|
21
|
+
from typing import List, Optional, Union
|
|
22
|
+
|
|
23
|
+
import requests
|
|
24
|
+
|
|
25
|
+
__all__ = ["PaperlyPdf", "PaperlyError"]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class PaperlyError(Exception):
|
|
29
|
+
"""Raised when the Paperly PDF API returns an error or a job fails."""
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class PaperlyPdf:
|
|
33
|
+
"""Async job-based client. Submitting returns a jobId immediately; you
|
|
34
|
+
poll with ``wait``/``get_job`` and fetch the finished PDF with ``download``."""
|
|
35
|
+
|
|
36
|
+
def __init__(
|
|
37
|
+
self,
|
|
38
|
+
api_key: str,
|
|
39
|
+
base_url: str = "https://saas-pdf-kappa.vercel.app",
|
|
40
|
+
timeout: int = 60,
|
|
41
|
+
) -> None:
|
|
42
|
+
self.base_url = base_url.rstrip("/")
|
|
43
|
+
self.timeout = timeout
|
|
44
|
+
self._session = requests.Session()
|
|
45
|
+
self._session.headers["Authorization"] = f"Bearer {api_key}"
|
|
46
|
+
self._session.headers["Accept"] = "application/json"
|
|
47
|
+
|
|
48
|
+
# ── low-level ────────────────────────────────────────────────────────────
|
|
49
|
+
def _request(self, method: str, path: str, **kwargs) -> requests.Response:
|
|
50
|
+
url = f"{self.base_url}{path}"
|
|
51
|
+
resp = self._session.request(method, url, timeout=self.timeout, **kwargs)
|
|
52
|
+
if resp.status_code >= 400:
|
|
53
|
+
try:
|
|
54
|
+
msg = resp.json().get("error", resp.text)
|
|
55
|
+
except Exception: # noqa: BLE001 — non-JSON error body
|
|
56
|
+
msg = resp.text
|
|
57
|
+
raise PaperlyError(f"HTTP {resp.status_code}: {msg}")
|
|
58
|
+
return resp
|
|
59
|
+
|
|
60
|
+
# ── endpoints ────────────────────────────────────────────────────────────
|
|
61
|
+
def me(self) -> dict:
|
|
62
|
+
"""Account / API-key info: balance, usage, caps."""
|
|
63
|
+
return self._request("GET", "/api/v1/me").json()
|
|
64
|
+
|
|
65
|
+
def generate(
|
|
66
|
+
self,
|
|
67
|
+
prompt: str,
|
|
68
|
+
length: str = "standard",
|
|
69
|
+
mode: str = "business",
|
|
70
|
+
file_text: Optional[str] = None,
|
|
71
|
+
clarify: bool = False,
|
|
72
|
+
answers: Optional[List[str]] = None,
|
|
73
|
+
) -> dict:
|
|
74
|
+
"""Submit a generation job.
|
|
75
|
+
|
|
76
|
+
Returns ``{"jobId": ...}`` when the job starts. If ``clarify=True`` and
|
|
77
|
+
the prompt is judged vague, returns ``{"needsInput": True, "questions": [...]}``
|
|
78
|
+
instead — pass the answered values back via ``answers`` on a retry.
|
|
79
|
+
"""
|
|
80
|
+
body: dict = {"prompt": prompt, "length": length, "mode": mode, "clarify": bool(clarify)}
|
|
81
|
+
if file_text:
|
|
82
|
+
body["fileText"] = file_text
|
|
83
|
+
if answers:
|
|
84
|
+
body["answers"] = list(answers)
|
|
85
|
+
return self._request("POST", "/api/v1/generate", json=body).json()
|
|
86
|
+
|
|
87
|
+
def get_job(self, job_id: str) -> dict:
|
|
88
|
+
"""Current job state: status (pending/running/done/failed) + step."""
|
|
89
|
+
return self._request("GET", f"/api/v1/jobs/{job_id}").json()
|
|
90
|
+
|
|
91
|
+
def wait(self, job_id: str, poll_interval: float = 3, timeout: float = 900) -> dict:
|
|
92
|
+
"""Poll until the job reaches a terminal state.
|
|
93
|
+
|
|
94
|
+
Jobs expire after 30 minutes; ``timeout`` defaults to 15 min and can be
|
|
95
|
+
raised for very long in-depth generations.
|
|
96
|
+
"""
|
|
97
|
+
deadline = time.time() + timeout
|
|
98
|
+
while True:
|
|
99
|
+
job = self.get_job(job_id)
|
|
100
|
+
status = job.get("status")
|
|
101
|
+
if status == "done":
|
|
102
|
+
return job
|
|
103
|
+
if status == "failed":
|
|
104
|
+
raise PaperlyError(job.get("error") or f"Job {job_id} failed.")
|
|
105
|
+
if time.time() >= deadline:
|
|
106
|
+
raise PaperlyError(f"Timed out after {timeout}s waiting for job {job_id}.")
|
|
107
|
+
time.sleep(poll_interval)
|
|
108
|
+
|
|
109
|
+
def download(self, job_id: str, output_path: Optional[str] = None) -> bytes:
|
|
110
|
+
"""Fetch the finished PDF. Returns raw bytes; writes to ``output_path`` when given."""
|
|
111
|
+
resp = self._request("GET", f"/api/v1/jobs/{job_id}/download")
|
|
112
|
+
content = resp.content
|
|
113
|
+
if output_path:
|
|
114
|
+
with open(output_path, "wb") as f:
|
|
115
|
+
f.write(content)
|
|
116
|
+
return content
|
|
117
|
+
|
|
118
|
+
# ── convenience ──────────────────────────────────────────────────────────
|
|
119
|
+
def generate_to_pdf(
|
|
120
|
+
self,
|
|
121
|
+
prompt: str,
|
|
122
|
+
output_path: Optional[str] = None,
|
|
123
|
+
length: str = "standard",
|
|
124
|
+
mode: str = "business",
|
|
125
|
+
file_text: Optional[str] = None,
|
|
126
|
+
clarify: bool = False,
|
|
127
|
+
answers: Optional[List[str]] = None,
|
|
128
|
+
poll_interval: float = 3,
|
|
129
|
+
timeout: float = 900,
|
|
130
|
+
) -> bytes:
|
|
131
|
+
"""Submit, poll to completion, and download — one call end to end."""
|
|
132
|
+
data = self.generate(
|
|
133
|
+
prompt=prompt,
|
|
134
|
+
length=length,
|
|
135
|
+
mode=mode,
|
|
136
|
+
file_text=file_text,
|
|
137
|
+
clarify=clarify,
|
|
138
|
+
answers=answers,
|
|
139
|
+
)
|
|
140
|
+
if data.get("needsInput"):
|
|
141
|
+
raise PaperlyError(
|
|
142
|
+
f"Clarification needed — call generate(clarify=True) with answers for: "
|
|
143
|
+
f"{data.get('questions')}"
|
|
144
|
+
)
|
|
145
|
+
job = self.wait(data["jobId"], poll_interval=poll_interval, timeout=timeout)
|
|
146
|
+
return self.download(job["jobId"], output_path)
|
|
147
|
+
|
|
148
|
+
def generate_from_text_file(
|
|
149
|
+
self,
|
|
150
|
+
file_path: str,
|
|
151
|
+
prompt: str = "Organize this file's content into a clean, structured document.",
|
|
152
|
+
**kwargs,
|
|
153
|
+
) -> bytes:
|
|
154
|
+
"""Read a plain-text (or CSV) file locally and generate a PDF from it."""
|
|
155
|
+
with open(file_path, encoding="utf-8", errors="replace") as f:
|
|
156
|
+
text = f.read()
|
|
157
|
+
return self.generate_to_pdf(prompt=prompt, file_text=text, **kwargs)
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: paperlypdf
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python client for Paperly — turn prompts or CSV/Excel files into polished, downloadable PDF reports.
|
|
5
|
+
License: MIT
|
|
6
|
+
Project-URL: Homepage, https://saas-pdf-kappa.vercel.app
|
|
7
|
+
Keywords: pdf,report,ai,generator,document,paperly
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Topic :: Office/Business
|
|
11
|
+
Requires-Python: >=3.8
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
Requires-Dist: requests>=2.25
|
|
14
|
+
|
|
15
|
+
# Paperly Python SDK
|
|
16
|
+
|
|
17
|
+
Turn a prompt — or a CSV/Excel file — into a polished, downloadable **PDF report**
|
|
18
|
+
in a few lines of Python. The AI builds a designed, multi-page document
|
|
19
|
+
(table of contents, tables, summary section) and renders it to PDF — no manual
|
|
20
|
+
formatting.
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install paperlypdf
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Quickstart
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from paperlypdf import PaperlyPdf
|
|
30
|
+
|
|
31
|
+
client = PaperlyPdf(api_key="pdf_YOUR_API_KEY")
|
|
32
|
+
|
|
33
|
+
pdf = client.generate_to_pdf(
|
|
34
|
+
"Write a quarterly sales analysis for Q2 2026.",
|
|
35
|
+
length="standard", # concise | standard | in-depth
|
|
36
|
+
output_path="report.pdf",
|
|
37
|
+
)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
That's it — submit, poll, download. `report.pdf` lands on disk.
|
|
41
|
+
|
|
42
|
+
## Data file → PDF report (the killer use case)
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
import csv
|
|
46
|
+
import io
|
|
47
|
+
from paperlypdf import PaperlyPdf
|
|
48
|
+
|
|
49
|
+
client = PaperlyPdf(api_key="pdf_YOUR_API_KEY")
|
|
50
|
+
|
|
51
|
+
def csv_as_text(path):
|
|
52
|
+
with open(path, encoding="utf-8-sig") as f:
|
|
53
|
+
rows = list(csv.DictReader(f))
|
|
54
|
+
out = io.StringIO()
|
|
55
|
+
out.write(f"Source: {path} ({len(rows)} rows)\n\n")
|
|
56
|
+
for row in rows:
|
|
57
|
+
out.write(" | ".join(f"{k}: {v}" for k, v in row.items()))
|
|
58
|
+
out.write("\n")
|
|
59
|
+
return out.getvalue()
|
|
60
|
+
|
|
61
|
+
client.generate_to_pdf(
|
|
62
|
+
"Organize this data into a clean business report with tables, "
|
|
63
|
+
"then add an analysis section with concrete recommendations.",
|
|
64
|
+
file_text=csv_as_text("sales.csv"),
|
|
65
|
+
length="standard",
|
|
66
|
+
output_path="sales_report.pdf",
|
|
67
|
+
)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
For Excel (`.xlsx`) use pandas to read and pass a text representation the same way:
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
import pandas as pd
|
|
74
|
+
client.generate_to_pdf("Summarize this into a clean report.", file_text=pd.read_excel("orders.xlsx").to_string())
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Low-level API
|
|
78
|
+
|
|
79
|
+
| Method | Purpose |
|
|
80
|
+
|---|---|
|
|
81
|
+
| `generate(prompt, length, mode, file_text, clarify, answers)` | Submit a job — returns `jobId` |
|
|
82
|
+
| `get_job(job_id)` | Poll status: `pending` / `running` / `done` / `failed` |
|
|
83
|
+
| `wait(job_id)` | Block until `done` (raises on `failed` or timeout) |
|
|
84
|
+
| `download(job_id, output_path)` | Fetch the finished PDF (bytes) |
|
|
85
|
+
| `generate_to_pdf(...)` | All of the above in one call |
|
|
86
|
+
| `me()` | API-key info: balance, usage, caps |
|
|
87
|
+
|
|
88
|
+
### Handling clarifying questions
|
|
89
|
+
|
|
90
|
+
Pass `clarify=True` and the API may ask questions first:
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
res = client.generate("I need a document about ice cream.", clarify=True)
|
|
94
|
+
if res.get("needsInput"):
|
|
95
|
+
print(res["questions"]) # -> ask the user, then retry with answers:
|
|
96
|
+
res = client.generate("I need a document about ice cream.",
|
|
97
|
+
clarify=True,
|
|
98
|
+
answers=["Tutorial", "Beginner home cooks", "3 sections"])
|
|
99
|
+
job = client.wait(res["jobId"])
|
|
100
|
+
client.download(job["jobId"], "out.pdf")
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Errors
|
|
104
|
+
|
|
105
|
+
Non-2xx responses raise `PaperlyError` with the server's error message. Failed
|
|
106
|
+
jobs raise `PaperlyError` too. Jobs expire after 30 minutes.
|
|
107
|
+
|
|
108
|
+
## Pricing
|
|
109
|
+
|
|
110
|
+
Prepaid, pay-as-you-go: `concise` $0.30 · `standard` $0.30 · `in-depth` $1.00,
|
|
111
|
+
plus $0.10 per 100K characters of file data. No subscription.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
requests>=2.25
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
paperlypdf
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "paperlypdf"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Python client for Paperly — turn prompts or CSV/Excel files into polished, downloadable PDF reports."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
keywords = ["pdf", "report", "ai", "generator", "document", "paperly"]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Programming Language :: Python :: 3",
|
|
15
|
+
"License :: OSI Approved :: MIT License",
|
|
16
|
+
"Topic :: Office/Business",
|
|
17
|
+
]
|
|
18
|
+
dependencies = ["requests>=2.25"]
|
|
19
|
+
|
|
20
|
+
[project.urls]
|
|
21
|
+
Homepage = "https://saas-pdf-kappa.vercel.app"
|
|
22
|
+
|
|
23
|
+
[tool.setuptools.packages.find]
|
|
24
|
+
include = ["paperlypdf*"]
|