### What problem does this PR solve? feat: Add component ExecSQL #1739 ### Type of change - [x] New Feature (non-breaking change which adds functionality)tags/v0.10.0
| <svg t="1723794486485" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7111" | |||||
| width="200" height="200"> | |||||
| <path | |||||
| d="M776.533333 755.456H598.903467c-14.421333 0-26.112 12.475733-26.112 27.869867v168.618666h28.433066L776.533333 760.439467v-4.983467zM776.533333 699.733333v-88.183466c0-15.189333 11.4688-27.477333 25.6-27.477334s25.6 12.288 25.6 27.477334v160.136533c0 7.2192-2.645333 14.1312-7.338666 19.285333L630.2208 998.7072a24.746667 24.746667 0 0 1-18.261333 8.226133H228.693333C163.669333 1006.933333 110.933333 950.306133 110.933333 880.452267V143.530667C110.933333 73.693867 163.669333 17.066667 228.693333 17.066667h481.28C774.997333 17.066667 827.733333 73.693867 827.733333 143.547733v48.930134c0 15.189333-11.4688 27.477333-25.6 27.477333s-25.6-12.288-25.6-27.477333V143.530667c0-39.4752-29.7984-71.492267-66.56-71.492267H228.693333c-36.7616 0-66.56 32.017067-66.56 71.509333v736.887467c0 39.4752 29.7984 71.492267 66.56 71.492267H520.533333v-168.618667C520.533333 737.160533 555.6224 699.733333 598.903467 699.733333H776.533333zM367.7696 280.576c27.272533 0 47.530667 5.512533 60.416 16.896 13.687467 11.997867 19.1488 30.8224 16.093867 56.149333h-37.666134c-0.238933-14.2848-4.215467-24.6784-11.3664-30.839466-7.0656-6.485333-19.456-9.4208-36.317866-9.4208-14.609067 0-26.0608 1.9456-34.747734 6.178133-10.752 4.864-17.015467 12.970667-19.336533 24.0128-2.048 9.745067 1.4336 17.8688 11.246933 23.722667 4.317867 2.577067 16.605867 7.458133 36.608 14.267733 29.44 9.728 47.9232 17.527467 55.927467 22.7328 17.578667 12.014933 24.1664 28.5696 19.6608 50.005333-4.369067 20.770133-15.9744 37.3248-34.730667 49.322667-18.688 11.690667-43.042133 17.8688-72.584533 17.8688-28.5696 0-49.8176-5.5296-63.402667-16.554667-16.605867-13.653333-22.801067-35.072-18.210133-64.6144h37.666133c-1.092267 17.527467 2.389333 30.208 10.888534 37.666134 7.7312 6.485333 20.9408 10.069333 40.106666 10.069333 16.878933 0 31.112533-2.935467 42.018134-8.448 10.973867-5.8368 17.749333-13.312 19.797333-23.04 2.594133-12.356267-2.833067-22.084267-15.616-29.2352-4.061867-2.269867-17.902933-7.458133-41.915733-15.2576-26.658133-9.079467-43.144533-15.581867-49.152-19.473067-15.581867-10.717867-21.077333-26.299733-16.776534-46.762666 4.3008-20.445867 16.162133-36.676267 36.164267-48.366934 18.602667-11.3664 40.226133-16.878933 65.2288-16.878933z m249.122133 0c35.3792 0 60.910933 11.3664 76.509867 34.4064 14.8992 21.76 18.568533 50.653867 11.042133 86.357333-7.304533 34.747733-22.664533 62.976-45.346133 84.411734 6.109867 11.042133 12.424533 22.7328 18.261333 35.072l-29.184 21.418666a712.5504 712.5504 0 0 0-18.1248-35.703466c-18.944 9.728-40.482133 14.933333-63.863466 14.933333-35.703467 0-61.166933-11.690667-76.509867-34.423467-14.848-22.0672-18.244267-50.6368-10.8544-85.7088 7.441067-35.3792 22.869333-63.9488 47.0016-86.016 25.0368-23.381333 55.3472-34.747733 91.067733-34.747733z m-7.048533 33.450667c-24.0128 0-44.2368 8.106667-60.962133 24.337066-15.940267 15.581867-26.4704 36.352-32.085334 62.976-5.5296 26.299733-3.7376 47.086933 5.649067 62.6688 9.642667 15.906133 26.760533 24.029867 50.7904 24.029867a90.794667 90.794667 0 0 0 41.2672-9.4208c-8.704-14.2848-17.066667-26.948267-25.378133-38.314667l26.5728-21.418666a704.085333 704.085333 0 0 1 25.838933 37.649066c11.451733-14.2848 19.899733-32.785067 24.610133-55.1936 5.7344-27.255467 3.754667-48.6912-5.632-64.273066-9.710933-15.581867-26.624-23.04-50.670933-23.04z m171.434667-28.910934h37.666133l-41.949867 199.338667h125.320534l-6.826667 32.477867h-162.986667l48.776534-231.816534z" | |||||
| fill="#2c2c2c" p-id="7112"></path> | |||||
| </svg> |
| interface IProps { | interface IProps { | ||||
| initialValue?: number; | initialValue?: number; | ||||
| max?: number; | |||||
| } | } | ||||
| const TopNItem = ({ initialValue = 8 }: IProps) => { | |||||
| const TopNItem = ({ initialValue = 8, max = 30 }: IProps) => { | |||||
| const { t } = useTranslate('chat'); | const { t } = useTranslate('chat'); | ||||
| return ( | return ( | ||||
| initialValue={initialValue} | initialValue={initialValue} | ||||
| tooltip={t('topNTip')} | tooltip={t('topNTip')} | ||||
| > | > | ||||
| <Slider max={30} /> | |||||
| <Slider max={max} /> | |||||
| </Form.Item> | </Form.Item> | ||||
| ); | ); | ||||
| }; | }; |
| '30d': '30 days', | '30d': '30 days', | ||||
| }, | }, | ||||
| publish: 'API', | publish: 'API', | ||||
| exeSQL: 'ExeSQL', | |||||
| exeSQLDescription: | |||||
| 'The component queries the results from the corresponding relational database via SQL statements. Supports MySQL, PostgreSQL, MariaDB. ', | |||||
| dbType: 'Database Type', | |||||
| database: 'Database', | |||||
| username: 'Username', | |||||
| host: 'Host', | |||||
| port: 'Port', | |||||
| password: 'Password', | |||||
| }, | }, | ||||
| footer: { | footer: { | ||||
| profile: 'All rights reserved @ React', | profile: 'All rights reserved @ React', |
| '30d': '30天', | '30d': '30天', | ||||
| }, | }, | ||||
| publish: 'API', | publish: 'API', | ||||
| exeSQL: 'ExeSQL', | |||||
| exeSQLDescription: | |||||
| '此元件透過SQL語句從對應的關聯式資料庫中查詢結果。支援 MySQL、PostgreSQL、MariaDB。 ', | |||||
| dbType: '資料庫類型', | |||||
| database: '資料庫', | |||||
| username: '使用者名稱', | |||||
| host: '主機', | |||||
| port: '端口', | |||||
| password: '密碼', | |||||
| }, | }, | ||||
| footer: { | footer: { | ||||
| profile: '“保留所有權利 @ react”', | profile: '“保留所有權利 @ react”', |
| '30d': '30天', | '30d': '30天', | ||||
| }, | }, | ||||
| publish: 'API', | publish: 'API', | ||||
| exeSQL: 'ExeSQL', | |||||
| exeSQLDescription: | |||||
| '该组件通过SQL语句从相应的关系数据库中查询结果。支持MySQL,PostgreSQL,MariaDB。', | |||||
| dbType: '数据库类型', | |||||
| database: '数据库', | |||||
| username: '用户名', | |||||
| host: '主机', | |||||
| port: '端口', | |||||
| password: '密码', | |||||
| }, | }, | ||||
| footer: { | footer: { | ||||
| profile: 'All rights reserved @ React', | profile: 'All rights reserved @ React', |
| import { ReactComponent as BingIcon } from '@/assets/svg/bing.svg'; | import { ReactComponent as BingIcon } from '@/assets/svg/bing.svg'; | ||||
| import { ReactComponent as DeepLIcon } from '@/assets/svg/deepl.svg'; | import { ReactComponent as DeepLIcon } from '@/assets/svg/deepl.svg'; | ||||
| import { ReactComponent as DuckIcon } from '@/assets/svg/duck.svg'; | import { ReactComponent as DuckIcon } from '@/assets/svg/duck.svg'; | ||||
| import { ReactComponent as ExeSqlIcon } from '@/assets/svg/exesql.svg'; | |||||
| import { ReactComponent as GithubIcon } from '@/assets/svg/github.svg'; | import { ReactComponent as GithubIcon } from '@/assets/svg/github.svg'; | ||||
| import { ReactComponent as GoogleScholarIcon } from '@/assets/svg/google-scholar.svg'; | import { ReactComponent as GoogleScholarIcon } from '@/assets/svg/google-scholar.svg'; | ||||
| import { ReactComponent as GoogleIcon } from '@/assets/svg/google.svg'; | import { ReactComponent as GoogleIcon } from '@/assets/svg/google.svg'; | ||||
| SendOutlined, | SendOutlined, | ||||
| SlidersOutlined, | SlidersOutlined, | ||||
| } from '@ant-design/icons'; | } from '@ant-design/icons'; | ||||
| import upperFirst from 'lodash/upperFirst'; | |||||
| export enum Operator { | export enum Operator { | ||||
| Begin = 'Begin', | Begin = 'Begin', | ||||
| GitHub = 'GitHub', | GitHub = 'GitHub', | ||||
| BaiduFanyi = 'BaiduFanyi', | BaiduFanyi = 'BaiduFanyi', | ||||
| QWeather = 'QWeather', | QWeather = 'QWeather', | ||||
| ExeSQL = 'ExeSQL', | |||||
| } | } | ||||
| export const operatorIconMap = { | export const operatorIconMap = { | ||||
| [Operator.GitHub]: GithubIcon, | [Operator.GitHub]: GithubIcon, | ||||
| [Operator.BaiduFanyi]: baiduFanyiIcon, | [Operator.BaiduFanyi]: baiduFanyiIcon, | ||||
| [Operator.QWeather]: QWeatherIcon, | [Operator.QWeather]: QWeatherIcon, | ||||
| [Operator.ExeSQL]: ExeSqlIcon, | |||||
| }; | }; | ||||
| export const operatorMap = { | export const operatorMap = { | ||||
| [Operator.GitHub]: {}, | [Operator.GitHub]: {}, | ||||
| [Operator.BaiduFanyi]: {}, | [Operator.BaiduFanyi]: {}, | ||||
| [Operator.QWeather]: {}, | [Operator.QWeather]: {}, | ||||
| [Operator.ExeSQL]: {}, | |||||
| }; | }; | ||||
| export const componentMenuList = [ | export const componentMenuList = [ | ||||
| { | { | ||||
| name: Operator.QWeather, | name: Operator.QWeather, | ||||
| }, | }, | ||||
| { | |||||
| name: Operator.ExeSQL, | |||||
| }, | |||||
| ]; | ]; | ||||
| export const initialRetrievalValues = { | export const initialRetrievalValues = { | ||||
| time_period: 'now', | time_period: 'now', | ||||
| }; | }; | ||||
| export const initialExeSqlValues = { | |||||
| db_type: 'mysql', | |||||
| database: '', | |||||
| username: '', | |||||
| host: '', | |||||
| port: 3306, | |||||
| password: '', | |||||
| loop: 3, | |||||
| top_n: 30, | |||||
| }; | |||||
| export const CategorizeAnchorPointPositions = [ | export const CategorizeAnchorPointPositions = [ | ||||
| { top: 1, right: 34 }, | { top: 1, right: 34 }, | ||||
| { top: 8, right: 18 }, | { top: 8, right: 18 }, | ||||
| [Operator.GitHub]: [Operator.Begin, Operator.Retrieval], | [Operator.GitHub]: [Operator.Begin, Operator.Retrieval], | ||||
| [Operator.BaiduFanyi]: [Operator.Begin, Operator.Retrieval], | [Operator.BaiduFanyi]: [Operator.Begin, Operator.Retrieval], | ||||
| [Operator.QWeather]: [Operator.Begin, Operator.Retrieval], | [Operator.QWeather]: [Operator.Begin, Operator.Retrieval], | ||||
| [Operator.ExeSQL]: [Operator.Begin], | |||||
| }; | }; | ||||
| export const NodeMap = { | export const NodeMap = { | ||||
| [Operator.GitHub]: 'ragNode', | [Operator.GitHub]: 'ragNode', | ||||
| [Operator.BaiduFanyi]: 'ragNode', | [Operator.BaiduFanyi]: 'ragNode', | ||||
| [Operator.QWeather]: 'ragNode', | [Operator.QWeather]: 'ragNode', | ||||
| [Operator.ExeSQL]: 'ragNode', | |||||
| }; | }; | ||||
| export const LanguageOptions = [ | export const LanguageOptions = [ | ||||
| '15d', | '15d', | ||||
| '30d', | '30d', | ||||
| ]; | ]; | ||||
| export const ExeSQLOptions = ['mysql', 'postgresql', 'mariadb'].map((x) => ({ | |||||
| label: upperFirst(x), | |||||
| value: x, | |||||
| })); |
| import TopNItem from '@/components/top-n-item'; | |||||
| import { useTranslate } from '@/hooks/common-hooks'; | |||||
| import { Form, Input, InputNumber, Select } from 'antd'; | |||||
| import { ExeSQLOptions } from '../constant'; | |||||
| import { IOperatorForm } from '../interface'; | |||||
| const ExeSQLForm = ({ onValuesChange, form }: IOperatorForm) => { | |||||
| const { t } = useTranslate('flow'); | |||||
| return ( | |||||
| <Form | |||||
| name="basic" | |||||
| labelCol={{ span: 7 }} | |||||
| wrapperCol={{ span: 17 }} | |||||
| autoComplete="off" | |||||
| form={form} | |||||
| onValuesChange={onValuesChange} | |||||
| > | |||||
| <Form.Item | |||||
| label={t('dbType')} | |||||
| name={'db_type'} | |||||
| rules={[{ required: true }]} | |||||
| > | |||||
| <Select options={ExeSQLOptions}></Select> | |||||
| </Form.Item> | |||||
| <Form.Item | |||||
| label={t('database')} | |||||
| name={'database'} | |||||
| rules={[{ required: true }]} | |||||
| > | |||||
| <Input></Input> | |||||
| </Form.Item> | |||||
| <Form.Item | |||||
| label={t('username')} | |||||
| name={'username'} | |||||
| rules={[{ required: true }]} | |||||
| > | |||||
| <Input></Input> | |||||
| </Form.Item> | |||||
| <Form.Item label={t('host')} name={'host'} rules={[{ required: true }]}> | |||||
| <Input></Input> | |||||
| </Form.Item> | |||||
| <Form.Item label={t('port')} name={'port'} rules={[{ required: true }]}> | |||||
| <InputNumber></InputNumber> | |||||
| </Form.Item> | |||||
| <Form.Item | |||||
| label={t('password')} | |||||
| name={'password'} | |||||
| rules={[{ required: true }]} | |||||
| > | |||||
| <Input.Password></Input.Password> | |||||
| </Form.Item> | |||||
| <Form.Item label={t('loop')} name={'loop'} rules={[{ required: true }]}> | |||||
| <InputNumber></InputNumber> | |||||
| </Form.Item> | |||||
| <TopNItem initialValue={30} max={100000}></TopNItem> | |||||
| </Form> | |||||
| ); | |||||
| }; | |||||
| export default ExeSQLForm; |
| import BingForm from '../bing-form'; | import BingForm from '../bing-form'; | ||||
| import CategorizeForm from '../categorize-form'; | import CategorizeForm from '../categorize-form'; | ||||
| import { Operator } from '../constant'; | import { Operator } from '../constant'; | ||||
| import DeepLForm from '../deepl-form'; | |||||
| import DuckDuckGoForm from '../duckduckgo-form'; | import DuckDuckGoForm from '../duckduckgo-form'; | ||||
| import ExeSQLForm from '../exesql-form'; | |||||
| import GenerateForm from '../generate-form'; | import GenerateForm from '../generate-form'; | ||||
| import GithubForm from '../github-form'; | import GithubForm from '../github-form'; | ||||
| import GoogleForm from '../google-form'; | import GoogleForm from '../google-form'; | ||||
| import RetrievalForm from '../retrieval-form'; | import RetrievalForm from '../retrieval-form'; | ||||
| import RewriteQuestionForm from '../rewrite-question-form'; | import RewriteQuestionForm from '../rewrite-question-form'; | ||||
| import WikipediaForm from '../wikipedia-form'; | import WikipediaForm from '../wikipedia-form'; | ||||
| import DeepLForm from '../deepl-form'; | |||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| interface IProps { | interface IProps { | ||||
| [Operator.GitHub]: GithubForm, | [Operator.GitHub]: GithubForm, | ||||
| [Operator.BaiduFanyi]: BaiduFanyiForm, | [Operator.BaiduFanyi]: BaiduFanyiForm, | ||||
| [Operator.QWeather]: QWeatherForm, | [Operator.QWeather]: QWeatherForm, | ||||
| [Operator.ExeSQL]: ExeSQLForm, | |||||
| }; | }; | ||||
| const EmptyContent = () => <div>empty</div>; | const EmptyContent = () => <div>empty</div>; |
| import useGraphStore from '../store'; | import useGraphStore from '../store'; | ||||
| // exclude nodes with branches | // exclude nodes with branches | ||||
| const ExcludedNodes = [Operator.Categorize, Operator.Relevant]; | |||||
| const ExcludedNodes = [ | |||||
| Operator.Categorize, | |||||
| Operator.Relevant, | |||||
| Operator.Begin, | |||||
| Operator.Answer, | |||||
| ]; | |||||
| export const useBuildComponentIdSelectOptions = (nodeId?: string) => { | export const useBuildComponentIdSelectOptions = (nodeId?: string) => { | ||||
| const nodes = useGraphStore((state) => state.nodes); | const nodes = useGraphStore((state) => state.nodes); |
| initialCategorizeValues, | initialCategorizeValues, | ||||
| initialDeepLValues, | initialDeepLValues, | ||||
| initialDuckValues, | initialDuckValues, | ||||
| initialExeSqlValues, | |||||
| initialGenerateValues, | initialGenerateValues, | ||||
| initialGithubValues, | initialGithubValues, | ||||
| initialGoogleScholarValues, | initialGoogleScholarValues, | ||||
| [Operator.GitHub]: initialGithubValues, | [Operator.GitHub]: initialGithubValues, | ||||
| [Operator.BaiduFanyi]: initialBaiduFanyiValues, | [Operator.BaiduFanyi]: initialBaiduFanyiValues, | ||||
| [Operator.QWeather]: initialQWeatherValues, | [Operator.QWeather]: initialQWeatherValues, | ||||
| [Operator.ExeSQL]: initialExeSqlValues, | |||||
| }; | }; | ||||
| }, [llmId]); | }, [llmId]); | ||||
| return ( | return ( | ||||
| <Flex justify={'space-between'}> | <Flex justify={'space-between'}> | ||||
| <a | <a | ||||
| href={`https://github.com/infiniflow/ragflow/blob/main/docs/guides/deploy_local_llm.md`} | |||||
| href={`https://github.com/infiniflow/ragflow/blob/main/docs/guides/deploy_local_llm.mdx`} | |||||
| target="_blank" | target="_blank" | ||||
| rel="noreferrer" | rel="noreferrer" | ||||
| > | > |