Spaces:
Runtime error
Runtime error
Commit History
-
Feat: capture inbox (Phase B) β phone captures merge into the libraryβ
/capture with a token enqueues place(s) into an ephemeral, TTL'd in-memory inbox. New POST /capture-inbox/{token} drains a token's captures and merges them into the caller's library (reuses the living-library _merge_rows) β returns a fresh job like /import. Client _pullCaptureInbox() drains on load and shows "π² N places captured from your phone" with β¨ New badges; a #capture-setup card in the import card surfaces the token (localStorage). Fixes an empty-multipart-body 400 by always sending merge_into (even ""). tests/test_capture.py extended (enqueue, drain+merge, idempotency, status preserved); visual review of the setup card + full round-trip at mobile/desktop. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>eda6c91 -
Feat: living-library merge polish (Phase 3)β
- /import returns added_urls + kept; merge_rows now returns the added rows. - Client tags freshly-merged places (row._isNew) β a "β¨ New" card badge, floats them to the top of Browse (stable, transient β resets on reload). - Merge banner reports "N new Β· M already in your library". - Import card gains a Merge/Replace radio (#import-mode), shown only when a cached library exists; a zero-overlap merge still offers Replace inline. Completes the living-library feature (Phases 1β3). Visual review at mobile + desktop; tests/test_merge.py extended (added_urls/kept) and green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>f981d71 -
Feat: living-library cost-skip on re-extract (Phase 2)β
POST /upload now accepts merge_into (the cached library CSV). _run_pipeline seeds it as the job's places_full.csv and runs extract.run(resume=True), so _warm_start_from_csv skips the LLM on posts already in the library (keyed on instagram_url). new_urls excludes known posts, so the cost estimate and progress message reflect only genuinely new ones ("X already in your library, skipped"). After extraction the result is folded back with _merge_rows (keep-existing-wins) so known posts keep status/coords and any place the new export omitted is re-added. Client sends the cached library on the Extract upload. tests/test_merge.py gains a warm-start section that patches extract.analyze_batch to prove known posts never reach the LLM and keep their visited status. A 600-post re-export where 550 are already mapped now only pays to extract the 50 new ones. Phase 3 (polish) is next. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>1a26356 -
Feat: living-library merge on import (Phase 1)β
POST /import now accepts an optional merge_into field (the caller's existing library CSV). The uploaded file is folded into it server-side via _merge_rows, keyed on instagram_url (else normalized name|city), keep-existing-wins β so user-owned status and manual edits are never overwritten and only genuinely new posts are added. Response gains added/merged/no_overlap. Client (importPlacesFile) sends the cached localStorage library as merge_into (unless restoring, which forceReplaces), shows an "N new places added" banner, and offers Replace when nothing in the file matched the library. Also fixes the restore card lingering after a library loads (showSubTabBar now hides it). This is the linchpin of the hybrid plan β it's what lets a capture/Shortcut or a re-import grow one living map instead of replacing it. Pinned by tests/test_merge.py (added to CI guardrails). Phase 2 (server-side warm-start cost-skip for bulk re-export) is next. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.cβ¦d1b556d -
Feat: flush pending library cache on tab background/closeβ
Adds flushCache() wired to visibilitychangeβhidden + pagehide so a status/ field/coord edit made within the ~1.5s debounce window is persisted to localStorage before the user leaves, instead of being lost. Also prunes completed items from TODO.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>90d15a0 -
Feat: client-side library persistence (localStorage restore card)β
Cache the canonical CSV in the browser after load and write-through on every edit (status, fields, coords). A returning visitor with no live job sees a #restore-card that replays the cached CSV through /import β a pure reconstruction-cache, so status/coords/edits round-trip losslessly with no new data shape and no server change. Stored only on-device; Download stays the durable backup. Works in both deployment modes (no HOSTED branch). - app.js: importPlacesFile() refactored out of handleImportFile; cacheLibrary/ cacheLibrarySoon/maybeShowRestore + restore/forget handlers; quota note - index.html + app.css: #restore-card above the import card - tests/test_persistence.py: cache/restore round-trip is lossless (CI guardrail) - docs: README, CLAUDE.md, TODO (item marked done; IndexedDB deferred) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>1c43cdb
-
Docs: split Instagram export guide into desktop + mobile stepsβ
Harshith Belagur +1: ClaudeThe "How to get your Instagram file" guide, FAQ entry, and README only documented one entry path (phrased for the app). Split each into a π» computer (instagram.com) flow and a π± Instagram app flow, sharing the common Accounts Center β Download your information steps. Adds an .export-platform heading style for the two labeled blocks in the Extract tab. Co-Authored-By: Claude <noreply@anthropic.com>08d1d42 -
Feat: single Instagram URL extraction via CAPTION_PROXY_URLβ
Re-adds the URL input on the Extract tab. Caption fetch now routes through a configurable proxy (CAPTION_PROXY_URL) on hosted builds β default allorigins.win requires no account. Local Docker skips the proxy and uses yt-dlp + direct OG scraping instead. pipeline/transcribe.py: fetch_post_metadata gains proxy_url param; _fetch_via_proxy handles allorigins.win JSON response format. web/app.py: _run_url_pipeline + /extract-url + /url-chatbot-prepare restored; reads CAPTION_PROXY_URL from env. deploy/hosted.env.example: CAPTION_PROXY_URL=https://api.allorigins.win/get TODO.md: P0 item for server-side video transcription; URL item updated. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>56b50ce -
Revert: remove single Instagram post URL featureβ
Removed the URL input from the Extract tab, all backend routes (/extract-url, /url-chatbot-prepare), JS logic, CSS, and the fetch_post_metadata/OG scraping helpers from transcribe.py. Root cause: yt-dlp needs --cookies-from-browser for Instagram auth (works locally, not on a hosted server). Tracked in TODO.md as a potential local-only CLI flag (--url) instead. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>425566e -
Fix: API key gate for URL mode; faster timeouts; better network error messageβ
Three issues addressed: 1. "Extract now β" was enabled without an API key on hosted deploys. Added data-has-server-key body attr; _syncUrlModeButtons() now disables the button with "Enter API key above to continue" when Anthropic is selected and neither a server key nor a typed key is present. Re-checks on every keystroke in the API key field. 2. Both yt-dlp and OG scraping were timing out on HF Spaces (Instagram is likely blocked from HF's network). Reduced timeouts: yt-dlp 15s, OG HTTP 8s, so failures surface quickly rather than hanging for 30s+. OG scrape tries two SSL contexts before giving up. 3. When both fetches fail, the error now says "try the free chatbot mode instead" since that path only needs the caption pasted by the user. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>0c8fe05 -
Feature: chatbot (free) mode works for single URL extractionβ
Fetches the post caption server-side (yt-dlp / OG scraping, no API key), wraps it as a single-post chatbot export, and hands off to the existing chatbot-step2 UI β same download JSON + copy prompt + paste response flow as the full-export chatbot path. - POST /url-chatbot-prepare: fetch caption β chatbot_mod.prepare_export([post]) - app.js: chatbot+URL shows "Prepare extraction file β"; clicking it calls /url-chatbot-prepare and populates chatbot-step2 without touching the existing file-based chatbot flow - _syncUrlModeButtons() centralises run-btn vs chatbot-prepare-btn visibility for URL mode so setProvider() stays clean Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>42e5a24 -
Fix: add yt-dlp to web requirements; block chatbot+URL modeβ
Two HF Spaces bugs: 1. yt-dlp was commented-out/optional β not installed in the Docker image. Added to requirements-web.txt so it's always present on web deploys. 2. Entering a URL while chatbot provider was active hid the prepare button, showed run-btn, then silently submitted as anthropic without a key and failed. Now URL mode blocks run-btn with an explanatory message when chatbot is selected, and setProvider() respects URL mode state when the provider is changed after a URL has been typed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>47dfeed -
Feature: extract a single place from an Instagram post URLβ
Users can now paste any https://www.instagram.com/p/β¦ URL directly in the upload card as an alternative to the full export ZIP. yt-dlp fetches the post caption and optional geotag server-side, the same LLM extraction + geocode + KML export pipeline runs on the result, and progress is streamed via the existing SSE flow β no new UI states needed. - pipeline/transcribe.py: fetch_post_metadata() uses yt-dlp --dump-json - web/app.py: _run_url_pipeline() + POST /extract-url route - index.html: URL input field + "or paste a single post URL" divider - app.js: URL mode β typing a valid IG URL enables the run button, clears any pending file; selecting a file exits URL mode - app.css: .url-or-divider and .url-input-row styles Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>714e84b
-
UX: footer copy, mobile hero stack, visual review workflowβ
- Footer: "Open source β star it, fork it, break it, fix it, make it yours. Contribute on GitHub β" - Hero stacks vertically on mobile (β€480px): full-width Watch demo button below copy - CLAUDE.md: document required visual review (Playwright 390/768/1280px) before every front-end commit Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>bc8eb05 -
Fix: footer centering and visited link colorβ
Add max-width + margin:auto so footer aligns with card content, not the page edge. Add a:visited rule to prevent browser-default purple link color. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>311b263 -
UX: remove docker note from hero, add OSS footerβ
- Hero card is back to clean copy + button only; Docker info lives in the FAQ where it belongs - Add #site-footer: "Open source β contribute on GitHub β", border-top, muted text, full-width Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>fada9fe -
Fix: demo hero layout β nested structure fixes copy collapse and docker note rowβ
Wraps copy+button in .demo-hero-main (flex row) inside #demo-hero (flex column) so the docker note reliably sits below as its own full-width row. Previously all three siblings were in a flat flex row, causing the copy to collapse into a narrow word-wrap column. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>8822e0c -
UX: fix demo hero font sizes and docker note copyβ
- Remove hardcoded 0.85rem from strong (inherits body default), bump span to 0.88rem and docker note to 0.82rem so the hero reads consistently with the rest of the UI - Reword docker strip to "Want to run it locally? Docker version on GitHub" β avoids implying only Docker is free Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>bdaa9fe -
UX: Docker nudge on landing, FAQ item, Ollama-aware tour stepβ
- Add `.demo-docker-note` strip inside `#demo-hero` linking to GitHub repo for self-hosting with Docker - Add FAQ item "Can I run this fully offline and free with Docker?" (after AI models FAQ) - Tour model-picker step (`model-card`) is now Ollama-aware: on hosted (`OLLAMA_ENABLED=false`) the Ollama option is omitted; `body` can be string or function - Update README.md and CLAUDE.md to document all three changes Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>7d20eac -
Fix: Escape key closes the demo tourβ
Wire keydown Escape to endTour() so users can exit at any step (previously only the β button and overlay-click worked; Escape only closed the feedback modal). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>44d956c -
UX: floating feature-request button β pre-filled GitHub issueβ
- Floating π‘ pill button (bottom-right, z-index 9000, safe-area-inset aware for iOS) - Click opens a modal (title + details fields, slide-in animation, Escape / overlay-click to dismiss) - Submit constructs issues/new?labels=enhancement&title=β¦&body=β¦ and opens in new tab - Collapses to emoji-only below 480 px so it doesn't crowd mobile screens Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>9f1919e -
UX: demo tour with dummy data, hero placement on landing pageβ
- tour.js: inject 8 real-world demo places (Tokyo/London/Paris/LA/Bangkokβ¦) into allRows so users see a fully populated Roulette pick, Browse grid with Leaflet map, and download bar β no upload needed - HTML: move tour trigger from FAQ tab to a #demo-hero card between the header and the nav (βΆ Watch demo) - app.css: replace .tour-cta-card with #demo-hero styles; tour state is fully restored on exit Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>3e19b3d -
UX: add guided tour, pipeline timing noteβ
- tour.js: 6-step spotlight tour (upload β model β run β reimport β roulette β pipeline diagram); simulates tab navigation and temporarily reveals sub-tab-bar in demo mode; triggered by βΆ Take the tour button in FAQ - Progress card: static timing note ("usually 5β10 min β may appear stuck") so users don't abandon a running job - app.css: tour overlay/spotlight/tooltip styles + .progress-timing-note + .tour-cta-card/.btn-tour Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>5c44de2 -
UX: add FAQ tab with pipeline diagram, About, and accordion FAQβ
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>23dabb1 -
UX: remove quality scores from model cardsβ
Scores were mostly dashes (β) for newer models and added noise rather than signal. Cards now show only the cost estimate. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>2a30ad3 -
UX: stop auto-opening export guide when drop zone is clickedβ
The guide was popping open every time a user clicked the drop zone to upload a file, which was disruptive. It stays closed unless the user explicitly opens it via the <details> toggle. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>8e8ea27 -
UX: run button says 'Extract now β' once a valid file is chosenβ
Previously stayed 'Choose a file to continue' even after a file was successfully validated, which was confusing after entering an API key. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>6fe5d5b -
Fix: roulette location search matches city OR country; strip UNKNOWN from displayβ
- /roulette city filter now matches r.city OR r.country (case-insensitive), so typing "United States" or "Japan" returns places from that country - Roulette datalist populated with both city names and country names so autocomplete suggestions appear for either - Label changed from "City trip:" to "Location:" with placeholder "city or country" - pick-loc display filters out "UNKNOWN" values (same guard already applied to category/cuisine/price in metaParts) - TODO.md: document confirmed KML city-level hierarchy breakage in Google My Maps Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>a2095dc -
Fix: remove #roulette-section { display:none } β roulette panel was blankβ
Leftover CSS rule permanently hid the roulette card content regardless of the sub-panel active state. Visibility is handled by .sub-panel.active now. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>ccd6e8c -
UX: drop Exports tab, auto-spin Roulette on first visitβ
- Remove the Exports sub-tab entirely β it was a one-shot action poorly placed as a dedicated tab. Download buttons (KML / GeoJSON / CSV) and the Google My Maps instructions now live in a #download-bar at the top of Browse, revealed when showSubTabBar() fires. - Roulette now auto-spins on first visit: showSubTab('roulette') triggers spin-btn.click() if #pick-card is still hidden. Subsequent tab switches don't re-spin (card is already visible). - Clean up orphaned success-block / success-ring CSS (no longer used). - Update test_routes.py: assert no exports tab, assert download-bar is inside the explore panel. - CLAUDE.md + README.md updated to reflect two-sub-tab nav. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>36362ca
-
Web UI: two-tier nav β Extract / Explore tabs visible from landingβ
Top nav (always sticky): [π₯ Extract] [πΊ Explore] - Extract tab: full pipeline UI (upload, model picker, run, progress) - Explore tab: KML/CSV import card; once data loads a sub-tab bar appears with [β¬ Exports] [π² Roulette] [π Browse] After extraction β auto-jump to Explore β Roulette (nudge toast). After KML/CSV import β Explore β Browse. οΌ New button switches back to Extract tab (no page reload). Clean up TASKS.md (remove completed phases) and TODO.md (remove all completed items, keep only open work). All 24 e2e + 14 structural + 2 guardrail tests pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>383680a -
Revert session restore: import card is the right returning-user flowβ
The server-ping restore banner was over-engineered β job data expires after 24h anyway and returning users naturally drop their KML/CSV into the always- visible import card to get straight to Roulette/Browse. Removed _restoreSession IIFE, #restore-banner HTML, and all associated CSS/JS. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>519bd6d -
Web UI: session restore for returning users + food-only filterβ
Returning users: showTabBar() now persists lastJobId to localStorage. On page load, _restoreSession() pings /results/{id}; if data is alive a #restore-banner offers Resume / Start fresh β no re-upload needed. Food-only filter: FOOD_CATEGORIES (Restaurant, Bar, Cafe, Bakery, Market) defined in both app.js and web/app.py. filterState.foodOnly defaults ON (persisted in localStorage). applyFilters() gates the Browse grid + map; /roulette accepts food_only=true and filters server-side. Toggle chip #food-toggle in the filter bar; active state kept in sync by applyFilters(). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>facc20d -
Web UI: Phase 4 tab-bar UX polishβ
- Tab badges: gradient pill (ig1βig3), hidden via CSS :empty + explicit display:none when count is 0 so empty pills never render - Stat strip: shows ~$X.XX cost alongside places/pinned when non-zero - Mobile: -webkit-overflow-scrolling:touch on .tab-bar-inner for iOS momentum scroll Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>89f8c84 -
Web UI: tab-bar SPA, KML/CSV import, refactor index.htmlβ
Three-tab SPA (Exports | Roulette | Browse) replaces the post-extraction long scroll. Roulette is the default tab after extraction (with nudge toast); Browse is the default after import. Tab badges show unvisited/total counts. KML/CSV import card (always visible before extraction) lets returning users skip re-extraction entirely β POST /import parses places_map.kml or places_full.csv and returns a job immediately at step "done". Refactored index.html: CSS β web/static/app.css, JS β web/static/app.js. Template drops from 2553 β 465 lines; Jinja vars passed via body data-* attributes. FastAPI serves static/ via StaticFiles mount. All 24 e2e tests pass; deployment-mode and prefilter guardrails unchanged. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>74aafdd