vectordb-bench 0.0.11__py3-none-any.whl → 0.0.13__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vectordb_bench/__init__.py +1 -0
- vectordb_bench/backend/assembler.py +1 -1
- vectordb_bench/backend/cases.py +64 -18
- vectordb_bench/backend/clients/__init__.py +35 -0
- vectordb_bench/backend/clients/api.py +21 -1
- vectordb_bench/backend/clients/aws_opensearch/aws_opensearch.py +159 -0
- vectordb_bench/backend/clients/aws_opensearch/cli.py +44 -0
- vectordb_bench/backend/clients/aws_opensearch/config.py +58 -0
- vectordb_bench/backend/clients/aws_opensearch/run.py +125 -0
- vectordb_bench/backend/clients/memorydb/cli.py +88 -0
- vectordb_bench/backend/clients/memorydb/config.py +54 -0
- vectordb_bench/backend/clients/memorydb/memorydb.py +254 -0
- vectordb_bench/backend/clients/pgvecto_rs/cli.py +154 -0
- vectordb_bench/backend/clients/pgvecto_rs/config.py +108 -73
- vectordb_bench/backend/clients/pgvecto_rs/pgvecto_rs.py +159 -59
- vectordb_bench/backend/clients/pgvectorscale/config.py +111 -0
- vectordb_bench/backend/clients/pgvectorscale/pgvectorscale.py +272 -0
- vectordb_bench/backend/dataset.py +27 -5
- vectordb_bench/cli/vectordbbench.py +7 -0
- vectordb_bench/custom/custom_case.json +18 -0
- vectordb_bench/frontend/components/check_results/charts.py +6 -6
- vectordb_bench/frontend/components/check_results/data.py +18 -11
- vectordb_bench/frontend/components/check_results/expanderStyle.py +1 -1
- vectordb_bench/frontend/components/check_results/filters.py +20 -13
- vectordb_bench/frontend/components/check_results/headerIcon.py +1 -1
- vectordb_bench/frontend/components/check_results/priceTable.py +1 -1
- vectordb_bench/frontend/components/check_results/stPageConfig.py +1 -1
- vectordb_bench/frontend/components/concurrent/charts.py +26 -29
- vectordb_bench/frontend/components/custom/displayCustomCase.py +31 -0
- vectordb_bench/frontend/components/custom/displaypPrams.py +11 -0
- vectordb_bench/frontend/components/custom/getCustomConfig.py +40 -0
- vectordb_bench/frontend/components/custom/initStyle.py +15 -0
- vectordb_bench/frontend/components/run_test/autoRefresh.py +1 -1
- vectordb_bench/frontend/components/run_test/caseSelector.py +50 -28
- vectordb_bench/frontend/components/run_test/dbConfigSetting.py +37 -19
- vectordb_bench/frontend/components/run_test/dbSelector.py +2 -14
- vectordb_bench/frontend/components/run_test/generateTasks.py +3 -5
- vectordb_bench/frontend/components/run_test/initStyle.py +16 -0
- vectordb_bench/frontend/components/run_test/submitTask.py +1 -1
- vectordb_bench/frontend/{const → config}/dbCaseConfigs.py +311 -40
- vectordb_bench/frontend/{const → config}/styles.py +2 -0
- vectordb_bench/frontend/pages/concurrent.py +11 -18
- vectordb_bench/frontend/pages/custom.py +64 -0
- vectordb_bench/frontend/pages/quries_per_dollar.py +5 -5
- vectordb_bench/frontend/pages/run_test.py +4 -0
- vectordb_bench/frontend/pages/tables.py +2 -2
- vectordb_bench/frontend/utils.py +17 -1
- vectordb_bench/frontend/vdb_benchmark.py +3 -3
- vectordb_bench/models.py +26 -10
- vectordb_bench/results/getLeaderboardData.py +1 -1
- {vectordb_bench-0.0.11.dist-info → vectordb_bench-0.0.13.dist-info}/METADATA +46 -15
- {vectordb_bench-0.0.11.dist-info → vectordb_bench-0.0.13.dist-info}/RECORD +57 -40
- {vectordb_bench-0.0.11.dist-info → vectordb_bench-0.0.13.dist-info}/WHEEL +1 -1
- /vectordb_bench/frontend/{const → config}/dbPrices.py +0 -0
- {vectordb_bench-0.0.11.dist-info → vectordb_bench-0.0.13.dist-info}/LICENSE +0 -0
- {vectordb_bench-0.0.11.dist-info → vectordb_bench-0.0.13.dist-info}/entry_points.txt +0 -0
- {vectordb_bench-0.0.11.dist-info → vectordb_bench-0.0.13.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
from vectordb_bench.frontend.components.custom.getCustomConfig import CustomCaseConfig
|
3
|
+
|
4
|
+
|
5
|
+
def displayCustomCase(customCase: CustomCaseConfig, st, key):
|
6
|
+
|
7
|
+
columns = st.columns([1, 2])
|
8
|
+
customCase.dataset_config.name = columns[0].text_input(
|
9
|
+
"Name", key=f"{key}_name", value=customCase.dataset_config.name)
|
10
|
+
customCase.name = f"{customCase.dataset_config.name} (Performace Case)"
|
11
|
+
customCase.dataset_config.dir = columns[1].text_input(
|
12
|
+
"Folder Path", key=f"{key}_dir", value=customCase.dataset_config.dir)
|
13
|
+
|
14
|
+
columns = st.columns(4)
|
15
|
+
customCase.dataset_config.dim = columns[0].number_input(
|
16
|
+
"dim", key=f"{key}_dim", value=customCase.dataset_config.dim)
|
17
|
+
customCase.dataset_config.size = columns[1].number_input(
|
18
|
+
"size", key=f"{key}_size", value=customCase.dataset_config.size)
|
19
|
+
customCase.dataset_config.metric_type = columns[2].selectbox(
|
20
|
+
"metric type", key=f"{key}_metric_type", options=["L2", "Cosine", "IP"])
|
21
|
+
customCase.dataset_config.file_count = columns[3].number_input(
|
22
|
+
"train file count", key=f"{key}_file_count", value=customCase.dataset_config.file_count)
|
23
|
+
|
24
|
+
columns = st.columns(4)
|
25
|
+
customCase.dataset_config.use_shuffled = columns[0].checkbox(
|
26
|
+
"use shuffled data", key=f"{key}_use_shuffled", value=customCase.dataset_config.use_shuffled)
|
27
|
+
customCase.dataset_config.with_gt = columns[1].checkbox(
|
28
|
+
"with groundtruth", key=f"{key}_with_gt", value=customCase.dataset_config.with_gt)
|
29
|
+
|
30
|
+
customCase.description = st.text_area(
|
31
|
+
"description", key=f"{key}_description", value=customCase.description)
|
@@ -0,0 +1,11 @@
|
|
1
|
+
def displayParams(st):
|
2
|
+
st.markdown("""
|
3
|
+
- `Folder Path` - The path to the folder containing all the files. Please ensure that all files in the folder are in the `Parquet` format.
|
4
|
+
- Vectors data files: The file must be named `train.parquet` and should have two columns: `id` as an incrementing `int` and `emb` as an array of `float32`.
|
5
|
+
- Query test vectors: The file must be named `test.parquet` and should have two columns: `id` as an incrementing `int` and `emb` as an array of `float32`.
|
6
|
+
- Ground truth file: The file must be named `neighbors.parquet` and should have two columns: `id` corresponding to query vectors and `neighbors_id` as an array of `int`.
|
7
|
+
|
8
|
+
- `Train File Count` - If the vector file is too large, you can consider splitting it into multiple files. The naming format for the split files should be `train-[index]-of-[file_count].parquet`. For example, `train-01-of-10.parquet` represents the second file (0-indexed) among 10 split files.
|
9
|
+
|
10
|
+
- `Use Shuffled Data` - If you check this option, the vector data files need to be modified. VectorDBBench will load the data labeled with `shuffle`. For example, use `shuffle_train.parquet` instead of `train.parquet` and `shuffle_train-04-of-10.parquet` instead of `train-04-of-10.parquet`. The `id` column in the shuffled data can be in any order.
|
11
|
+
""")
|
@@ -0,0 +1,40 @@
|
|
1
|
+
import json
|
2
|
+
|
3
|
+
from pydantic import BaseModel
|
4
|
+
|
5
|
+
from vectordb_bench import config
|
6
|
+
|
7
|
+
|
8
|
+
class CustomDatasetConfig(BaseModel):
|
9
|
+
name: str = "custom_dataset"
|
10
|
+
dir: str = ""
|
11
|
+
size: int = 0
|
12
|
+
dim: int = 0
|
13
|
+
metric_type: str = "L2"
|
14
|
+
file_count: int = 1
|
15
|
+
use_shuffled: bool = False
|
16
|
+
with_gt: bool = True
|
17
|
+
|
18
|
+
|
19
|
+
class CustomCaseConfig(BaseModel):
|
20
|
+
name: str = "custom_dataset (Performace Case)"
|
21
|
+
description: str = ""
|
22
|
+
load_timeout: int = 36000
|
23
|
+
optimize_timeout: int = 36000
|
24
|
+
dataset_config: CustomDatasetConfig = CustomDatasetConfig()
|
25
|
+
|
26
|
+
|
27
|
+
def get_custom_configs():
|
28
|
+
with open(config.CUSTOM_CONFIG_DIR, "r") as f:
|
29
|
+
custom_configs = json.load(f)
|
30
|
+
return [CustomCaseConfig(**custom_config) for custom_config in custom_configs]
|
31
|
+
|
32
|
+
|
33
|
+
def save_custom_configs(custom_configs: list[CustomDatasetConfig]):
|
34
|
+
with open(config.CUSTOM_CONFIG_DIR, "w") as f:
|
35
|
+
json.dump([custom_config.dict()
|
36
|
+
for custom_config in custom_configs], f, indent=4)
|
37
|
+
|
38
|
+
|
39
|
+
def generate_custom_case():
|
40
|
+
return CustomCaseConfig()
|
@@ -0,0 +1,15 @@
|
|
1
|
+
def initStyle(st):
|
2
|
+
st.markdown(
|
3
|
+
"""<style>
|
4
|
+
/* expander - header */
|
5
|
+
.main div[data-testid='stExpander'] summary p {font-size: 20px; font-weight: 600;}
|
6
|
+
/*
|
7
|
+
button {
|
8
|
+
height: auto;
|
9
|
+
padding-left: 8px !important;
|
10
|
+
padding-right: 6px !important;
|
11
|
+
}
|
12
|
+
*/
|
13
|
+
</style>""",
|
14
|
+
unsafe_allow_html=True,
|
15
|
+
)
|
@@ -1,9 +1,13 @@
|
|
1
|
-
|
1
|
+
|
2
|
+
from vectordb_bench.frontend.config.styles import *
|
2
3
|
from vectordb_bench.backend.cases import CaseType
|
3
|
-
from vectordb_bench.frontend.
|
4
|
+
from vectordb_bench.frontend.config.dbCaseConfigs import *
|
5
|
+
from collections import defaultdict
|
6
|
+
|
7
|
+
from vectordb_bench.frontend.utils import addHorizontalLine
|
4
8
|
|
5
9
|
|
6
|
-
def caseSelector(st, activedDbList):
|
10
|
+
def caseSelector(st, activedDbList: list[DB]):
|
7
11
|
st.markdown(
|
8
12
|
"<div style='height: 24px;'></div>",
|
9
13
|
unsafe_allow_html=True,
|
@@ -14,41 +18,49 @@ def caseSelector(st, activedDbList):
|
|
14
18
|
unsafe_allow_html=True,
|
15
19
|
)
|
16
20
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
21
|
+
activedCaseList: list[CaseConfig] = []
|
22
|
+
dbToCaseClusterConfigs = defaultdict(lambda: defaultdict(dict))
|
23
|
+
dbToCaseConfigs = defaultdict(lambda: defaultdict(dict))
|
24
|
+
caseClusters = UI_CASE_CLUSTERS + [get_custom_case_cluter()]
|
25
|
+
for caseCluster in caseClusters:
|
26
|
+
activedCaseList += caseClusterExpander(
|
27
|
+
st, caseCluster, dbToCaseClusterConfigs, activedDbList)
|
28
|
+
for db in dbToCaseClusterConfigs:
|
29
|
+
for uiCaseItem in dbToCaseClusterConfigs[db]:
|
30
|
+
for case in uiCaseItem.cases:
|
31
|
+
dbToCaseConfigs[db][case] = dbToCaseClusterConfigs[db][uiCaseItem]
|
32
|
+
|
33
|
+
return activedCaseList, dbToCaseConfigs
|
34
|
+
|
35
|
+
|
36
|
+
def caseClusterExpander(st, caseCluster: UICaseItemCluster, dbToCaseClusterConfigs, activedDbList: list[DB]):
|
37
|
+
expander = st.expander(caseCluster.label, False)
|
38
|
+
activedCases: list[CaseConfig] = []
|
39
|
+
for uiCaseItem in caseCluster.uiCaseItems:
|
40
|
+
if uiCaseItem.isLine:
|
41
|
+
addHorizontalLine(expander)
|
25
42
|
else:
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
caseItemContainer, allCaseConfigs, case, activedDbList
|
30
|
-
)
|
31
|
-
activedCaseList = [case for case in CASE_LIST if caseIsActived[case]]
|
32
|
-
return activedCaseList, allCaseConfigs
|
43
|
+
activedCases += caseItemCheckbox(expander,
|
44
|
+
dbToCaseClusterConfigs, uiCaseItem, activedDbList)
|
45
|
+
return activedCases
|
33
46
|
|
34
47
|
|
35
|
-
def
|
36
|
-
selected = st.checkbox(
|
48
|
+
def caseItemCheckbox(st, dbToCaseClusterConfigs, uiCaseItem: UICaseItem, activedDbList: list[DB]):
|
49
|
+
selected = st.checkbox(uiCaseItem.label)
|
37
50
|
st.markdown(
|
38
|
-
f"<div style='color: #1D2939; margin: -8px 0 20px {CHECKBOX_INDENT}px; font-size: 14px;'>{
|
51
|
+
f"<div style='color: #1D2939; margin: -8px 0 20px {CHECKBOX_INDENT}px; font-size: 14px;'>{uiCaseItem.description}</div>",
|
39
52
|
unsafe_allow_html=True,
|
40
53
|
)
|
41
54
|
|
42
55
|
if selected:
|
43
|
-
caseConfigSettingContainer = st.container()
|
44
56
|
caseConfigSetting(
|
45
|
-
|
57
|
+
st.container(), dbToCaseClusterConfigs, uiCaseItem, activedDbList
|
46
58
|
)
|
47
59
|
|
48
|
-
return selected
|
60
|
+
return uiCaseItem.cases if selected else []
|
49
61
|
|
50
62
|
|
51
|
-
def caseConfigSetting(st,
|
63
|
+
def caseConfigSetting(st, dbToCaseClusterConfigs, uiCaseItem: UICaseItem, activedDbList: list[DB]):
|
52
64
|
for db in activedDbList:
|
53
65
|
columns = st.columns(1 + CASE_CONFIG_SETTING_COLUMNS)
|
54
66
|
# column 0 - title
|
@@ -57,12 +69,12 @@ def caseConfigSetting(st, allCaseConfigs, case, activedDbList):
|
|
57
69
|
f"<div style='margin: 0 0 24px {CHECKBOX_INDENT}px; font-size: 18px; font-weight: 600;'>{db.name}</div>",
|
58
70
|
unsafe_allow_html=True,
|
59
71
|
)
|
60
|
-
caseConfig = allCaseConfigs[db][case]
|
61
72
|
k = 0
|
62
|
-
|
73
|
+
caseConfig = dbToCaseClusterConfigs[db][uiCaseItem]
|
74
|
+
for config in CASE_CONFIG_MAP.get(db, {}).get(uiCaseItem.caseLabel, []):
|
63
75
|
if config.isDisplayed(caseConfig):
|
64
76
|
column = columns[1 + k % CASE_CONFIG_SETTING_COLUMNS]
|
65
|
-
key = "%s-%s-%s" % (db,
|
77
|
+
key = "%s-%s-%s" % (db, uiCaseItem.label, config.label.value)
|
66
78
|
if config.inputType == InputType.Text:
|
67
79
|
caseConfig[config.label] = column.text_input(
|
68
80
|
config.displayLabel if config.displayLabel else config.label.value,
|
@@ -88,6 +100,16 @@ def caseConfigSetting(st, allCaseConfigs, case, activedDbList):
|
|
88
100
|
value=config.inputConfig["value"],
|
89
101
|
help=config.inputHelp,
|
90
102
|
)
|
103
|
+
elif config.inputType == InputType.Float:
|
104
|
+
caseConfig[config.label] = column.number_input(
|
105
|
+
config.displayLabel if config.displayLabel else config.label.value,
|
106
|
+
step=config.inputConfig.get("step", 0.1),
|
107
|
+
min_value=config.inputConfig["min"],
|
108
|
+
max_value=config.inputConfig["max"],
|
109
|
+
key=key,
|
110
|
+
value=config.inputConfig["value"],
|
111
|
+
help=config.inputHelp,
|
112
|
+
)
|
91
113
|
k += 1
|
92
114
|
if k == 0:
|
93
115
|
columns[1].write("Auto")
|
@@ -1,13 +1,10 @@
|
|
1
1
|
from pydantic import ValidationError
|
2
|
-
from vectordb_bench.
|
2
|
+
from vectordb_bench.backend.clients import DB
|
3
|
+
from vectordb_bench.frontend.config.styles import DB_CONFIG_SETTING_COLUMNS
|
3
4
|
from vectordb_bench.frontend.utils import inputIsPassword
|
4
5
|
|
5
6
|
|
6
|
-
def dbConfigSettings(st, activedDbList):
|
7
|
-
st.markdown(
|
8
|
-
"<style> .streamlit-expanderHeader p {font-size: 20px; font-weight: 600;}</style>",
|
9
|
-
unsafe_allow_html=True,
|
10
|
-
)
|
7
|
+
def dbConfigSettings(st, activedDbList: list[DB]):
|
11
8
|
expander = st.expander("Configurations for the selected databases", True)
|
12
9
|
|
13
10
|
dbConfigs = {}
|
@@ -31,7 +28,7 @@ def dbConfigSettings(st, activedDbList):
|
|
31
28
|
return dbConfigs, isAllValid
|
32
29
|
|
33
30
|
|
34
|
-
def dbConfigSettingItem(st, activeDb):
|
31
|
+
def dbConfigSettingItem(st, activeDb: DB):
|
35
32
|
st.markdown(
|
36
33
|
f"<div style='font-weight: 600; font-size: 20px; margin-top: 16px;'>{activeDb.value}</div>",
|
37
34
|
unsafe_allow_html=True,
|
@@ -40,20 +37,41 @@ def dbConfigSettingItem(st, activeDb):
|
|
40
37
|
|
41
38
|
dbConfigClass = activeDb.config_cls
|
42
39
|
properties = dbConfigClass.schema().get("properties")
|
43
|
-
propertiesItems = list(properties.items())
|
44
|
-
moveDBLabelToLast(propertiesItems)
|
45
40
|
dbConfig = {}
|
46
|
-
|
47
|
-
|
48
|
-
|
41
|
+
idx = 0
|
42
|
+
|
43
|
+
# db config (unique)
|
44
|
+
for key, property in properties.items():
|
45
|
+
if (
|
46
|
+
key not in dbConfigClass.common_short_configs()
|
47
|
+
and key not in dbConfigClass.common_long_configs()
|
48
|
+
):
|
49
|
+
column = columns[idx % DB_CONFIG_SETTING_COLUMNS]
|
50
|
+
idx += 1
|
51
|
+
dbConfig[key] = column.text_input(
|
52
|
+
key,
|
53
|
+
key="%s-%s" % (activeDb.name, key),
|
54
|
+
value=property.get("default", ""),
|
55
|
+
type="password" if inputIsPassword(key) else "default",
|
56
|
+
)
|
57
|
+
# db config (common short labels)
|
58
|
+
for key in dbConfigClass.common_short_configs():
|
59
|
+
column = columns[idx % DB_CONFIG_SETTING_COLUMNS]
|
60
|
+
idx += 1
|
49
61
|
dbConfig[key] = column.text_input(
|
50
62
|
key,
|
51
|
-
key="%s-%s" % (activeDb, key),
|
52
|
-
value=
|
53
|
-
type="
|
63
|
+
key="%s-%s" % (activeDb.name, key),
|
64
|
+
value="",
|
65
|
+
type="default",
|
66
|
+
placeholder="optional, for labeling results",
|
54
67
|
)
|
55
|
-
return dbConfig
|
56
68
|
|
57
|
-
|
58
|
-
|
59
|
-
|
69
|
+
# db config (common long text_input)
|
70
|
+
for key in dbConfigClass.common_long_configs():
|
71
|
+
dbConfig[key] = st.text_area(
|
72
|
+
key,
|
73
|
+
key="%s-%s" % (activeDb.name, key),
|
74
|
+
value="",
|
75
|
+
placeholder="optional",
|
76
|
+
)
|
77
|
+
return dbConfig
|
@@ -1,7 +1,6 @@
|
|
1
1
|
from streamlit.runtime.media_file_storage import MediaFileStorageError
|
2
|
-
|
3
|
-
from vectordb_bench.frontend.
|
4
|
-
from vectordb_bench.frontend.const.dbCaseConfigs import DB_LIST
|
2
|
+
from vectordb_bench.frontend.config.styles import DB_SELECTOR_COLUMNS, DB_TO_ICON
|
3
|
+
from vectordb_bench.frontend.config.dbCaseConfigs import DB_LIST
|
5
4
|
|
6
5
|
|
7
6
|
def dbSelector(st):
|
@@ -18,17 +17,6 @@ def dbSelector(st):
|
|
18
17
|
dbContainerColumns = st.columns(DB_SELECTOR_COLUMNS, gap="small")
|
19
18
|
dbIsActived = {db: False for db in DB_LIST}
|
20
19
|
|
21
|
-
# style - image; column gap; checkbox font;
|
22
|
-
st.markdown(
|
23
|
-
"""
|
24
|
-
<style>
|
25
|
-
div[data-testid='stImage'] {margin: auto;}
|
26
|
-
div[data-testid='stHorizontalBlock'] {gap: 8px;}
|
27
|
-
.stCheckbox p { color: #000; font-size: 18px; font-weight: 600; }
|
28
|
-
</style>
|
29
|
-
""",
|
30
|
-
unsafe_allow_html=True,
|
31
|
-
)
|
32
20
|
for i, db in enumerate(DB_LIST):
|
33
21
|
column = dbContainerColumns[i % DB_SELECTOR_COLUMNS]
|
34
22
|
dbIsActived[db] = column.checkbox(db.name)
|
@@ -1,17 +1,15 @@
|
|
1
|
+
from vectordb_bench.backend.clients import DB
|
1
2
|
from vectordb_bench.models import CaseConfig, CaseConfigParamType, TaskConfig
|
2
3
|
|
3
4
|
|
4
|
-
def generate_tasks(activedDbList, dbConfigs, activedCaseList, allCaseConfigs):
|
5
|
+
def generate_tasks(activedDbList: list[DB], dbConfigs, activedCaseList: list[CaseConfig], allCaseConfigs):
|
5
6
|
tasks = []
|
6
7
|
for db in activedDbList:
|
7
8
|
for case in activedCaseList:
|
8
9
|
task = TaskConfig(
|
9
10
|
db=db.value,
|
10
11
|
db_config=dbConfigs[db],
|
11
|
-
case_config=
|
12
|
-
case_id=case.value,
|
13
|
-
custom_case={},
|
14
|
-
),
|
12
|
+
case_config=case,
|
15
13
|
db_case_config=db.case_config_cls(
|
16
14
|
allCaseConfigs[db][case].get(CaseConfigParamType.IndexType, None)
|
17
15
|
)(**{key.value: value for key, value in allCaseConfigs[db][case].items()}),
|
@@ -0,0 +1,16 @@
|
|
1
|
+
def initStyle(st):
|
2
|
+
st.markdown(
|
3
|
+
"""<style>
|
4
|
+
/* expander - header */
|
5
|
+
.main div[data-testid='stExpander'] p {font-size: 18px; font-weight: 600;}
|
6
|
+
/* db icon */
|
7
|
+
div[data-testid='stImage'] {margin: auto;}
|
8
|
+
/* db column gap */
|
9
|
+
div[data-testid='stHorizontalBlock'] {gap: 8px;}
|
10
|
+
/* check box */
|
11
|
+
.stCheckbox p { color: #000; font-size: 18px; font-weight: 600; }
|
12
|
+
/* db selector - db_name should not wrap */
|
13
|
+
div[data-testid="stVerticalBlockBorderWrapper"] div[data-testid="stCheckbox"] div[data-testid="stWidgetLabel"] p { white-space: nowrap; }
|
14
|
+
</style>""",
|
15
|
+
unsafe_allow_html=True,
|
16
|
+
)
|