* Generate combined keyword&pattern score for text matching a specific query intent * Used in post-processing to re-rank results beyond vector similarity
(text: string, query: string)
| 750 | * Used in post-processing to re-rank results beyond vector similarity |
| 751 | */ |
| 752 | function calculateKeywordMatchScore(text: string, query: string): number { |
| 753 | // Lower-case for case-insensitive matching |
| 754 | const lowerText = text.toLowerCase(); |
| 755 | const lowerQuery = query.toLowerCase(); |
| 756 | |
| 757 | let score = 0; |
| 758 | |
| 759 | // Penalize license sections, which are rarely relevant |
| 760 | if ( |
| 761 | /^#+\s+license\b/im.test(text) || |
| 762 | text.toLowerCase().includes("mit license") |
| 763 | ) { |
| 764 | score -= 0.3; |
| 765 | } |
| 766 | |
| 767 | // Penalize badge sections which are usually not informative for queries |
| 768 | if ( |
| 769 | /\]\(https?:\/\/[^)]*badge[^)]*\)/i.test(text) && |
| 770 | text.split("\n").length < 8 |
| 771 | ) { |
| 772 | score -= 0.2; |
| 773 | } |
| 774 | |
| 775 | // Boost sections that likely contain actual information |
| 776 | if ( |
| 777 | /^#+\s+(what is|getting started|introduction|usage|examples|installation)/im.test( |
| 778 | text, |
| 779 | ) |
| 780 | ) { |
| 781 | score += 0.3; |
| 782 | } |
| 783 | |
| 784 | // Extract terms from query (removing stop words) |
| 785 | const queryTerms = lowerQuery |
| 786 | .split(/\W+/) |
| 787 | .filter((term) => term.length > 2 && !commonWords.has(term)); |
| 788 | |
| 789 | // Count term occurrences in text |
| 790 | for (const term of queryTerms) { |
| 791 | // Use regex to find whole word matches |
| 792 | const regex = new RegExp(`\\b${term}\\b`, "gi"); |
| 793 | const matches = lowerText.match(regex) || []; |
| 794 | |
| 795 | // Add score based on frequency |
| 796 | score += matches.length * 0.05; |
| 797 | } |
| 798 | |
| 799 | // Boost for heading matches (much higher boost than before) |
| 800 | const headings = text.match(/#{1,6}\s+([^\n]+)/g) || []; |
| 801 | for (const heading of headings) { |
| 802 | const lowerHeading = heading.toLowerCase(); |
| 803 | for (const term of queryTerms) { |
| 804 | if (lowerHeading.includes(term)) { |
| 805 | score += 0.25; // Higher boost for term in heading |
| 806 | } |
| 807 | } |
| 808 | } |
| 809 |
no outgoing calls
no test coverage detected