Convert uploaded .xlsx files to csv artifacts server-side
Uploading a .xlsx file no longer becomes a generic downloadable binary -
it's read server-side with openpyxl and converted to a csv artifact,
rendering in the same interactive grid as a native CSV post. Detected by
content type or .xlsx extension (some clients send generic/incorrect
content types for multipart uploads). Only the active sheet converts;
formula cells use whatever cached result the spreadsheet software last
saved (openpyxl doesn't evaluate formulas itself). Corrupt/unreadable
files return 400.
Since the existing posting script already forwards any non-text file via
multipart with no special-casing, `daybook_post.py balance_sheet.xlsx`
already works with zero script changes - verified live.
Two real bugs found and fixed while building this, both now covered by
regression tests:
- {**a_querydict, ...} silently wrapped every value (including title) in
a list - Python's ** spread on a dict subclass bypasses QueryDict's
__getitem__ override and exposes its internal one-list-per-key storage
directly. Fixed by building the delegated dict explicitly via .get().
- Pre-setting None for absent optional fields (e.g. source_prompt) defeated
create_text_artifact's own data.get(field, default) calls, since .get()
only falls through to its default when the key is *missing*, not when
the value is None - caused a NOT NULL constraint failure. Fixed by only
setting keys that were actually provided.
- csv.writer's default "\r\n" terminator was getting doubled by
Path.write_text()'s own newline translation on Windows, producing a
blank line between every row. Fixed with lineterminator="\n".
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
4145c37dfe
commit
4b5ec09ae2
6 changed files with 232 additions and 6 deletions
26
docs/api.md
26
docs/api.md
|
|
@ -226,14 +226,38 @@ Required fields:
|
|||
| `title` | Required. |
|
||||
| `file` | Required file part. |
|
||||
|
||||
File kind is inferred from content type:
|
||||
File kind is inferred from content type (or file extension for `.xlsx`):
|
||||
|
||||
| Content type | Artifact kind |
|
||||
|---|---|
|
||||
| `image/*` | `image` |
|
||||
| `application/pdf` | `pdf` |
|
||||
| `.xlsx` (by content type or extension) | `csv` — converted server-side, see below |
|
||||
| Anything else | `binary` |
|
||||
|
||||
### `.xlsx` Upload → `csv` Kind
|
||||
|
||||
Uploading a `.xlsx` file doesn't create a `binary` artifact — it's read
|
||||
server-side (`openpyxl`) and converted into a `csv` artifact, so it renders
|
||||
in the same interactive grid view as a native CSV post. Known limitations:
|
||||
|
||||
- Only the workbook's **active sheet** is converted; other sheets in a
|
||||
multi-sheet workbook are silently dropped.
|
||||
- Formula cells use the **cached result** the spreadsheet application last
|
||||
calculated and saved, not a live re-evaluation — a workbook that's never
|
||||
actually been opened/calculated in real spreadsheet software (e.g. one
|
||||
built by a script that never triggered calculation) will show those cells
|
||||
blank.
|
||||
- Legacy `.xls` (pre-2007 binary format) is **not** supported, only modern
|
||||
`.xlsx`.
|
||||
- Rich spreadsheet formatting (bold, colors, merged cells, multi-level
|
||||
headers) is not preserved — like any `csv` artifact, it renders as a
|
||||
plain sortable/searchable table. If preserving that formatting matters
|
||||
more than interactivity, post as `html_fragment` with a hand-built
|
||||
`<table>` instead.
|
||||
|
||||
A corrupt or unreadable `.xlsx` file returns `400`.
|
||||
|
||||
PowerShell/curl example:
|
||||
|
||||
```powershell
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue