Spaces:
Runtime error
Runtime error
Commit History
-
Fix language selector: wire user choice through to generatorβ
webmuppet +1: Claude Sonnet 4.6Three-layer fix: - pipeline.py: run_query_retrieval accepts an explicit language param; uses it for the response language while still auto-detecting the source language for query translation (can't translate from 'mi' if the text is English) - generator.py: language instruction now says 'user has selected X as their response language' rather than 'user asked in another language', which was wrong when the query was typed in English; imports get_language_name for the human-readable label - server.py: passes body.language through to run_query_retrieval - prompts/generator_system.md: clarifies that an explicit language instruction in the messages takes precedence over the English default Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>016503a
-
Saved responses: store just the pair, not the full threadβ
webmuppet +1: Claude Opus 4.7 (1M context)Previously save_response captured st.session_state.messages[:i+1] β every message leading up to the saved Q&A. Clicking a saved response restored that entire thread into the chat, which contradicted the 'one save per question' mental model the user wanted. New shape: each saved record holds messages_pair (2 entries: user q, assistant a) and history_pair (the same exchange in the LLM-history shape). The single result dict sits flat on the record. Restoring loads just those two messages into a fresh conversation_id β new questions fork from that pair as the only context. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>baa1903 -
Saved Responses: per-Q&A bookmarks with fork-on-clickβ
webmuppet +1: Claude Opus 4.7 (1M context)Replaces the per-message .md download with an in-app save that bookmarks that Q&A pair into a new sidebar section. Clicking a saved response forks the conversation β restores the snapshot context under a fresh conversation_id, leaving the original conversation untouched. The sidebar now has three vocabularies: - Save (in-app, Q&A pair β sidebar) - Saved Responses (the section holding them) - Download saved responses (aggregate β single .md file) - Recent conversations (renamed from Past conversations) Save is idempotent on (conversation_id, msg_index) β re-clicking the same Q&A is a no-op; the button renders 'Saved β' (disabled) once saved. Storage lives in a separate localStorage key (hmc-saved-responses) so conversation schema changes don't risk corrupting bookmarks. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>2260b35
-
Fix past-conversation delete (zombie bug) + title ellipsisβ
webmuppet +1: Claude Opus 4.7 (1M context)Two bugs fixed: 1. Delete didn't actually remove from localStorage. Root cause was the streamlit-js-eval st.rerun() race: calling st.rerun() inside the click handler aborted the script before the component was sent to the frontend, so the JS that writes to localStorage never executed. UI looked correct (cache mutation) but on browser refresh the deleted conversation came back from localStorage as a 'zombie'. Fix: deferred-write pattern. queue_delete() stashes the id on session_state, click handler reruns for UI, and the next render calls process_pending() at the top β which runs the actual delete + write inside a render that completes normally. The component sends to the frontend, JS executes, localStorage updates. 2. Past-conversation titles were hard-cut without ellipsis. text-overflow:ellipsis was on the button, but Streamlit wraps button labels in an inner div/p β the overflowing text node was the inner element, not the button. Moved β¦71d5674 -
Fix persistence: bypass streamlit-js-eval's broken set_local_storageβ
webmuppet +1: Claude Opus 4.7 (1M context)streamlit-js-eval 1.0.0 builds set_local_storage's JS as: localStorage.setItem('key', '<your-value>') β single-quoted, no escaping. Any apostrophe in the value (very common in compliance answers: 'I'll', 'you're', 'doesn't') breaks the JS string literal, raising 'Uncaught SyntaxError: missing ) after argument list' inside the iframe. The save silently fails; nothing lands in localStorage. Confirmed via console log from the user's session β every save was emitting a SyntaxError on the apostrophe in the assistant's response. Workaround: bypass the helper, call streamlit_js_eval directly, build the JS with json.dumps(json.dumps(value)) β the inner dumps produces our payload, the outer dumps wraps it as a JS-safe string literal with all special characters escaped. This was the root cause of all the persistence failures in this session, not the bootstrap_load cache logic and not the iframe hiding. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>59d97a8 -
Fix persistence: don't cache first-render None as 'loaded'β
webmuppet +1: Claude Opus 4.7 (1M context)Conversations weren't persisting across refreshes because of a race in bootstrap_load: streamlit-js-eval's get_local_storage() returns None on the first render (component is still mounting); Streamlit then auto-reruns and the second render returns the actual stored value. Old code cached the None response as []. Next render saw _CACHE_KEY already in session_state, short-circuited, and never re-read β so the real value (which was sitting in localStorage) never made it into the cache. Fix: only populate the cache when the response is non-None. First-render None is treated as 'still loading' and we let the next render re-attempt. Empty string is the actual 'no data stored' signal and is cached as []. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>314ef46 -
Add browser-local conversation persistenceβ
webmuppet +1: Claude Opus 4.7 (1M context)New feature: past conversations persist to browser localStorage and appear in the sidebar so users can return to prior compliance Q&A in the same browser. Implementation: - New module src/persistence.py wraps streamlit-js-eval to read/write a single localStorage key 'hmc-conversations' containing a JSON array of conversation objects (id, title, created_at, last_active_at, messages, history, results). Capped at 20 most recent by last_active_at. - App boot: persistence.bootstrap_load() runs once per session, cached in session_state thereafter. - conversation_id allocated when user submits first message in a fresh session, persisted across renders, cleared by 'New conversation', overwritten on restore. - Save fires after each assistant response β after st.write_stream returns and session_state is fully updated. No st.rerun() between state mutation and save, so no race condition. - Sidebar 'Past conversations' section: title button + β delete per row via st.columns([5,β¦26a2c61
-
Surface system prompt to prompts/generator_system.mdβ
webmuppet +1: Claude Opus 4.7 (1M context)The prompt template was previously a 90-line triple-quoted Python string with line continuations, hard to read and edit. Extracted verbatim to prompts/generator_system.md (clean markdown, no escaping) so it can be opened in any editor and reasoned about as a document. Loading semantics changed: - Was: cached at module load, restart required to pick up changes - Now: read from file every call, save-and-rerun is enough The prototype's volume is low (handful of LLM calls per session) so the per-call file read is negligible β gain in iteration speed beats the microsecond cost. If we ever need to cache, we can reintroduce a module-level cache with a file-mtime invalidation hook. The {TODAY} placeholder substitution still happens at call time as before. Other files referencing SYSTEM_PROMPT-like constants (scripts/build_indexes.py SUMMARY_SYSTEM_PROMPT, PageIndex examples) are unrelated and unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>6353df2 -
Prompt: lock 'Short answer:' as a level-2 headingβ
webmuppet +1: Claude Opus 4.7 (1M context)The 'Short answer: ...' lead was inconsistently formatted across responses β sometimes a ## heading (renders as the violet h2 we styled) and sometimes **bold body text**. Both were valid markdown but produced visually inconsistent UX. The fix is at the prompt layer, not CSS: explicit instruction in the Structure section that the lead MUST be '## Short answer: ...' as h2. Also updated the example output to match the prescribed form (was '**Answer:** Short answer:' which the model was anchoring on as the canonical pattern). Adds matching guidance for using ## / ### consistently within the body of the answer for the section hierarchy. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>990de55 -
Initial commit β health marketing compliance RAGβ
webmuppet +1: Claude Opus 4.7 (1M context)Conversational compliance assistant for NZ healthcare marketing regulation, scoped to complementary/alternative practitioners and supplement sellers. Six-domain corpus + PageIndex retrieval + Claude Sonnet generation. Configured for Hugging Face Spaces (docker SDK). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>bad8b6c