vectra-client 1.0.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 +6 -45
- data/README.md +99 -15
- data/docs/_layouts/default.html +97 -2
- data/docs/_layouts/home.html +408 -4
- data/docs/_layouts/page.html +38 -2
- 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 +15 -0
- data/docs/index.md +8 -0
- data/examples/README.md +18 -0
- data/lib/generators/vectra/index_generator.rb +157 -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
|
============================================ */
|
|
@@ -182,6 +182,21 @@ client.upsert(vectors: vectors)
|
|
|
182
182
|
# => ValidationError: Inconsistent vector dimensions at index 1: expected 3, got 2
|
|
183
183
|
```
|
|
184
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
|
+
|
|
185
200
|
## Configuration
|
|
186
201
|
|
|
187
202
|
Create a configuration file (Rails: `config/initializers/vectra.rb`):
|
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/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.
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators/base"
|
|
4
|
+
|
|
5
|
+
module Vectra
|
|
6
|
+
module Generators
|
|
7
|
+
# Rails generator for creating a vectra-enabled index for a model.
|
|
8
|
+
#
|
|
9
|
+
# @example
|
|
10
|
+
# rails generate vectra:index Product embedding dimension:1536 provider:qdrant
|
|
11
|
+
#
|
|
12
|
+
# This will:
|
|
13
|
+
# - Generate a pgvector migration (when provider=pgvector)
|
|
14
|
+
# - Create a model concern with `has_vector`
|
|
15
|
+
# - Update the model to include the concern
|
|
16
|
+
# - Append an entry to config/vectra.yml (no secrets)
|
|
17
|
+
class IndexGenerator < Rails::Generators::Base
|
|
18
|
+
argument :model_name, type: :string, banner: "ModelName"
|
|
19
|
+
argument :column_name, type: :string, default: "embedding", banner: "column_name"
|
|
20
|
+
|
|
21
|
+
class_option :dimension, type: :numeric, default: 1536,
|
|
22
|
+
desc: "Vector dimension (e.g. 1536 for OpenAI)"
|
|
23
|
+
class_option :provider, type: :string, default: "qdrant",
|
|
24
|
+
desc: "Vector provider (qdrant, pgvector, pinecone, weaviate, memory)"
|
|
25
|
+
class_option :index, type: :string, default: nil,
|
|
26
|
+
desc: "Index/collection name (defaults to table name)"
|
|
27
|
+
|
|
28
|
+
def initialize(args = [], options = {}, config = {})
|
|
29
|
+
super
|
|
30
|
+
@model_name = args[0]&.to_s
|
|
31
|
+
@column_name = (args[1] || "embedding")&.to_s
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def create_migration_for_pgvector
|
|
35
|
+
return unless provider_name == "pgvector"
|
|
36
|
+
|
|
37
|
+
timestamp = Time.now.utc.strftime("%Y%m%d%H%M%S")
|
|
38
|
+
file_name = "#{timestamp}_add_#{column_name.underscore}_to_#{table_name}.rb"
|
|
39
|
+
path = File.join("db/migrate", file_name)
|
|
40
|
+
|
|
41
|
+
migration_body = <<~RUBY
|
|
42
|
+
class Add#{column_name.camelize}To#{table_name.camelize} < ActiveRecord::Migration#{migration_version}
|
|
43
|
+
def change
|
|
44
|
+
add_column :#{table_name}, :#{column_name}, :vector, limit: #{dimension}
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
RUBY
|
|
48
|
+
|
|
49
|
+
create_file(path, migration_body)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def create_model_concern
|
|
53
|
+
path = File.join("app/models/concerns", "#{model_name.underscore}_vector.rb")
|
|
54
|
+
|
|
55
|
+
concern_body = <<~RUBY
|
|
56
|
+
# frozen_string_literal: true
|
|
57
|
+
|
|
58
|
+
module #{concern_module_name}
|
|
59
|
+
extend ActiveSupport::Concern
|
|
60
|
+
|
|
61
|
+
included do
|
|
62
|
+
include Vectra::ActiveRecord
|
|
63
|
+
|
|
64
|
+
has_vector :#{column_name},
|
|
65
|
+
provider: :#{provider_name},
|
|
66
|
+
index: "#{index_name}",
|
|
67
|
+
dimension: #{dimension}
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
RUBY
|
|
71
|
+
|
|
72
|
+
create_file(path, concern_body)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def update_model_file
|
|
76
|
+
path = File.join("app/models", "#{model_name.underscore}.rb")
|
|
77
|
+
|
|
78
|
+
unless File.exist?(path)
|
|
79
|
+
create_file(
|
|
80
|
+
path,
|
|
81
|
+
<<~RUBY
|
|
82
|
+
# frozen_string_literal: true
|
|
83
|
+
|
|
84
|
+
class #{model_name.camelize} < ApplicationRecord
|
|
85
|
+
include #{concern_module_name}
|
|
86
|
+
end
|
|
87
|
+
RUBY
|
|
88
|
+
)
|
|
89
|
+
return
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
content = File.read(path)
|
|
93
|
+
return if content.include?("include #{concern_module_name}")
|
|
94
|
+
|
|
95
|
+
new_content = content.sub(/end\s*\z/, " include #{concern_module_name}\nend\n")
|
|
96
|
+
File.write(path, new_content)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def update_vectra_config
|
|
100
|
+
path = File.join(destination_root || ".", "config", "vectra.yml")
|
|
101
|
+
|
|
102
|
+
existing = File.exist?(path) ? File.read(path) : ""
|
|
103
|
+
entry_key = "#{table_name}:"
|
|
104
|
+
|
|
105
|
+
return if existing.include?(entry_key)
|
|
106
|
+
|
|
107
|
+
header = +"# Vectra index configuration (do NOT store API keys here)\n"
|
|
108
|
+
header << "# Generated by vectra:index for #{model_name}\n\n"
|
|
109
|
+
|
|
110
|
+
config_body = <<~YAML
|
|
111
|
+
#{table_name}:
|
|
112
|
+
provider: #{provider_name}
|
|
113
|
+
index: #{index_name}
|
|
114
|
+
dimension: #{dimension}
|
|
115
|
+
|
|
116
|
+
YAML
|
|
117
|
+
|
|
118
|
+
FileUtils.mkdir_p(File.dirname(path))
|
|
119
|
+
File.write(path, "#{existing.presence || header}#{config_body}")
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
private
|
|
123
|
+
|
|
124
|
+
def model_name
|
|
125
|
+
@model_name || raise("Model name is required")
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def column_name
|
|
129
|
+
@column_name || "embedding"
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def table_name
|
|
133
|
+
model_name.underscore.pluralize
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def provider_name
|
|
137
|
+
options[:provider].to_s
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def index_name
|
|
141
|
+
(options[:index] || table_name).to_s
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def dimension
|
|
145
|
+
options[:dimension].to_i
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def concern_module_name
|
|
149
|
+
"#{model_name.camelize}Vector"
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def migration_version
|
|
153
|
+
"[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
data/lib/vectra/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: vectra-client
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mijo Kristo
|
|
@@ -252,6 +252,11 @@ files:
|
|
|
252
252
|
- docs/_site/robots.txt
|
|
253
253
|
- docs/_site/sitemap.xml
|
|
254
254
|
- docs/api/overview.md
|
|
255
|
+
- docs/assets/favicon.svg
|
|
256
|
+
- docs/assets/logo.svg
|
|
257
|
+
- docs/assets/radme.png
|
|
258
|
+
- docs/assets/readme-new.png
|
|
259
|
+
- docs/assets/seo.png
|
|
255
260
|
- docs/assets/style.css
|
|
256
261
|
- docs/community/contributing.md
|
|
257
262
|
- docs/examples/basic-usage.md
|
|
@@ -282,6 +287,7 @@ files:
|
|
|
282
287
|
- examples/grafana-setup.md
|
|
283
288
|
- examples/instrumentation_demo.rb
|
|
284
289
|
- examples/prometheus-exporter.rb
|
|
290
|
+
- lib/generators/vectra/index_generator.rb
|
|
285
291
|
- lib/generators/vectra/install_generator.rb
|
|
286
292
|
- lib/generators/vectra/templates/enable_pgvector_extension.rb
|
|
287
293
|
- lib/generators/vectra/templates/vectra.rb
|