vectra-client 0.4.0 → 1.0.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -12
- data/README.md +108 -15
- data/docs/_layouts/default.html +97 -2
- data/docs/_layouts/home.html +408 -4
- data/docs/_layouts/page.html +38 -2
- data/docs/api/overview.md +92 -0
- data/docs/assets/favicon.svg +8 -0
- data/docs/assets/logo.svg +10 -0
- data/docs/assets/radme.png +0 -0
- data/docs/assets/readme-new.png +0 -0
- data/docs/assets/seo.png +0 -0
- data/docs/assets/style.css +389 -24
- data/docs/guides/getting-started.md +61 -0
- data/docs/guides/performance.md +35 -1
- data/docs/index.md +8 -0
- data/docs/providers/pgvector.md +12 -0
- data/docs/providers/pinecone.md +10 -0
- data/docs/providers/qdrant.md +8 -0
- data/docs/providers/weaviate.md +10 -0
- data/examples/README.md +18 -0
- data/lib/generators/vectra/index_generator.rb +157 -0
- data/lib/vectra/client.rb +65 -0
- data/lib/vectra/errors.rb +3 -0
- data/lib/vectra/providers/pgvector.rb +68 -0
- data/lib/vectra/providers/pinecone.rb +57 -0
- data/lib/vectra/providers/qdrant.rb +59 -0
- data/lib/vectra/providers/weaviate.rb +85 -0
- data/lib/vectra/version.rb +1 -1
- metadata +7 -1
data/docs/assets/style.css
CHANGED
|
@@ -4,34 +4,34 @@
|
|
|
4
4
|
|
|
5
5
|
/* CSS Custom Properties */
|
|
6
6
|
:root {
|
|
7
|
-
/* Color Palette -
|
|
8
|
-
--tma-color-bg-primary: #
|
|
9
|
-
--tma-color-bg-secondary: #
|
|
10
|
-
--tma-color-bg-tertiary: #
|
|
11
|
-
--tma-color-bg-elevated: #
|
|
12
|
-
--tma-color-bg-hover: #
|
|
7
|
+
/* Color Palette - Deep Navy + Coral Accent */
|
|
8
|
+
--tma-color-bg-primary: #0c1a3f;
|
|
9
|
+
--tma-color-bg-secondary: #111f4b;
|
|
10
|
+
--tma-color-bg-tertiary: #17265c;
|
|
11
|
+
--tma-color-bg-elevated: #1f2f70;
|
|
12
|
+
--tma-color-bg-hover: #24367d;
|
|
13
13
|
|
|
14
|
-
/* Accent Colors - Based on #
|
|
15
|
-
--tma-color-accent-primary: #
|
|
16
|
-
--tma-color-accent-light: #
|
|
17
|
-
--tma-color-accent-dark: #
|
|
18
|
-
--tma-color-accent-muted: rgba(
|
|
14
|
+
/* Accent Colors - Based on logo (#e19e96) */
|
|
15
|
+
--tma-color-accent-primary: #e19e96;
|
|
16
|
+
--tma-color-accent-light: #f1b4aa;
|
|
17
|
+
--tma-color-accent-dark: #c46f63;
|
|
18
|
+
--tma-color-accent-muted: rgba(225, 158, 150, 0.16);
|
|
19
19
|
|
|
20
20
|
/* Text Colors */
|
|
21
21
|
--tma-color-text-primary: #f4f4f5;
|
|
22
|
-
--tma-color-text-secondary: #
|
|
23
|
-
--tma-color-text-muted: #
|
|
24
|
-
--tma-color-text-accent: #
|
|
22
|
+
--tma-color-text-secondary: #c1c2d0;
|
|
23
|
+
--tma-color-text-muted: #8b8ca0;
|
|
24
|
+
--tma-color-text-accent: #e19e96;
|
|
25
25
|
|
|
26
26
|
/* Border Colors */
|
|
27
27
|
--tma-color-border: rgba(255, 255, 255, 0.08);
|
|
28
|
-
--tma-color-border-hover: rgba(
|
|
28
|
+
--tma-color-border-hover: rgba(225, 158, 150, 0.6);
|
|
29
29
|
|
|
30
30
|
/* Shadows */
|
|
31
31
|
--tma-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
|
|
32
32
|
--tma-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.5);
|
|
33
33
|
--tma-shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.6);
|
|
34
|
-
--tma-shadow-glow: 0 0 30px rgba(
|
|
34
|
+
--tma-shadow-glow: 0 0 30px rgba(225, 158, 150, 0.35);
|
|
35
35
|
|
|
36
36
|
/* Typography */
|
|
37
37
|
--tma-font-family-primary: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
@@ -98,7 +98,7 @@ body {
|
|
|
98
98
|
left: 0;
|
|
99
99
|
right: 0;
|
|
100
100
|
height: var(--tma-header-height);
|
|
101
|
-
background: rgba(
|
|
101
|
+
background: rgba(12, 26, 63, 0.96);
|
|
102
102
|
backdrop-filter: blur(12px);
|
|
103
103
|
border-bottom: 1px solid var(--tma-color-border);
|
|
104
104
|
z-index: 1000;
|
|
@@ -119,15 +119,16 @@ body {
|
|
|
119
119
|
align-items: center;
|
|
120
120
|
gap: var(--tma-spacing-sm);
|
|
121
121
|
text-decoration: none;
|
|
122
|
-
|
|
123
|
-
font-weight: 800;
|
|
124
|
-
color: var(--tma-color-accent-primary);
|
|
125
|
-
letter-spacing: -0.02em;
|
|
122
|
+
color: var(--tma-color-text-primary);
|
|
126
123
|
}
|
|
127
124
|
|
|
128
125
|
.tma-nav__brand::before {
|
|
129
|
-
content: '
|
|
130
|
-
|
|
126
|
+
content: '';
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.tma-nav__logo {
|
|
130
|
+
width: 110px;
|
|
131
|
+
display: block;
|
|
131
132
|
}
|
|
132
133
|
|
|
133
134
|
.tma-nav__menu {
|
|
@@ -220,7 +221,7 @@ body {
|
|
|
220
221
|
gap: var(--tma-spacing-sm);
|
|
221
222
|
padding: var(--tma-spacing-xs) var(--tma-spacing-md);
|
|
222
223
|
background: var(--tma-color-accent-muted);
|
|
223
|
-
border: 1px solid rgba(
|
|
224
|
+
border: 1px solid rgba(225, 158, 150, 0.3);
|
|
224
225
|
border-radius: 100px;
|
|
225
226
|
font-size: 0.85rem;
|
|
226
227
|
font-weight: 500;
|
|
@@ -696,6 +697,370 @@ code {
|
|
|
696
697
|
color: var(--tma-color-text-secondary);
|
|
697
698
|
}
|
|
698
699
|
|
|
700
|
+
/* Comparison Table Styles */
|
|
701
|
+
.tma-comparison {
|
|
702
|
+
padding: var(--tma-spacing-3xl) var(--tma-spacing-xl);
|
|
703
|
+
max-width: var(--tma-max-width);
|
|
704
|
+
margin: 0 auto;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
.tma-comparison-table {
|
|
708
|
+
width: 100%;
|
|
709
|
+
border-collapse: collapse;
|
|
710
|
+
margin: var(--tma-spacing-xl) 0;
|
|
711
|
+
background: var(--tma-color-bg-secondary);
|
|
712
|
+
border-radius: var(--tma-radius-lg);
|
|
713
|
+
overflow: hidden;
|
|
714
|
+
border: 1px solid var(--tma-color-border);
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
.tma-comparison-table thead {
|
|
718
|
+
background: var(--tma-color-bg-tertiary);
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
.tma-comparison-table th {
|
|
722
|
+
padding: var(--tma-spacing-md) var(--tma-spacing-lg);
|
|
723
|
+
text-align: left;
|
|
724
|
+
font-weight: 600;
|
|
725
|
+
color: var(--tma-color-text-primary);
|
|
726
|
+
font-size: 0.9rem;
|
|
727
|
+
border-bottom: 2px solid var(--tma-color-border);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
.tma-comparison-table th:first-child {
|
|
731
|
+
font-weight: 700;
|
|
732
|
+
color: var(--tma-color-accent-primary);
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
.tma-comparison-table td {
|
|
736
|
+
padding: var(--tma-spacing-md) var(--tma-spacing-lg);
|
|
737
|
+
border-bottom: 1px solid var(--tma-color-border);
|
|
738
|
+
color: var(--tma-color-text-secondary);
|
|
739
|
+
font-size: 0.9rem;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
.tma-comparison-table tbody tr:hover {
|
|
743
|
+
background: var(--tma-color-bg-hover);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
.tma-comparison-table tbody tr:last-child td {
|
|
747
|
+
border-bottom: none;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
.tma-comparison-table .tma-check {
|
|
751
|
+
color: var(--tma-color-accent-primary);
|
|
752
|
+
font-weight: 600;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
.tma-comparison-table .tma-partial {
|
|
756
|
+
color: #fbbf24;
|
|
757
|
+
font-weight: 500;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
.tma-comparison-table .tma-cross {
|
|
761
|
+
color: var(--tma-color-text-muted);
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
/* Advantages Section */
|
|
765
|
+
.tma-advantages {
|
|
766
|
+
padding: var(--tma-spacing-3xl) var(--tma-spacing-xl);
|
|
767
|
+
max-width: var(--tma-max-width);
|
|
768
|
+
margin: 0 auto;
|
|
769
|
+
background: var(--tma-color-bg-secondary);
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
.tma-advantages__grid {
|
|
773
|
+
display: grid;
|
|
774
|
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
775
|
+
gap: var(--tma-spacing-lg);
|
|
776
|
+
margin-top: var(--tma-spacing-xl);
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
.tma-advantage-card {
|
|
780
|
+
padding: var(--tma-spacing-xl);
|
|
781
|
+
background: var(--tma-color-bg-tertiary);
|
|
782
|
+
border: 1px solid var(--tma-color-border);
|
|
783
|
+
border-radius: var(--tma-radius-lg);
|
|
784
|
+
border-left: 3px solid var(--tma-color-accent-primary);
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
.tma-advantage-card__title {
|
|
788
|
+
font-size: 1.1rem;
|
|
789
|
+
font-weight: 700;
|
|
790
|
+
margin-bottom: var(--tma-spacing-md);
|
|
791
|
+
color: var(--tma-color-text-primary);
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
.tma-advantage-card__list {
|
|
795
|
+
list-style: none;
|
|
796
|
+
padding: 0;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
.tma-advantage-card__list li {
|
|
800
|
+
padding: var(--tma-spacing-xs) 0;
|
|
801
|
+
color: var(--tma-color-text-secondary);
|
|
802
|
+
font-size: 0.9rem;
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
.tma-advantage-card__list li::before {
|
|
806
|
+
content: '✓';
|
|
807
|
+
color: var(--tma-color-accent-primary);
|
|
808
|
+
font-weight: 700;
|
|
809
|
+
margin-right: var(--tma-spacing-sm);
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
/* Choose Section */
|
|
813
|
+
.tma-choose {
|
|
814
|
+
padding: var(--tma-spacing-3xl) var(--tma-spacing-xl);
|
|
815
|
+
max-width: var(--tma-max-width);
|
|
816
|
+
margin: 0 auto;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
.tma-choose__grid {
|
|
820
|
+
display: grid;
|
|
821
|
+
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
|
822
|
+
gap: var(--tma-spacing-lg);
|
|
823
|
+
margin-top: var(--tma-spacing-xl);
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
.tma-choose-card {
|
|
827
|
+
padding: var(--tma-spacing-xl);
|
|
828
|
+
background: var(--tma-color-bg-secondary);
|
|
829
|
+
border: 1px solid var(--tma-color-border);
|
|
830
|
+
border-radius: var(--tma-radius-lg);
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
.tma-choose-card__title {
|
|
834
|
+
font-size: 1.1rem;
|
|
835
|
+
font-weight: 700;
|
|
836
|
+
margin-bottom: var(--tma-spacing-md);
|
|
837
|
+
color: var(--tma-color-accent-primary);
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
.tma-choose-card__list {
|
|
841
|
+
list-style: none;
|
|
842
|
+
padding: 0;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
.tma-choose-card__list li {
|
|
846
|
+
padding: var(--tma-spacing-xs) 0;
|
|
847
|
+
color: var(--tma-color-text-secondary);
|
|
848
|
+
font-size: 0.9rem;
|
|
849
|
+
padding-left: var(--tma-spacing-md);
|
|
850
|
+
position: relative;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
.tma-choose-card__list li::before {
|
|
854
|
+
content: '→';
|
|
855
|
+
position: absolute;
|
|
856
|
+
left: 0;
|
|
857
|
+
color: var(--tma-color-accent-primary);
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
/* Visual Charts Section */
|
|
861
|
+
.tma-charts {
|
|
862
|
+
padding: var(--tma-spacing-3xl) var(--tma-spacing-xl);
|
|
863
|
+
max-width: var(--tma-max-width);
|
|
864
|
+
margin: 0 auto;
|
|
865
|
+
background: var(--tma-color-bg-secondary);
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
.tma-charts__grid {
|
|
869
|
+
display: grid;
|
|
870
|
+
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
|
|
871
|
+
gap: var(--tma-spacing-2xl);
|
|
872
|
+
margin-top: var(--tma-spacing-xl);
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
.tma-chart-card {
|
|
876
|
+
padding: var(--tma-spacing-xl);
|
|
877
|
+
background: var(--tma-color-bg-tertiary);
|
|
878
|
+
border: 1px solid var(--tma-color-border);
|
|
879
|
+
border-radius: var(--tma-radius-lg);
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
.tma-chart-card__title {
|
|
883
|
+
font-size: 1.2rem;
|
|
884
|
+
font-weight: 700;
|
|
885
|
+
margin-bottom: var(--tma-spacing-lg);
|
|
886
|
+
color: var(--tma-color-text-primary);
|
|
887
|
+
text-align: center;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
/* Bar Chart Styles */
|
|
891
|
+
.tma-bar-chart {
|
|
892
|
+
margin-top: var(--tma-spacing-lg);
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
.tma-bar-chart__item {
|
|
896
|
+
margin-bottom: var(--tma-spacing-md);
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
.tma-bar-chart__label {
|
|
900
|
+
display: flex;
|
|
901
|
+
justify-content: space-between;
|
|
902
|
+
margin-bottom: var(--tma-spacing-xs);
|
|
903
|
+
font-size: 0.9rem;
|
|
904
|
+
color: var(--tma-color-text-secondary);
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
.tma-bar-chart__name {
|
|
908
|
+
font-weight: 600;
|
|
909
|
+
color: var(--tma-color-text-primary);
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
.tma-bar-chart__value {
|
|
913
|
+
color: var(--tma-color-text-secondary);
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
.tma-bar-chart__bar-container {
|
|
917
|
+
height: 28px;
|
|
918
|
+
background: var(--tma-color-bg-primary);
|
|
919
|
+
border-radius: var(--tma-radius-sm);
|
|
920
|
+
overflow: hidden;
|
|
921
|
+
border: 1px solid var(--tma-color-border);
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
.tma-bar-chart__bar {
|
|
925
|
+
height: 100%;
|
|
926
|
+
background: linear-gradient(90deg, var(--tma-color-accent-primary), var(--tma-color-accent-light));
|
|
927
|
+
border-radius: var(--tma-radius-sm);
|
|
928
|
+
transition: width var(--tma-transition-slow);
|
|
929
|
+
display: flex;
|
|
930
|
+
align-items: center;
|
|
931
|
+
padding: 0 var(--tma-spacing-sm);
|
|
932
|
+
color: #0a0a0f;
|
|
933
|
+
font-weight: 600;
|
|
934
|
+
font-size: 0.85rem;
|
|
935
|
+
min-width: fit-content;
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
.tma-bar-chart__bar--vectra {
|
|
939
|
+
background: linear-gradient(90deg, var(--tma-color-accent-primary), var(--tma-color-accent-light));
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
.tma-bar-chart__bar--langchain {
|
|
943
|
+
background: linear-gradient(90deg, #fbbf24, #fcd34d);
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
.tma-bar-chart__bar--pgvector {
|
|
947
|
+
background: linear-gradient(90deg, #60a5fa, #93c5fd);
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
.tma-bar-chart__bar--qdrant {
|
|
951
|
+
background: linear-gradient(90deg, #a78bfa, #c4b5fd);
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
/* Radar Chart Styles */
|
|
955
|
+
.tma-radar-chart {
|
|
956
|
+
display: flex;
|
|
957
|
+
justify-content: center;
|
|
958
|
+
align-items: center;
|
|
959
|
+
margin: var(--tma-spacing-xl) 0;
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
.tma-radar-chart__container {
|
|
963
|
+
position: relative;
|
|
964
|
+
width: 300px;
|
|
965
|
+
height: 300px;
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
.tma-radar-chart__svg {
|
|
969
|
+
width: 100%;
|
|
970
|
+
height: 100%;
|
|
971
|
+
transform: rotate(-90deg);
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
.tma-radar-chart__axis {
|
|
975
|
+
stroke: var(--tma-color-border);
|
|
976
|
+
stroke-width: 1;
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
.tma-radar-chart__grid {
|
|
980
|
+
stroke: var(--tma-color-border);
|
|
981
|
+
stroke-width: 0.5;
|
|
982
|
+
fill: none;
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
.tma-radar-chart__area {
|
|
986
|
+
fill: var(--tma-color-accent-muted);
|
|
987
|
+
stroke: var(--tma-color-accent-primary);
|
|
988
|
+
stroke-width: 2;
|
|
989
|
+
opacity: 0.6;
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
.tma-radar-chart__point {
|
|
993
|
+
fill: var(--tma-color-accent-primary);
|
|
994
|
+
r: 4;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
.tma-radar-chart__label {
|
|
998
|
+
font-size: 0.75rem;
|
|
999
|
+
fill: var(--tma-color-text-secondary);
|
|
1000
|
+
text-anchor: middle;
|
|
1001
|
+
transform: rotate(90deg);
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
.tma-radar-chart__labels {
|
|
1005
|
+
position: absolute;
|
|
1006
|
+
top: 0;
|
|
1007
|
+
left: 0;
|
|
1008
|
+
right: 0;
|
|
1009
|
+
bottom: 0;
|
|
1010
|
+
display: flex;
|
|
1011
|
+
flex-direction: column;
|
|
1012
|
+
justify-content: space-around;
|
|
1013
|
+
padding: var(--tma-spacing-md);
|
|
1014
|
+
pointer-events: none;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
.tma-radar-chart__label-item {
|
|
1018
|
+
font-size: 0.8rem;
|
|
1019
|
+
color: var(--tma-color-text-secondary);
|
|
1020
|
+
text-align: center;
|
|
1021
|
+
font-weight: 500;
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
/* Responsive Charts */
|
|
1025
|
+
@media (max-width: 768px) {
|
|
1026
|
+
.tma-charts__grid {
|
|
1027
|
+
grid-template-columns: 1fr;
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
.tma-radar-chart__container {
|
|
1031
|
+
width: 250px;
|
|
1032
|
+
height: 250px;
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
/* Responsive Comparison Table */
|
|
1037
|
+
@media (max-width: 1024px) {
|
|
1038
|
+
.tma-comparison-table {
|
|
1039
|
+
font-size: 0.85rem;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
.tma-comparison-table th,
|
|
1043
|
+
.tma-comparison-table td {
|
|
1044
|
+
padding: var(--tma-spacing-sm) var(--tma-spacing-md);
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
@media (max-width: 768px) {
|
|
1049
|
+
.tma-comparison-table {
|
|
1050
|
+
font-size: 0.75rem;
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
.tma-comparison-table th,
|
|
1054
|
+
.tma-comparison-table td {
|
|
1055
|
+
padding: var(--tma-spacing-xs) var(--tma-spacing-sm);
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
.tma-advantages__grid,
|
|
1059
|
+
.tma-choose__grid {
|
|
1060
|
+
grid-template-columns: 1fr;
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
|
|
699
1064
|
/* ============================================
|
|
700
1065
|
Footer
|
|
701
1066
|
============================================ */
|
|
@@ -121,6 +121,52 @@ if status[:error]
|
|
|
121
121
|
end
|
|
122
122
|
```
|
|
123
123
|
|
|
124
|
+
### Hybrid Search (Semantic + Keyword)
|
|
125
|
+
|
|
126
|
+
Combine the best of both worlds: semantic understanding from vectors and exact keyword matching:
|
|
127
|
+
|
|
128
|
+
```ruby
|
|
129
|
+
# Hybrid search with 70% semantic, 30% keyword
|
|
130
|
+
results = client.hybrid_search(
|
|
131
|
+
index: 'docs',
|
|
132
|
+
vector: embedding, # Semantic search
|
|
133
|
+
text: 'ruby programming', # Keyword search
|
|
134
|
+
alpha: 0.7, # 0.0 = pure keyword, 1.0 = pure semantic
|
|
135
|
+
top_k: 10
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
results.each do |match|
|
|
139
|
+
puts "#{match.id}: #{match.score}"
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Pure semantic (alpha = 1.0)
|
|
143
|
+
results = client.hybrid_search(
|
|
144
|
+
index: 'docs',
|
|
145
|
+
vector: embedding,
|
|
146
|
+
text: 'ruby',
|
|
147
|
+
alpha: 1.0
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
# Pure keyword (alpha = 0.0)
|
|
151
|
+
results = client.hybrid_search(
|
|
152
|
+
index: 'docs',
|
|
153
|
+
vector: embedding,
|
|
154
|
+
text: 'ruby programming',
|
|
155
|
+
alpha: 0.0
|
|
156
|
+
)
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Provider Support:**
|
|
160
|
+
- **Qdrant**: ✅ Full support (prefetch + rescore API)
|
|
161
|
+
- **Weaviate**: ✅ Full support (hybrid GraphQL with BM25)
|
|
162
|
+
- **Pinecone**: ⚠️ Partial support (requires sparse vectors for true hybrid search)
|
|
163
|
+
- **pgvector**: ✅ Full support (combines vector similarity + PostgreSQL full-text search)
|
|
164
|
+
|
|
165
|
+
**Note for pgvector:** Your table needs a text column with a tsvector index:
|
|
166
|
+
```sql
|
|
167
|
+
CREATE INDEX idx_content_fts ON my_index USING gin(to_tsvector('english', content));
|
|
168
|
+
```
|
|
169
|
+
|
|
124
170
|
### Dimension Validation
|
|
125
171
|
|
|
126
172
|
Vectra automatically validates that all vectors in a batch have the same dimension:
|
|
@@ -136,6 +182,21 @@ client.upsert(vectors: vectors)
|
|
|
136
182
|
# => ValidationError: Inconsistent vector dimensions at index 1: expected 3, got 2
|
|
137
183
|
```
|
|
138
184
|
|
|
185
|
+
## Rails Generator (vectra:index)
|
|
186
|
+
|
|
187
|
+
For Rails apps, you can generate everything you need for a model with a single command:
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
rails generate vectra:index Product embedding dimension:1536 provider:qdrant
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
This will:
|
|
194
|
+
|
|
195
|
+
- Create a **pgvector migration** when `provider=pgvector` (adds `embedding` vector column)
|
|
196
|
+
- Generate a **model concern** (`ProductVector`) with `has_vector :embedding`
|
|
197
|
+
- Update the **model** to include `ProductVector`
|
|
198
|
+
- Append an entry to **`config/vectra.yml`** with index metadata (no API keys)
|
|
199
|
+
|
|
139
200
|
## Configuration
|
|
140
201
|
|
|
141
202
|
Create a configuration file (Rails: `config/initializers/vectra.rb`):
|
data/docs/guides/performance.md
CHANGED
|
@@ -26,13 +26,47 @@ vectors = 10_000.times.map { |i| { id: "vec_#{i}", values: Array.new(384) { rand
|
|
|
26
26
|
result = batch.upsert_async(
|
|
27
27
|
index: 'my-index',
|
|
28
28
|
vectors: vectors,
|
|
29
|
-
chunk_size: 100
|
|
29
|
+
chunk_size: 100,
|
|
30
|
+
on_progress: proc { |stats|
|
|
31
|
+
progress = stats[:percentage]
|
|
32
|
+
processed = stats[:processed]
|
|
33
|
+
total = stats[:total]
|
|
34
|
+
chunk = stats[:current_chunk] + 1
|
|
35
|
+
total_chunks = stats[:total_chunks]
|
|
36
|
+
|
|
37
|
+
puts "Progress: #{progress}% (#{processed}/#{total})"
|
|
38
|
+
puts " Chunk #{chunk}/#{total_chunks} | Success: #{stats[:success_count]}, Failed: #{stats[:failed_count]}"
|
|
39
|
+
}
|
|
30
40
|
)
|
|
31
41
|
|
|
32
42
|
puts "Upserted: #{result[:upserted_count]} vectors in #{result[:chunks]} chunks"
|
|
33
43
|
puts "Errors: #{result[:errors].size}" if result[:errors].any?
|
|
34
44
|
```
|
|
35
45
|
|
|
46
|
+
### Progress Tracking
|
|
47
|
+
|
|
48
|
+
Monitor batch operations in real-time with progress callbacks:
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
batch.upsert_async(
|
|
52
|
+
index: 'my-index',
|
|
53
|
+
vectors: large_vector_array,
|
|
54
|
+
chunk_size: 100,
|
|
55
|
+
on_progress: proc { |stats|
|
|
56
|
+
# stats contains:
|
|
57
|
+
# - processed: number of processed vectors
|
|
58
|
+
# - total: total number of vectors
|
|
59
|
+
# - percentage: progress percentage (0-100)
|
|
60
|
+
# - current_chunk: current chunk index (0-based)
|
|
61
|
+
# - total_chunks: total number of chunks
|
|
62
|
+
# - success_count: number of successful chunks
|
|
63
|
+
# - failed_count: number of failed chunks
|
|
64
|
+
|
|
65
|
+
puts "Progress: #{stats[:percentage]}% (#{stats[:processed]}/#{stats[:total]})"
|
|
66
|
+
}
|
|
67
|
+
)
|
|
68
|
+
```
|
|
69
|
+
|
|
36
70
|
### Batch Delete
|
|
37
71
|
|
|
38
72
|
```ruby
|
data/docs/index.md
CHANGED
|
@@ -34,4 +34,12 @@ results = client.query(
|
|
|
34
34
|
results.each do |match|
|
|
35
35
|
puts "#{match['id']}: #{match['score']}"
|
|
36
36
|
end
|
|
37
|
+
|
|
38
|
+
# Hybrid search (semantic + keyword)
|
|
39
|
+
results = client.hybrid_search(
|
|
40
|
+
index: 'docs',
|
|
41
|
+
vector: embedding,
|
|
42
|
+
text: 'ruby programming',
|
|
43
|
+
alpha: 0.7 # 70% semantic, 30% keyword
|
|
44
|
+
)
|
|
37
45
|
```
|
data/docs/providers/pgvector.md
CHANGED
|
@@ -43,6 +43,7 @@ client = Vectra::Client.new(
|
|
|
43
43
|
- ✅ ACID transactions
|
|
44
44
|
- ✅ Complex queries
|
|
45
45
|
- ✅ Rails ActiveRecord integration
|
|
46
|
+
- ✅ Hybrid search (vector + full-text search)
|
|
46
47
|
|
|
47
48
|
## Example
|
|
48
49
|
|
|
@@ -63,6 +64,17 @@ client.upsert(
|
|
|
63
64
|
|
|
64
65
|
# Search using cosine distance
|
|
65
66
|
results = client.query(vector: [0.1, 0.2, 0.3], top_k: 5)
|
|
67
|
+
|
|
68
|
+
# Hybrid search (requires text column with tsvector index)
|
|
69
|
+
# First, create the index:
|
|
70
|
+
# CREATE INDEX idx_content_fts ON my_index USING gin(to_tsvector('english', content));
|
|
71
|
+
results = client.hybrid_search(
|
|
72
|
+
index: 'my_index',
|
|
73
|
+
vector: embedding,
|
|
74
|
+
text: 'ruby programming',
|
|
75
|
+
alpha: 0.7,
|
|
76
|
+
text_column: 'content' # default: 'content'
|
|
77
|
+
)
|
|
66
78
|
```
|
|
67
79
|
|
|
68
80
|
## ActiveRecord Integration
|
data/docs/providers/pinecone.md
CHANGED
|
@@ -32,6 +32,7 @@ client = Vectra::Client.new(
|
|
|
32
32
|
- ✅ Index statistics
|
|
33
33
|
- ✅ Metadata filtering
|
|
34
34
|
- ✅ Namespace support
|
|
35
|
+
- ⚠️ Hybrid search (partial - requires sparse vectors)
|
|
35
36
|
|
|
36
37
|
## Example
|
|
37
38
|
|
|
@@ -56,6 +57,15 @@ results = client.query(vector: [0.1, 0.2, 0.3], top_k: 5)
|
|
|
56
57
|
results.matches.each do |match|
|
|
57
58
|
puts "#{match['id']}: #{match['score']}"
|
|
58
59
|
end
|
|
60
|
+
|
|
61
|
+
# Hybrid search (note: requires sparse vectors for true hybrid search)
|
|
62
|
+
# For now, this uses dense vector search only
|
|
63
|
+
results = client.hybrid_search(
|
|
64
|
+
index: 'my-index',
|
|
65
|
+
vector: embedding,
|
|
66
|
+
text: 'ruby programming',
|
|
67
|
+
alpha: 0.7
|
|
68
|
+
)
|
|
59
69
|
```
|
|
60
70
|
|
|
61
71
|
## Configuration Options
|
data/docs/providers/qdrant.md
CHANGED
|
@@ -56,6 +56,14 @@ client.upsert(
|
|
|
56
56
|
|
|
57
57
|
# Search
|
|
58
58
|
results = client.query(vector: [0.1, 0.2, 0.3], top_k: 10)
|
|
59
|
+
|
|
60
|
+
# Hybrid search (semantic + keyword)
|
|
61
|
+
results = client.hybrid_search(
|
|
62
|
+
index: 'my-collection',
|
|
63
|
+
vector: embedding,
|
|
64
|
+
text: 'ruby programming',
|
|
65
|
+
alpha: 0.7 # 70% semantic, 30% keyword
|
|
66
|
+
)
|
|
59
67
|
```
|
|
60
68
|
|
|
61
69
|
## Configuration Options
|
data/docs/providers/weaviate.md
CHANGED
|
@@ -47,6 +47,7 @@ client = Vectra::Client.new(
|
|
|
47
47
|
- ✅ Delete by IDs or filter
|
|
48
48
|
- ✅ List and describe classes
|
|
49
49
|
- ✅ Basic stats via GraphQL `Aggregate`
|
|
50
|
+
- ✅ Hybrid search (BM25 + vector similarity)
|
|
50
51
|
|
|
51
52
|
## Basic Example
|
|
52
53
|
|
|
@@ -89,6 +90,15 @@ results = client.query(
|
|
|
89
90
|
results.each do |match|
|
|
90
91
|
puts "#{match.id} (score=#{match.score.round(3)}): #{match.metadata["title"]}"
|
|
91
92
|
end
|
|
93
|
+
|
|
94
|
+
# Hybrid search (BM25 + vector)
|
|
95
|
+
results = client.hybrid_search(
|
|
96
|
+
index: index,
|
|
97
|
+
vector: embedding,
|
|
98
|
+
text: 'ruby programming',
|
|
99
|
+
alpha: 0.7, # 70% semantic, 30% keyword
|
|
100
|
+
top_k: 10
|
|
101
|
+
)
|
|
92
102
|
```
|
|
93
103
|
|
|
94
104
|
## Advanced Filtering
|
data/examples/README.md
CHANGED
|
@@ -29,6 +29,24 @@ psql vectra_demo -c "CREATE EXTENSION vector;"
|
|
|
29
29
|
|
|
30
30
|
## Examples
|
|
31
31
|
|
|
32
|
+
### Rails Quickstart (with generator)
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# Generate Vectra index for Product model
|
|
36
|
+
rails generate vectra:index Product embedding dimension:1536 provider:qdrant
|
|
37
|
+
|
|
38
|
+
# Run migrations (if pgvector)
|
|
39
|
+
rails db:migrate
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Then in `app/models/product.rb`:
|
|
43
|
+
|
|
44
|
+
```ruby
|
|
45
|
+
class Product < ApplicationRecord
|
|
46
|
+
include ProductVector # generated concern with has_vector :embedding
|
|
47
|
+
end
|
|
48
|
+
```
|
|
49
|
+
|
|
32
50
|
### 1. **Comprehensive Demo** (`comprehensive_demo.rb`)
|
|
33
51
|
|
|
34
52
|
**⭐ START HERE** - Complete production-ready demonstration of all Vectra features.
|