Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Hybrid Search #19

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions builder/partnerproduct/src/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ vector_store:
numCandidates: 150
minScore: 0.1
vectorSearchIndexName: 'vector_index'
textSearchIndexName: 'text_index'
llms:
class_name: Fireworks
model_name: 'accounts/fireworks/models/mixtral-8x22b-instruct'
Expand Down
3 changes: 2 additions & 1 deletion builder/partnerproduct/src/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@ try {
chunksAdded += chunks.entriesAdded;
});
}

if (chunksAdded > 0) {
console.log(`\n Total documents added : ${chunksAdded} `)
await llmApplication.createVectorIndex();
await llmApplication.createTextIndex();
}
else {
console.log("\n-- Data not inserted, please retry --")
Expand Down
28 changes: 26 additions & 2 deletions builder/partnerproduct/src/semantic-search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const app = express();
const port = 9001;

app.use(express.json());
app.use(cors());
app.use(cors());

const llmApplication = await new RAGApplicationBuilder()
.setModel(getModelClass())
Expand Down Expand Up @@ -42,6 +42,30 @@ app.get('/semantic-search', async (req: Request, res: Response) => {
}
});

app.get('/hybrid-search', async (req: Request, res: Response) => {
try {
const userQuery = asString(req.query.query);
const vectorWeight = asFloat(req.query.vectorWeight ?? 0.5);
const fullTextWeight = asFloat(req.query.fullTextWeight ?? 0.5);

if (!userQuery) {
return res.status(400).send('Query is required');
}

llmApplication.hybridQuery(userQuery, vectorWeight, fullTextWeight).then((result) => {
console.log('Result:', result);
res.send(result);
});

} catch (error) {
console.error('Error during hybrid vector search:', error);
res.status(500).send('An error occurred while processing your request.');
}
});

app.listen(port, () => {
console.log(`Server is running on http://localhost:${port}`);
});
});

function asString(value: any): string { return typeof value !== 'undefined' ? value.toString() : ''; }
function asFloat(value: any): number { return typeof value !== 'undefined' ? parseFloat(value.toString()) || 0 : 0; }
136 changes: 117 additions & 19 deletions builder/partnerproduct/ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions builder/partnerproduct/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"@leafygreen-ui/card": "^11.0.0",
"@leafygreen-ui/icon": "^12.6.0",
"@leafygreen-ui/loading-indicator": "^2.0.12",
"@leafygreen-ui/number-input": "^2.2.1",
"@leafygreen-ui/search-input": "^3.1.2",
"@leafygreen-ui/side-nav": "^14.1.3",
"@leafygreen-ui/tabs": "^13.0.1",
Expand Down
8 changes: 7 additions & 1 deletion builder/partnerproduct/ui/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,19 @@ function App() {
Vector Search
</SideNavItem>
</Link>
<Link onClick={handleTabClick(3)} className="link" to="/hybrid-search">
<SideNavItem active={activeTab === 3} glyph={<Icon glyph="Wizard" />} >
Hybrid Search
</SideNavItem>
</Link>
</SideNavGroup>
</SideNav>
<div className="main-content">
<Routes>
<Route path="/" element={<Hero />} />
<Route path="/rag-chatbot" element={<ChatModule />} />
<Route path="/search" element={<Search />} />
<Route path="/hybrid-search" element={<Search hybrid="true" />} />
</Routes>
</div>
</div>
Expand All @@ -64,4 +70,4 @@ function App() {
);
}

export default App;
export default App;
31 changes: 27 additions & 4 deletions builder/partnerproduct/ui/src/modules/search/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,27 @@ import Card from '@leafygreen-ui/card';
import { PageLoader, Spinner } from "@leafygreen-ui/loading-indicator";
import './search.css';
import { H1, H2 } from '@leafygreen-ui/typography';
import { NumberInput } from '@leafygreen-ui/number-input';

function Search() {
function Search({ hybrid }) {
const isHybridSearch = hybrid
const [searchValue, setSearchValue] = useState('');
const [vectorWeight, setVectorWeight] = useState(0.5);
const [textWeight, setTextWeight] = useState(0.5);
const [response, setResponse] = useState([]);
const [loading, setLoading] = useState(false);

const handleInputChange = (event) => {
setSearchValue(event.target.value);
};

const searchEndpoint = `http://localhost:9001/${isHybridSearch ? 'hybrid-search' : 'semantic-search'}`;

const searchResults = () => {
console.log(searchValue);
setLoading(true);
const query = encodeURIComponent(searchValue);
fetch(`http://localhost:9001/semantic-search?query=${query}`, {
fetch(`${searchEndpoint}?query=${query}&vectorWeight=${vectorWeight}&fullTextWeight=${textWeight}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
Expand All @@ -38,20 +44,37 @@ function Search() {

return (
<div className="search-bar">
<H1>Vector Search</H1>
<H1>{ isHybridSearch ? "Hybrid Search" : "Vector Search"}</H1>
<header className="search-header">
<SearchInput
value={searchValue}
onChange={handleInputChange}
onSubmit={searchResults}
/>
{ isHybridSearch && <>
<NumberInput
label='Vector Weight'
description='Affects the weighted reciprocal rank'
darkMode="true"
value={vectorWeight}
onChange={(e) => setVectorWeight(e.target.value)}
/>
<NumberInput
label='Text Weight'
description='Affects the weighted reciprocal rank'
darkMode="true"
value={textWeight}
onChange={(e) => setTextWeight(e.target.value)}
/>
</> }
</header>
<div className='results'>
<>
{loading ? <PageLoader /> : <div>
{response.map((item, index) => (
<Card key={index} className="card-styles" as="article">
<h3>Score: {item.score}</h3>
{ isHybridSearch && <pre>Text Score: {item.fts_score}, Vector Score: {item.vs_score}</pre> }
<p><strong>Content:</strong> {item.pageContent}</p>
<div>
<h4>Metadata:</h4>
Expand All @@ -66,4 +89,4 @@ function Search() {
);
}

export default Search;
export default Search;
Loading