chore: add hybrid search control (#39258)

## Description
Add hybrid search control for UQI forms.

![Снимок экрана 2025-02-14 в 10 06
28](https://github.com/user-attachments/assets/45167650-3646-4746-93eb-aa0322b68a58)

Example of usage:
```
{
  "isRequired": false,
  "configProperty": "actionConfiguration.formData.hybridSearch",
  "controlType": "HYBRID_SEARCH",
  "initialValue": {
      "isEnabled": true,
      "keywordWeight": 0.5,
      "semanticWeight": 0.5
  }
}
```

Fixes https://github.com/appsmithorg/appsmith/issues/39236

## Automation

/ok-to-test tags="@tag.Datasource"

### 🔍 Cypress test results
<!-- This is an auto-generated comment: Cypress test results  -->
> [!TIP]
> 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉
> Workflow run:
<https://github.com/appsmithorg/appsmith/actions/runs/13324291818>
> Commit: 9495722fe3224474db772890f31730becfa45d79
> <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=13324291818&attempt=1"
target="_blank">Cypress dashboard</a>.
> Tags: `@tag.Datasource`
> Spec:
> <hr>Fri, 14 Feb 2025 07:52:38 UTC
<!-- end of auto-generated comment: Cypress test results  -->


## Communication
Should the DevRel and Marketing teams inform users about this change?
- [ ] Yes
- [x] No


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Introduced a new hybrid search control in the form. Users can now
easily adjust search parameters with intuitive sliders for keyword and
semantic weights, along with a toggle to activate or deactivate hybrid
search.
- Added a new control type for hybrid search to the form control
registry, enhancing the flexibility of form configurations.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Valera Melnikov 2025-02-14 11:05:41 +03:00 committed by GitHub
parent 23b2b9256e
commit 0e67bbc68c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 85 additions and 0 deletions

View File

@ -0,0 +1,78 @@
import React from "react";
import { Field, type WrappedFieldInputProps } from "redux-form";
import BaseControl from "./BaseControl";
import type { ControlProps } from "./BaseControl";
import { Slider, type SliderProps, Flex, Switch, Text } from "@appsmith/ads";
export interface HybridSearchControlProps
extends ControlProps,
Omit<SliderProps, "id" | "label"> {}
export class HybridSearchControl extends BaseControl<HybridSearchControlProps> {
render() {
const { configProperty, ...rest } = this.props;
return (
<Field
component={renderHybridSearchControl}
name={configProperty}
props={{ ...rest }}
/>
);
}
getControlType(): string {
return "HYBRID_SEARCH";
}
}
const renderHybridSearchControl = (
props: {
input?: WrappedFieldInputProps;
} & HybridSearchControlProps,
) => {
const { input } = props;
const onSliderChange = (value: number) => {
input?.onChange({
...input?.value,
keywordWeight: value,
semanticWeight: (10 - value * 10) / 10, // Scale by 10 to avoid floating-point issues
});
};
const onSwitchChange = (value: boolean) => {
input?.onChange({
...input?.value,
isEnabled: value,
});
};
return (
<Flex flexDirection="column" gap="spaces-4">
<Flex width="150px">
<Switch
defaultSelected={input?.value.isEnabled}
onChange={onSwitchChange}
>
Hybrid search
</Switch>
</Flex>
<Flex flexDirection="column">
<Slider
getValueLabel={() => "Semantic weight"}
isDisabled={!input?.value.isEnabled}
label="Keyword weight"
maxValue={1}
minValue={0}
onChange={onSliderChange}
step={0.1}
value={input?.value.keywordWeight}
/>
<Flex justifyContent="space-between">
<Text>{input?.value.keywordWeight}</Text>
<Text>{input?.value.semanticWeight}</Text>
</Flex>
</Flex>
</Flex>
);
};

View File

@ -45,6 +45,7 @@ import {
SliderControl,
type SliderControlProps,
} from "components/formControls/SliderControl";
import { HybridSearchControl } from "components/formControls/HybridSearch";
/**
* NOTE: If you are adding a component that uses FormControl
@ -225,6 +226,11 @@ class FormControlRegistry {
},
},
);
FormControlFactory.registerControlBuilder(formControlTypes.HYBRID_SEARCH, {
buildPropertyControl(controlProps: SliderControlProps): JSX.Element {
return <HybridSearchControl {...controlProps} />;
},
});
}
}

View File

@ -22,4 +22,5 @@ export default {
RAG_INTEGRATIONS: "RAG_INTEGRATIONS",
SLIDER: "SLIDER",
RAG_DOCUMENTS_SELECTOR: "RAG_DOCUMENTS_SELECTOR",
HYBRID_SEARCH: "HYBRID_SEARCH",
};