sonamu 0.7.3 → 0.7.5

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.
Files changed (133) hide show
  1. package/dist/api/config.d.ts +1 -4
  2. package/dist/api/config.d.ts.map +1 -1
  3. package/dist/api/config.js +1 -1
  4. package/dist/api/sonamu.d.ts +2 -0
  5. package/dist/api/sonamu.d.ts.map +1 -1
  6. package/dist/api/sonamu.js +19 -47
  7. package/dist/bin/cli.js +6 -6
  8. package/dist/database/base-model.d.ts +1 -1
  9. package/dist/database/base-model.d.ts.map +1 -1
  10. package/dist/database/base-model.js +15 -4
  11. package/dist/database/code-generator.d.ts.map +1 -1
  12. package/dist/database/code-generator.js +3 -3
  13. package/dist/database/db.d.ts.map +1 -1
  14. package/dist/database/db.js +1 -1
  15. package/dist/database/puri-wrapper.d.ts +11 -11
  16. package/dist/database/puri-wrapper.d.ts.map +1 -1
  17. package/dist/database/puri-wrapper.js +7 -11
  18. package/dist/database/puri.d.ts +36 -17
  19. package/dist/database/puri.d.ts.map +1 -1
  20. package/dist/database/puri.js +54 -7
  21. package/dist/database/puri.types.d.ts +54 -17
  22. package/dist/database/puri.types.d.ts.map +1 -1
  23. package/dist/database/puri.types.js +2 -4
  24. package/dist/database/puri.types.test-d.js +129 -0
  25. package/dist/database/upsert-builder.d.ts +16 -10
  26. package/dist/database/upsert-builder.d.ts.map +1 -1
  27. package/dist/database/upsert-builder.js +10 -19
  28. package/dist/entity/entity-manager.d.ts +113 -22
  29. package/dist/entity/entity-manager.d.ts.map +1 -1
  30. package/dist/entity/entity-manager.js +1 -1
  31. package/dist/entity/entity.d.ts +34 -0
  32. package/dist/entity/entity.d.ts.map +1 -1
  33. package/dist/entity/entity.js +110 -37
  34. package/dist/index.d.ts +5 -0
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +8 -2
  37. package/dist/migration/code-generation.d.ts.map +1 -1
  38. package/dist/migration/code-generation.js +341 -149
  39. package/dist/migration/migration-set.d.ts.map +1 -1
  40. package/dist/migration/migration-set.js +21 -5
  41. package/dist/migration/migrator.d.ts.map +1 -1
  42. package/dist/migration/migrator.js +7 -1
  43. package/dist/migration/postgresql-schema-reader.d.ts +11 -1
  44. package/dist/migration/postgresql-schema-reader.d.ts.map +1 -1
  45. package/dist/migration/postgresql-schema-reader.js +111 -10
  46. package/dist/syncer/syncer.d.ts.map +1 -1
  47. package/dist/syncer/syncer.js +5 -4
  48. package/dist/template/implementations/generated.template.d.ts.map +1 -1
  49. package/dist/template/implementations/generated.template.js +12 -2
  50. package/dist/template/implementations/generated_sso.template.d.ts +3 -3
  51. package/dist/template/implementations/generated_sso.template.d.ts.map +1 -1
  52. package/dist/template/implementations/generated_sso.template.js +50 -2
  53. package/dist/template/implementations/model.template.js +6 -6
  54. package/dist/template/implementations/model_test.template.js +4 -4
  55. package/dist/template/implementations/view_enums_dropdown.template.js +2 -2
  56. package/dist/template/implementations/view_enums_select.template.js +2 -2
  57. package/dist/template/implementations/view_form.template.d.ts.map +1 -1
  58. package/dist/template/implementations/view_form.template.js +12 -9
  59. package/dist/template/implementations/view_id_async_select.template.js +4 -4
  60. package/dist/template/implementations/view_list.template.d.ts.map +1 -1
  61. package/dist/template/implementations/view_list.template.js +12 -9
  62. package/dist/template/implementations/view_search_input.template.js +2 -2
  63. package/dist/template/template.js +2 -2
  64. package/dist/template/zod-converter.d.ts.map +1 -1
  65. package/dist/template/zod-converter.js +17 -2
  66. package/dist/testing/fixture-manager.d.ts +2 -1
  67. package/dist/testing/fixture-manager.d.ts.map +1 -1
  68. package/dist/testing/fixture-manager.js +29 -29
  69. package/dist/types/types.d.ts +593 -68
  70. package/dist/types/types.d.ts.map +1 -1
  71. package/dist/types/types.js +113 -9
  72. package/dist/vector/chunking.d.ts +25 -0
  73. package/dist/vector/chunking.d.ts.map +1 -0
  74. package/dist/vector/chunking.js +97 -0
  75. package/dist/vector/config.d.ts +12 -0
  76. package/dist/vector/config.d.ts.map +1 -0
  77. package/dist/vector/config.js +83 -0
  78. package/dist/vector/embedding.d.ts +42 -0
  79. package/dist/vector/embedding.d.ts.map +1 -0
  80. package/dist/vector/embedding.js +147 -0
  81. package/dist/vector/types.d.ts +105 -0
  82. package/dist/vector/types.d.ts.map +1 -0
  83. package/dist/vector/types.js +5 -0
  84. package/dist/vector/vector-search.d.ts +47 -0
  85. package/dist/vector/vector-search.d.ts.map +1 -0
  86. package/dist/vector/vector-search.js +176 -0
  87. package/package.json +11 -11
  88. package/src/api/config.ts +0 -4
  89. package/src/api/sonamu.ts +21 -36
  90. package/src/bin/cli.ts +5 -5
  91. package/src/database/base-model.ts +20 -11
  92. package/src/database/code-generator.ts +6 -2
  93. package/src/database/db.ts +1 -0
  94. package/src/database/puri-wrapper.ts +22 -16
  95. package/src/database/puri.ts +150 -27
  96. package/src/database/puri.types.test-d.ts +457 -0
  97. package/src/database/puri.types.ts +231 -33
  98. package/src/database/upsert-builder.ts +43 -34
  99. package/src/entity/entity-manager.ts +2 -2
  100. package/src/entity/entity.ts +134 -44
  101. package/src/index.ts +6 -0
  102. package/src/migration/code-generation.ts +377 -174
  103. package/src/migration/migration-set.ts +22 -3
  104. package/src/migration/migrator.ts +6 -0
  105. package/src/migration/postgresql-schema-reader.ts +121 -21
  106. package/src/syncer/syncer.ts +4 -3
  107. package/src/template/implementations/generated.template.ts +51 -9
  108. package/src/template/implementations/generated_sso.template.ts +71 -2
  109. package/src/template/implementations/model.template.ts +5 -5
  110. package/src/template/implementations/model_test.template.ts +3 -3
  111. package/src/template/implementations/view_enums_dropdown.template.ts +1 -1
  112. package/src/template/implementations/view_enums_select.template.ts +1 -1
  113. package/src/template/implementations/view_form.template.ts +11 -8
  114. package/src/template/implementations/view_id_async_select.template.ts +3 -3
  115. package/src/template/implementations/view_list.template.ts +11 -8
  116. package/src/template/implementations/view_search_input.template.ts +1 -1
  117. package/src/template/template.ts +1 -1
  118. package/src/template/zod-converter.ts +20 -0
  119. package/src/testing/fixture-manager.ts +31 -30
  120. package/src/types/types.ts +226 -48
  121. package/src/vector/chunking.ts +115 -0
  122. package/src/vector/config.ts +68 -0
  123. package/src/vector/embedding.ts +193 -0
  124. package/src/vector/types.ts +122 -0
  125. package/src/vector/vector-search.ts +261 -0
  126. package/dist/template/implementations/view_enums_buttonset.template.d.ts +0 -17
  127. package/dist/template/implementations/view_enums_buttonset.template.d.ts.map +0 -1
  128. package/dist/template/implementations/view_enums_buttonset.template.js +0 -31
  129. package/dist/template/implementations/view_list_columns.template.d.ts +0 -17
  130. package/dist/template/implementations/view_list_columns.template.d.ts.map +0 -1
  131. package/dist/template/implementations/view_list_columns.template.js +0 -49
  132. package/src/template/implementations/view_enums_buttonset.template.ts +0 -34
  133. package/src/template/implementations/view_list_columns.template.ts +0 -53
@@ -0,0 +1,115 @@
1
+ import { DEFAULT_VECTOR_CONFIG } from "./config";
2
+ import type { Chunk, ChunkingConfig } from "./types";
3
+
4
+ /**
5
+ * 텍스트 청킹
6
+ * - 현재 가이드에서는 400토큰 이하만 저장하므로 기본적으로 사용하지 않음
7
+ * - 추후 긴 문서 처리 시 사용
8
+ */
9
+ export class Chunking {
10
+ private config: ChunkingConfig;
11
+
12
+ constructor(config: Partial<ChunkingConfig> = {}) {
13
+ this.config = { ...DEFAULT_VECTOR_CONFIG.chunking, ...config };
14
+ }
15
+
16
+ /**
17
+ * 텍스트를 청크로 분할
18
+ */
19
+ chunk(text: string): Chunk[] {
20
+ if (text.length < this.config.skipThreshold) {
21
+ return [
22
+ {
23
+ index: 0,
24
+ text: text.trim(),
25
+ startOffset: 0,
26
+ endOffset: text.length,
27
+ },
28
+ ];
29
+ }
30
+
31
+ const chunks: Chunk[] = [];
32
+ let currentPosition = 0;
33
+
34
+ while (currentPosition < text.length) {
35
+ const remainingText = text.slice(currentPosition);
36
+ const { chunk, length } = this.extractChunk(remainingText);
37
+
38
+ if (chunk.trim().length >= this.config.minChunkSize) {
39
+ chunks.push({
40
+ index: chunks.length,
41
+ text: chunk.trim(),
42
+ startOffset: currentPosition,
43
+ endOffset: currentPosition + length,
44
+ });
45
+ }
46
+
47
+ const advance = Math.max(length - this.config.chunkOverlap, this.config.minChunkSize);
48
+ currentPosition += advance;
49
+ }
50
+
51
+ return chunks;
52
+ }
53
+
54
+ /**
55
+ * 청킹이 필요한지 확인
56
+ */
57
+ needsChunking(text: string): boolean {
58
+ return text.length > this.config.chunkSize;
59
+ }
60
+
61
+ /**
62
+ * 예상 청크 수 계산
63
+ */
64
+ estimateChunkCount(text: string): number {
65
+ if (text.length <= this.config.chunkSize) {
66
+ return 1;
67
+ }
68
+ const effectiveChunkSize = this.config.chunkSize - this.config.chunkOverlap;
69
+ return Math.ceil(text.length / effectiveChunkSize);
70
+ }
71
+
72
+ private extractChunk(text: string): { chunk: string; length: number } {
73
+ if (text.length <= this.config.chunkSize) {
74
+ return { chunk: text, length: text.length };
75
+ }
76
+
77
+ for (const separator of this.config.separators) {
78
+ const result = this.splitBySeparator(text, separator);
79
+ if (result) return result;
80
+ }
81
+
82
+ return {
83
+ chunk: text.slice(0, this.config.chunkSize),
84
+ length: this.config.chunkSize,
85
+ };
86
+ }
87
+
88
+ private splitBySeparator(
89
+ text: string,
90
+ separator: string,
91
+ ): { chunk: string; length: number } | null {
92
+ const searchRange = text.slice(0, this.config.chunkSize + 100);
93
+
94
+ let lastIndex = -1;
95
+ let index = 0;
96
+
97
+ while (true) {
98
+ index = searchRange.indexOf(separator, index);
99
+ if (index === -1) break;
100
+ if (index <= this.config.chunkSize) {
101
+ lastIndex = index + separator.length;
102
+ }
103
+ index++;
104
+ }
105
+
106
+ if (lastIndex > this.config.minChunkSize) {
107
+ return {
108
+ chunk: text.slice(0, lastIndex),
109
+ length: lastIndex,
110
+ };
111
+ }
112
+
113
+ return null;
114
+ }
115
+ }
@@ -0,0 +1,68 @@
1
+ import type { VectorConfig } from "./types";
2
+
3
+ /**
4
+ * 벡터 검색 기본 설정
5
+ * 사용자는 이 설정을 override하여 커스터마이즈할 수 있음
6
+ */
7
+ export const DEFAULT_VECTOR_CONFIG: VectorConfig = {
8
+ // Voyage AI 설정
9
+ // apiKey는 Sonamu.secrets에서 로드되므로 여기서는 빈 문자열
10
+ voyage: {
11
+ apiKey: "",
12
+ baseUrl: "https://api.voyageai.com/v1/embeddings",
13
+ model: "voyage-3",
14
+ dimensions: 1024,
15
+ maxTokens: 32000,
16
+ batchSize: 100,
17
+ },
18
+
19
+ // OpenAI 설정
20
+ // apiKey는 Sonamu.secrets에서 로드되므로 여기서는 빈 문자열
21
+ openai: {
22
+ apiKey: "",
23
+ baseUrl: "https://api.openai.com/v1/embeddings",
24
+ model: "text-embedding-3-small",
25
+ dimensions: 1536,
26
+ maxTokens: 8191,
27
+ batchSize: 100,
28
+ },
29
+
30
+ // 청킹 설정 (필요시 사용)
31
+ chunking: {
32
+ chunkSize: 500,
33
+ chunkOverlap: 50,
34
+ minChunkSize: 50,
35
+ skipThreshold: 200,
36
+ separators: ["\n\n", "\n", "。", ". ", "! ", "? ", ", ", " "],
37
+ },
38
+
39
+ // 검색 설정
40
+ search: {
41
+ defaultLimit: 10,
42
+ similarityThreshold: 0.5,
43
+ vectorWeight: 0.7,
44
+ ftsWeight: 0.3,
45
+ },
46
+
47
+ // pgvector 설정
48
+ pgvector: {
49
+ iterativeScan: true,
50
+ efSearch: 100,
51
+ },
52
+ };
53
+
54
+ /**
55
+ * 설정 생성 헬퍼 함수
56
+ * 부분 설정만 제공하면 나머지는 기본값 사용
57
+ */
58
+ export function createVectorConfig(
59
+ overrides: Partial<VectorConfig> = {}
60
+ ): VectorConfig {
61
+ return {
62
+ voyage: { ...DEFAULT_VECTOR_CONFIG.voyage, ...overrides.voyage },
63
+ openai: { ...DEFAULT_VECTOR_CONFIG.openai, ...overrides.openai },
64
+ chunking: { ...DEFAULT_VECTOR_CONFIG.chunking, ...overrides.chunking },
65
+ search: { ...DEFAULT_VECTOR_CONFIG.search, ...overrides.search },
66
+ pgvector: { ...DEFAULT_VECTOR_CONFIG.pgvector, ...overrides.pgvector },
67
+ };
68
+ }
@@ -0,0 +1,193 @@
1
+ import { Sonamu } from "../api/sonamu";
2
+ import { DEFAULT_VECTOR_CONFIG } from "./config";
3
+ import type {
4
+ EmbeddingProvider,
5
+ EmbeddingResult,
6
+ ProgressCallback,
7
+ VectorConfig,
8
+ VectorInputType,
9
+ } from "./types";
10
+
11
+ /**
12
+ * 임베딩 클라이언트
13
+ * Voyage AI와 OpenAI 임베딩을 통합 지원
14
+ */
15
+ export class Embedding {
16
+ private config: VectorConfig;
17
+
18
+ constructor(config: Partial<VectorConfig> = {}) {
19
+ this.config = {
20
+ voyage: { ...DEFAULT_VECTOR_CONFIG.voyage, ...config.voyage },
21
+ openai: { ...DEFAULT_VECTOR_CONFIG.openai, ...config.openai },
22
+ chunking: { ...DEFAULT_VECTOR_CONFIG.chunking, ...config.chunking },
23
+ search: { ...DEFAULT_VECTOR_CONFIG.search, ...config.search },
24
+ pgvector: { ...DEFAULT_VECTOR_CONFIG.pgvector, ...config.pgvector },
25
+ };
26
+ }
27
+
28
+ /**
29
+ * 텍스트 임베딩 생성
30
+ * @param texts - 임베딩할 텍스트 배열
31
+ * @param provider - 'voyage' | 'openai'
32
+ * @param inputType - 'document' | 'query' (Voyage AI만 해당)
33
+ */
34
+ async embed(
35
+ texts: string[],
36
+ provider: EmbeddingProvider,
37
+ inputType: VectorInputType = "document"
38
+ ): Promise<EmbeddingResult[]> {
39
+ if (provider === "voyage") {
40
+ return this.embedVoyage(texts, inputType);
41
+ } else {
42
+ return this.embedOpenAI(texts);
43
+ }
44
+ }
45
+
46
+ /**
47
+ * 단일 텍스트 임베딩 (편의 메서드)
48
+ */
49
+ async embedOne(
50
+ text: string,
51
+ provider: EmbeddingProvider,
52
+ inputType: VectorInputType = "document"
53
+ ): Promise<EmbeddingResult> {
54
+ const results = await this.embed([text], provider, inputType);
55
+ return results[0];
56
+ }
57
+
58
+ /**
59
+ * Voyage AI 임베딩
60
+ */
61
+ private async embedVoyage(
62
+ texts: string[],
63
+ inputType: VectorInputType
64
+ ): Promise<EmbeddingResult[]> {
65
+ const voyageConfig = this.config.voyage;
66
+
67
+ // config에서 설정된 apiKey 우선, 없으면 Sonamu.secrets에서 로드
68
+ const apiKey = voyageConfig.apiKey || Sonamu.secrets?.voyage_api_key;
69
+ if (!apiKey) {
70
+ throw new Error(
71
+ "VOYAGE_API_KEY가 설정되지 않았습니다. 환경변수를 확인하세요."
72
+ );
73
+ }
74
+
75
+ const response = await fetch(voyageConfig.baseUrl, {
76
+ method: "POST",
77
+ headers: {
78
+ "Content-Type": "application/json",
79
+ Authorization: `Bearer ${apiKey}`,
80
+ },
81
+ body: JSON.stringify({
82
+ input: texts,
83
+ model: voyageConfig.model,
84
+ input_type: inputType,
85
+ }),
86
+ });
87
+
88
+ if (!response.ok) {
89
+ const error = await response.text();
90
+ throw new Error(`Voyage API error: ${response.status} - ${error}`);
91
+ }
92
+
93
+ const data = await response.json();
94
+
95
+ return data.data.map((item: { embedding: number[] }) => ({
96
+ embedding: item.embedding,
97
+ model: voyageConfig.model,
98
+ tokenCount: data.usage?.total_tokens || 0,
99
+ }));
100
+ }
101
+
102
+ /**
103
+ * OpenAI 임베딩
104
+ */
105
+ private async embedOpenAI(texts: string[]): Promise<EmbeddingResult[]> {
106
+ const openaiConfig = this.config.openai;
107
+
108
+ // config에서 설정된 apiKey 우선, 없으면 Sonamu.secrets에서 로드
109
+ const apiKey = openaiConfig.apiKey || Sonamu.secrets?.openai_api_key;
110
+ if (!apiKey) {
111
+ throw new Error(
112
+ "OPENAI_API_KEY가 설정되지 않았습니다. 환경변수를 확인하세요."
113
+ );
114
+ }
115
+
116
+ const response = await fetch(openaiConfig.baseUrl, {
117
+ method: "POST",
118
+ headers: {
119
+ "Content-Type": "application/json",
120
+ Authorization: `Bearer ${apiKey}`,
121
+ },
122
+ body: JSON.stringify({
123
+ input: texts,
124
+ model: openaiConfig.model,
125
+ }),
126
+ });
127
+
128
+ if (!response.ok) {
129
+ const error = await response.text();
130
+ throw new Error(`OpenAI API error: ${response.status} - ${error}`);
131
+ }
132
+
133
+ const data = await response.json();
134
+
135
+ return data.data.map((item: { embedding: number[] }) => ({
136
+ embedding: item.embedding,
137
+ model: openaiConfig.model,
138
+ tokenCount: data.usage?.total_tokens || 0,
139
+ }));
140
+ }
141
+
142
+ /**
143
+ * 배치 임베딩 (대량 처리)
144
+ */
145
+ async embedBatch(
146
+ texts: string[],
147
+ provider: EmbeddingProvider,
148
+ inputType: VectorInputType = "document",
149
+ onProgress?: ProgressCallback
150
+ ): Promise<EmbeddingResult[]> {
151
+ const batchSize =
152
+ provider === "voyage"
153
+ ? this.config.voyage.batchSize
154
+ : this.config.openai.batchSize;
155
+
156
+ const results: EmbeddingResult[] = [];
157
+
158
+ for (let i = 0; i < texts.length; i += batchSize) {
159
+ const batch = texts.slice(i, i + batchSize);
160
+ const batchResults = await this.embed(batch, provider, inputType);
161
+ results.push(...batchResults);
162
+
163
+ onProgress?.(Math.min(i + batchSize, texts.length), texts.length);
164
+
165
+ // Rate limiting (100ms between batches)
166
+ if (i + batchSize < texts.length) {
167
+ await this.delay(100);
168
+ }
169
+ }
170
+
171
+ return results;
172
+ }
173
+
174
+ /**
175
+ * 벡터를 PostgreSQL vector 타입 문자열로 변환
176
+ */
177
+ static toVectorString(embedding: number[]): string {
178
+ return `[${embedding.join(",")}]`;
179
+ }
180
+
181
+ /**
182
+ * 임베딩 provider의 차원 수 반환
183
+ */
184
+ getDimensions(provider: EmbeddingProvider): number {
185
+ return provider === "voyage"
186
+ ? this.config.voyage.dimensions
187
+ : this.config.openai.dimensions;
188
+ }
189
+
190
+ private delay(ms: number): Promise<void> {
191
+ return new Promise((resolve) => setTimeout(resolve, ms));
192
+ }
193
+ }
@@ -0,0 +1,122 @@
1
+ /**
2
+ * pgvector 통합을 위한 타입 정의
3
+ */
4
+
5
+ /** 임베딩 제공자 */
6
+ export type EmbeddingProvider = "voyage" | "openai";
7
+
8
+ /** 입력 타입 (Voyage AI 전용 - 비대칭 임베딩) */
9
+ export type VectorInputType = "document" | "query";
10
+
11
+ /** 임베딩 결과 */
12
+ export interface EmbeddingResult {
13
+ embedding: number[];
14
+ model: string;
15
+ tokenCount: number;
16
+ }
17
+
18
+ /** 청크 정보 */
19
+ export interface Chunk {
20
+ index: number;
21
+ text: string;
22
+ startOffset: number;
23
+ endOffset: number;
24
+ }
25
+
26
+ /** 벡터 검색 결과 */
27
+ export interface VectorSearchResult<T = Record<string, unknown>> {
28
+ id: number | string;
29
+ similarity: number;
30
+ data: T;
31
+ }
32
+
33
+ /** 하이브리드 검색 결과 (Vector + FTS) */
34
+ export interface HybridSearchResult<T = Record<string, unknown>>
35
+ extends VectorSearchResult<T> {
36
+ vectorScore?: number;
37
+ ftsScore?: number;
38
+ }
39
+
40
+ /** 벤치마크 결과 */
41
+ export interface BenchmarkResult {
42
+ provider: EmbeddingProvider;
43
+ embedTime: number;
44
+ searchTime: number;
45
+ results: VectorSearchResult[];
46
+ }
47
+
48
+ /** Voyage AI 설정 */
49
+ export interface VoyageConfig {
50
+ apiKey: string;
51
+ baseUrl: string;
52
+ model: string;
53
+ dimensions: number;
54
+ maxTokens: number;
55
+ batchSize: number;
56
+ }
57
+
58
+ /** OpenAI 설정 */
59
+ export interface OpenAIConfig {
60
+ apiKey: string;
61
+ baseUrl: string;
62
+ model: string;
63
+ dimensions: number;
64
+ maxTokens: number;
65
+ batchSize: number;
66
+ }
67
+
68
+ /** 청킹 설정 */
69
+ export interface ChunkingConfig {
70
+ chunkSize: number;
71
+ chunkOverlap: number;
72
+ minChunkSize: number;
73
+ skipThreshold: number;
74
+ separators: string[];
75
+ }
76
+
77
+ /** 검색 설정 */
78
+ export interface SearchConfig {
79
+ defaultLimit: number;
80
+ similarityThreshold: number;
81
+ vectorWeight: number;
82
+ ftsWeight: number;
83
+ }
84
+
85
+ /** pgvector 설정 */
86
+ export interface PgvectorConfig {
87
+ iterativeScan: boolean;
88
+ efSearch: number;
89
+ }
90
+
91
+ /** 전체 벡터 설정 */
92
+ export interface VectorConfig {
93
+ voyage: VoyageConfig;
94
+ openai: OpenAIConfig;
95
+ chunking: ChunkingConfig;
96
+ search: SearchConfig;
97
+ pgvector: PgvectorConfig;
98
+ }
99
+
100
+ /** 벡터 검색 옵션 */
101
+ export interface VectorSearchOptions {
102
+ embeddingColumn?: string;
103
+ limit?: number;
104
+ threshold?: number;
105
+ where?: string;
106
+ }
107
+
108
+ /** 하이브리드 검색 옵션 */
109
+ export interface HybridSearchOptions extends VectorSearchOptions {
110
+ vectorWeight?: number;
111
+ ftsWeight?: number;
112
+ ftsColumn?: string;
113
+ }
114
+
115
+ /** 임베딩 저장 항목 */
116
+ export interface EmbeddingItem {
117
+ id: number;
118
+ text: string;
119
+ }
120
+
121
+ /** 진행률 콜백 */
122
+ export type ProgressCallback = (processed: number, total: number) => void;