mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-07-01 17:39:39 +02:00
saving
This commit is contained in:
parent
e8c7a4f6e0
commit
ffd97375a8
160 changed files with 6704 additions and 1895 deletions
|
|
@ -16,6 +16,7 @@ import {
|
|||
type DocumentEmbeddingsRequest,
|
||||
type DocumentEmbeddingsResponse,
|
||||
} from "@trustgraph/base";
|
||||
import { makeProcessorProgram } from "@trustgraph/base";
|
||||
import { QdrantDocEmbeddingsQuery } from "./qdrant-doc.js";
|
||||
|
||||
export class DocEmbeddingsQueryService extends FlowProcessor {
|
||||
|
|
@ -26,7 +27,7 @@ export class DocEmbeddingsQueryService extends FlowProcessor {
|
|||
this.query = new QdrantDocEmbeddingsQuery();
|
||||
|
||||
this.registerSpecification(
|
||||
new ConsumerSpec<DocumentEmbeddingsRequest>(
|
||||
ConsumerSpec.fromPromise<DocumentEmbeddingsRequest>(
|
||||
"document-embeddings-request",
|
||||
this.onMessage.bind(this),
|
||||
),
|
||||
|
|
@ -44,7 +45,7 @@ export class DocEmbeddingsQueryService extends FlowProcessor {
|
|||
flowCtx: FlowContext,
|
||||
): Promise<void> {
|
||||
const requestId = properties.id;
|
||||
if (!requestId) return;
|
||||
if (requestId === undefined || requestId.length === 0) return;
|
||||
|
||||
const producer = flowCtx.flow.producer<DocumentEmbeddingsResponse>("document-embeddings-response");
|
||||
const collection = msg.collection ?? "default";
|
||||
|
|
@ -64,7 +65,7 @@ export class DocEmbeddingsQueryService extends FlowProcessor {
|
|||
allChunks.push({
|
||||
chunkId: match.chunkId,
|
||||
score: match.score,
|
||||
content: match.content,
|
||||
...(match.content !== undefined ? { content: match.content } : {}),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -80,6 +81,11 @@ export class DocEmbeddingsQueryService extends FlowProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
export const program = makeProcessorProgram({
|
||||
id: "doc-embeddings-query",
|
||||
make: (config) => new DocEmbeddingsQueryService(config),
|
||||
});
|
||||
|
||||
export async function run(): Promise<void> {
|
||||
await DocEmbeddingsQueryService.launch("doc-embeddings-query");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,10 @@ export class QdrantDocEmbeddingsQuery {
|
|||
const url = config.url ?? process.env.QDRANT_URL ?? "http://localhost:6333";
|
||||
const apiKey = config.apiKey ?? process.env.QDRANT_API_KEY;
|
||||
|
||||
this.client = new QdrantClient({ url, apiKey });
|
||||
this.client = new QdrantClient({
|
||||
url,
|
||||
...(apiKey !== undefined && apiKey.length > 0 ? { apiKey } : {}),
|
||||
});
|
||||
|
||||
console.log("[QdrantDocQuery] Query service initialized");
|
||||
}
|
||||
|
|
@ -42,7 +45,7 @@ export class QdrantDocEmbeddingsQuery {
|
|||
async query(request: DocEmbeddingsQueryRequest): Promise<ChunkMatch[]> {
|
||||
const { vector, user, collection, limit } = request;
|
||||
|
||||
if (!vector || vector.length === 0) {
|
||||
if (vector.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
|
@ -68,11 +71,11 @@ export class QdrantDocEmbeddingsQuery {
|
|||
for (const point of searchResult) {
|
||||
const payload = point.payload as Record<string, unknown> | undefined;
|
||||
const chunkId = payload?.chunk_id as string | undefined;
|
||||
if (chunkId) {
|
||||
if (chunkId !== undefined && chunkId.length > 0) {
|
||||
chunks.push({
|
||||
chunkId,
|
||||
score: point.score,
|
||||
content: (payload?.content as string) ?? undefined,
|
||||
...(typeof payload?.content === "string" ? { content: payload.content } : {}),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import {
|
|||
type GraphEmbeddingsRequest,
|
||||
type GraphEmbeddingsResponse,
|
||||
} from "@trustgraph/base";
|
||||
import { makeProcessorProgram } from "@trustgraph/base";
|
||||
import { QdrantGraphEmbeddingsQuery } from "./qdrant-graph.js";
|
||||
|
||||
export class GraphEmbeddingsQueryService extends FlowProcessor {
|
||||
|
|
@ -26,7 +27,7 @@ export class GraphEmbeddingsQueryService extends FlowProcessor {
|
|||
this.query = new QdrantGraphEmbeddingsQuery();
|
||||
|
||||
this.registerSpecification(
|
||||
new ConsumerSpec<GraphEmbeddingsRequest>(
|
||||
ConsumerSpec.fromPromise<GraphEmbeddingsRequest>(
|
||||
"graph-embeddings-request",
|
||||
this.onMessage.bind(this),
|
||||
),
|
||||
|
|
@ -44,7 +45,7 @@ export class GraphEmbeddingsQueryService extends FlowProcessor {
|
|||
flowCtx: FlowContext,
|
||||
): Promise<void> {
|
||||
const requestId = properties.id;
|
||||
if (!requestId) return;
|
||||
if (requestId === undefined || requestId.length === 0) return;
|
||||
|
||||
const producer = flowCtx.flow.producer<GraphEmbeddingsResponse>("graph-embeddings-response");
|
||||
const user = msg.user ?? "default";
|
||||
|
|
@ -79,6 +80,11 @@ export class GraphEmbeddingsQueryService extends FlowProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
export const program = makeProcessorProgram({
|
||||
id: "graph-embeddings-query",
|
||||
make: (config) => new GraphEmbeddingsQueryService(config),
|
||||
});
|
||||
|
||||
export async function run(): Promise<void> {
|
||||
await GraphEmbeddingsQueryService.launch("graph-embeddings-query");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,10 @@ export class QdrantGraphEmbeddingsQuery {
|
|||
const url = config.url ?? process.env.QDRANT_URL ?? "http://localhost:6333";
|
||||
const apiKey = config.apiKey ?? process.env.QDRANT_API_KEY;
|
||||
|
||||
this.client = new QdrantClient({ url, apiKey });
|
||||
this.client = new QdrantClient({
|
||||
url,
|
||||
...(apiKey !== undefined && apiKey.length > 0 ? { apiKey } : {}),
|
||||
});
|
||||
|
||||
console.log("[QdrantGraphQuery] Query service initialized");
|
||||
}
|
||||
|
|
@ -52,7 +55,7 @@ export class QdrantGraphEmbeddingsQuery {
|
|||
async query(request: GraphEmbeddingsQueryRequest): Promise<EntityMatch[]> {
|
||||
const { vector, user, collection, limit } = request;
|
||||
|
||||
if (!vector || vector.length === 0) {
|
||||
if (vector.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
|
@ -82,7 +85,7 @@ export class QdrantGraphEmbeddingsQuery {
|
|||
for (const point of searchResult) {
|
||||
const payload = point.payload as Record<string, unknown> | undefined;
|
||||
const entityValue = payload?.entity as string | undefined;
|
||||
if (!entityValue) continue;
|
||||
if (entityValue === undefined || entityValue.length === 0) continue;
|
||||
|
||||
// Deduplicate by entity value, keeping the highest score (results are
|
||||
// already sorted by score descending from Qdrant)
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import {
|
|||
type TriplesQueryRequest,
|
||||
type TriplesQueryResponse,
|
||||
} from "@trustgraph/base";
|
||||
import { makeProcessorProgram } from "@trustgraph/base";
|
||||
import { FalkorDBTriplesQuery } from "./falkordb.js";
|
||||
|
||||
export class TriplesQueryService extends FlowProcessor {
|
||||
|
|
@ -26,7 +27,7 @@ export class TriplesQueryService extends FlowProcessor {
|
|||
this.query = new FalkorDBTriplesQuery();
|
||||
|
||||
this.registerSpecification(
|
||||
new ConsumerSpec<TriplesQueryRequest>("triples-request", this.onMessage.bind(this)),
|
||||
ConsumerSpec.fromPromise<TriplesQueryRequest>("triples-request", this.onMessage.bind(this)),
|
||||
);
|
||||
this.registerSpecification(new ProducerSpec<TriplesQueryResponse>("triples-response"));
|
||||
|
||||
|
|
@ -39,7 +40,7 @@ export class TriplesQueryService extends FlowProcessor {
|
|||
flowCtx: FlowContext,
|
||||
): Promise<void> {
|
||||
const requestId = properties.id;
|
||||
if (!requestId) return;
|
||||
if (requestId === undefined || requestId.length === 0) return;
|
||||
|
||||
const producer = flowCtx.flow.producer<TriplesQueryResponse>("triples-response");
|
||||
|
||||
|
|
@ -62,6 +63,11 @@ export class TriplesQueryService extends FlowProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
export const program = makeProcessorProgram({
|
||||
id: "triples-query",
|
||||
make: (config) => new TriplesQueryService(config),
|
||||
});
|
||||
|
||||
export async function run(): Promise<void> {
|
||||
await TriplesQueryService.launch("triples-query");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ export interface FalkorDBQueryConfig {
|
|||
}
|
||||
|
||||
function termToValue(term: Term | undefined): string | null {
|
||||
if (!term) return null;
|
||||
if (term === undefined) return null;
|
||||
switch (term.type) {
|
||||
case "IRI": return term.iri;
|
||||
case "LITERAL": return term.value;
|
||||
|
|
@ -25,7 +25,7 @@ function termToValue(term: Term | undefined): string | null {
|
|||
}
|
||||
|
||||
function createTerm(value: string): Term {
|
||||
if (!value) {
|
||||
if (value.length === 0) {
|
||||
return { type: "LITERAL", value: "" };
|
||||
}
|
||||
if (value.startsWith("http://") || value.startsWith("https://")) {
|
||||
|
|
@ -75,25 +75,25 @@ export class FalkorDBTriplesQuery {
|
|||
const rawTriples: [string, string, string][] = [];
|
||||
|
||||
// Query both Node and Literal targets for each pattern
|
||||
if (sv && pv && ov) {
|
||||
if (sv !== null && pv !== null && ov !== null) {
|
||||
// SPO — exact match
|
||||
await this.matchPattern(rawTriples, sv, pv, ov, limit);
|
||||
} else if (sv && pv) {
|
||||
} else if (sv !== null && pv !== null) {
|
||||
// SP — known subject + predicate
|
||||
await this.matchSP(rawTriples, sv, pv, limit);
|
||||
} else if (sv && ov) {
|
||||
} else if (sv !== null && ov !== null) {
|
||||
// SO — known subject + object
|
||||
await this.matchSO(rawTriples, sv, ov, limit);
|
||||
} else if (pv && ov) {
|
||||
} else if (pv !== null && ov !== null) {
|
||||
// PO — known predicate + object
|
||||
await this.matchPO(rawTriples, pv, ov, limit);
|
||||
} else if (sv) {
|
||||
} else if (sv !== null) {
|
||||
// S only
|
||||
await this.matchS(rawTriples, sv, limit);
|
||||
} else if (pv) {
|
||||
} else if (pv !== null) {
|
||||
// P only
|
||||
await this.matchP(rawTriples, pv, limit);
|
||||
} else if (ov) {
|
||||
} else if (ov !== null) {
|
||||
// O only
|
||||
await this.matchO(rawTriples, ov, limit);
|
||||
} else {
|
||||
|
|
@ -102,7 +102,7 @@ export class FalkorDBTriplesQuery {
|
|||
}
|
||||
|
||||
return rawTriples
|
||||
.filter(([s, p, o]) => s != null && p != null && o != null)
|
||||
.filter(([s, p, o]) => s !== null && p !== null && o !== null)
|
||||
.slice(0, limit)
|
||||
.map(([s, p, o]) => ({
|
||||
s: createTerm(s),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue