search for standard sites pub-search.waow.tech
search zig blog atproto

fix: highlight quoted phrase matches in search results

- highlightTerms() now extracts quoted phrases as single terms
- add daily scheduled workflow for embedding backfill (6am UTC)
- can also trigger backfill manually via workflow_dispatch

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

+39 -1
+23
.github/workflows/backfill-embeddings.yml
··· 1 + name: Backfill Embeddings 2 + 3 + on: 4 + schedule: 5 + # run daily at 6am UTC 6 + - cron: '0 6 * * *' 7 + workflow_dispatch: # allow manual trigger 8 + 9 + jobs: 10 + backfill: 11 + runs-on: ubuntu-latest 12 + steps: 13 + - uses: actions/checkout@v4 14 + 15 + - name: Install uv 16 + uses: astral-sh/setup-uv@v5 17 + 18 + - name: Run backfill 19 + env: 20 + TURSO_URL: ${{ secrets.TURSO_URL }} 21 + TURSO_TOKEN: ${{ secrets.TURSO_TOKEN }} 22 + VOYAGE_API_KEY: ${{ secrets.VOYAGE_API_KEY }} 23 + run: ./scripts/backfill-embeddings --batch-size 50
+16 -1
site/index.html
··· 758 758 759 759 function highlightTerms(text, query) { 760 760 if (!text || !query) return escapeHtml(text); 761 - const terms = query.toLowerCase().split(/\s+/).filter(t => t.length > 0); 761 + 762 + // extract terms: quoted phrases as single terms, or split by whitespace 763 + const terms = []; 764 + const phraseRegex = /"([^"]+)"/g; 765 + let match; 766 + let remaining = query.toLowerCase(); 767 + 768 + // extract quoted phrases first 769 + while ((match = phraseRegex.exec(query.toLowerCase())) !== null) { 770 + terms.push(match[1]); // the phrase without quotes 771 + remaining = remaining.replace(match[0], ' '); 772 + } 773 + 774 + // add remaining non-quoted terms 775 + remaining.split(/\s+/).filter(t => t.length > 0).forEach(t => terms.push(t)); 776 + 762 777 if (terms.length === 0) return escapeHtml(text); 763 778 764 779 // build regex that matches any term (case insensitive)