Squashed 'vendor/ruvector/' content from commit b64c2172

git-subtree-dir: vendor/ruvector
git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
This commit is contained in:
ruv
2026-02-28 14:39:40 -05:00
commit d803bfe2b1
7854 changed files with 3522914 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
# OpenRouter API Configuration
OPENROUTER_API_KEY=your_openrouter_api_key_here
# Model Configuration (optional)
# Default: moonshot/kimi-k2-instruct
# OPENROUTER_MODEL=moonshot/kimi-k2-instruct
# Rate Limiting (optional)
# OPENROUTER_RATE_LIMIT_REQUESTS=10
# OPENROUTER_RATE_LIMIT_INTERVAL=1000
# Embedding Configuration (optional)
# EMBEDDING_DIMENSIONS=1536
# EMBEDDING_BATCH_SIZE=100

View File

@@ -0,0 +1,42 @@
# Dependencies
node_modules/
.pnp
.pnp.js
# Build outputs
dist/
build/
*.tsbuildinfo
# Environment variables
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# Testing
coverage/
.nyc_output/
# Logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# OS
.DS_Store
Thumbs.db
# Temporary files
*.tmp
.cache/

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 rUv
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,270 @@
# @ruvector/graph-data-generator
AI-powered synthetic graph data generation with OpenRouter/Kimi K2 integration for Neo4j knowledge graphs, social networks, and temporal events.
## Features
- **Knowledge Graph Generation**: Create realistic knowledge graphs with entities and relationships
- **Social Network Generation**: Generate social networks with various topology patterns
- **Temporal Events**: Create time-series graph data with events and entities
- **Entity Relationships**: Generate domain-specific entity-relationship graphs
- **Cypher Generation**: Automatic Neo4j Cypher statement generation
- **Vector Embeddings**: Enrich graphs with semantic embeddings
- **OpenRouter Integration**: Powered by Kimi K2 and other OpenRouter models
- **Type-Safe**: Full TypeScript support with Zod validation
## Installation
```bash
npm install @ruvector/graph-data-generator
```
## Quick Start
```typescript
import { createGraphDataGenerator } from '@ruvector/graph-data-generator';
// Initialize with OpenRouter API key
const generator = createGraphDataGenerator({
apiKey: process.env.OPENROUTER_API_KEY,
model: 'moonshot/kimi-k2-instruct'
});
// Generate a knowledge graph
const result = await generator.generateKnowledgeGraph({
domain: 'technology',
entities: 100,
relationships: 300,
includeEmbeddings: true
});
// Get Cypher statements for Neo4j
const cypher = generator.generateCypher(result.data, {
useConstraints: true,
useIndexes: true
});
console.log(cypher);
```
## Usage Examples
### Knowledge Graph
```typescript
const knowledgeGraph = await generator.generateKnowledgeGraph({
domain: 'artificial intelligence',
entities: 200,
relationships: 500,
entityTypes: ['Concept', 'Technology', 'Person', 'Organization'],
relationshipTypes: ['RELATES_TO', 'DEVELOPED_BY', 'PART_OF'],
includeEmbeddings: true,
embeddingDimension: 1536
});
```
### Social Network
```typescript
const socialNetwork = await generator.generateSocialNetwork({
users: 1000,
avgConnections: 50,
networkType: 'small-world', // or 'scale-free', 'clustered', 'random'
communities: 5,
includeMetadata: true,
includeEmbeddings: true
});
```
### Temporal Events
```typescript
const temporalEvents = await generator.generateTemporalEvents({
startDate: '2024-01-01',
endDate: '2024-12-31',
eventTypes: ['login', 'purchase', 'logout', 'error'],
eventsPerDay: 100,
entities: 50,
includeEmbeddings: true
});
```
### Entity Relationships
```typescript
const erGraph = await generator.generateEntityRelationships({
domain: 'e-commerce',
entityCount: 500,
relationshipDensity: 0.3,
entitySchema: {
Product: {
properties: { name: 'string', price: 'number' }
},
Category: {
properties: { name: 'string' }
}
},
relationshipTypes: ['BELONGS_TO', 'SIMILAR_TO', 'PURCHASED_WITH'],
includeEmbeddings: true
});
```
## Cypher Generation
Generate Neo4j Cypher statements from graph data:
```typescript
// Basic Cypher generation
const cypher = generator.generateCypher(graphData);
// With constraints and indexes
const cypher = generator.generateCypher(graphData, {
useConstraints: true,
useIndexes: true,
useMerge: true // Use MERGE instead of CREATE
});
// Save to file
import fs from 'fs';
fs.writeFileSync('graph-setup.cypher', cypher);
```
## Vector Embeddings
Enrich graph data with semantic embeddings:
```typescript
// Add embeddings to existing graph data
const enrichedData = await generator.enrichWithEmbeddings(graphData, {
provider: 'openrouter',
dimensions: 1536,
batchSize: 100
});
// Find similar nodes
const embeddingEnrichment = generator.getEmbeddingEnrichment();
const similar = embeddingEnrichment.findSimilarNodes(
targetNode,
allNodes,
10, // top 10
'cosine' // similarity metric
);
```
## Configuration
### Environment Variables
```bash
OPENROUTER_API_KEY=your_api_key
OPENROUTER_MODEL=moonshot/kimi-k2-instruct
OPENROUTER_RATE_LIMIT_REQUESTS=10
OPENROUTER_RATE_LIMIT_INTERVAL=1000
EMBEDDING_DIMENSIONS=1536
```
### Programmatic Configuration
```typescript
const generator = createGraphDataGenerator({
apiKey: 'your_api_key',
model: 'moonshot/kimi-k2-instruct',
baseURL: 'https://openrouter.ai/api/v1',
timeout: 60000,
maxRetries: 3,
rateLimit: {
requests: 10,
interval: 1000
}
});
```
## Integration with agentic-synth
This package extends `@ruvector/agentic-synth` with graph-specific data generation:
```typescript
import { createSynth } from '@ruvector/agentic-synth';
import { createGraphDataGenerator } from '@ruvector/graph-data-generator';
// Use both together
const synth = createSynth({ provider: 'gemini' });
const graphGen = createGraphDataGenerator({
apiKey: process.env.OPENROUTER_API_KEY
});
// Generate structured data with synth
const structuredData = await synth.generateStructured({
schema: { /* ... */ }
});
// Generate graph data
const graphData = await graphGen.generateKnowledgeGraph({
domain: 'technology',
entities: 100,
relationships: 300
});
```
## API Reference
### GraphDataGenerator
Main class for graph data generation.
#### Methods
- `generateKnowledgeGraph(options)` - Generate knowledge graph
- `generateSocialNetwork(options)` - Generate social network
- `generateTemporalEvents(options)` - Generate temporal events
- `generateEntityRelationships(options)` - Generate entity-relationship graph
- `enrichWithEmbeddings(data, config)` - Add embeddings to graph data
- `generateCypher(data, options)` - Generate Cypher statements
- `getClient()` - Get OpenRouter client
- `getCypherGenerator()` - Get Cypher generator
- `getEmbeddingEnrichment()` - Get embedding enrichment
### OpenRouterClient
Client for OpenRouter API.
#### Methods
- `createCompletion(messages, options)` - Create chat completion
- `createStreamingCompletion(messages, options)` - Stream completion
- `generateStructured(systemPrompt, userPrompt, options)` - Generate structured data
### CypherGenerator
Generate Neo4j Cypher statements.
#### Methods
- `generate(data)` - Generate CREATE statements
- `generateMergeStatements(data)` - Generate MERGE statements
- `generateIndexStatements(data)` - Generate index creation
- `generateConstraintStatements(data)` - Generate constraints
- `generateSetupScript(data, options)` - Complete setup script
- `generateBatchInsert(data, batchSize)` - Batch insert statements
### EmbeddingEnrichment
Add vector embeddings to graph data.
#### Methods
- `enrichGraphData(data)` - Enrich entire graph
- `calculateSimilarity(emb1, emb2, metric)` - Calculate similarity
- `findSimilarNodes(node, allNodes, topK, metric)` - Find similar nodes
## License
MIT
## Author
rUv - https://github.com/ruvnet
## Repository
https://github.com/ruvnet/ruvector/tree/main/packages/graph-data-generator

View File

@@ -0,0 +1,177 @@
#!/usr/bin/env node
/**
* CLI for @ruvector/graph-data-generator
*/
import { Command } from 'commander';
import { createGraphDataGenerator } from '../dist/index.js';
import fs from 'fs';
import path from 'path';
const program = new Command();
program
.name('graph-synth')
.description('AI-powered synthetic graph data generator with OpenRouter/Kimi K2')
.version('0.1.0');
program
.command('knowledge-graph')
.description('Generate a knowledge graph')
.requiredOption('-d, --domain <domain>', 'Domain for the knowledge graph')
.requiredOption('-e, --entities <number>', 'Number of entities to generate')
.requiredOption('-r, --relationships <number>', 'Number of relationships to generate')
.option('--embeddings', 'Include vector embeddings')
.option('-o, --output <file>', 'Output file (default: stdout)')
.action(async (options) => {
try {
const generator = createGraphDataGenerator();
console.error('Generating knowledge graph...');
const result = await generator.generateKnowledgeGraph({
domain: options.domain,
entities: parseInt(options.entities),
relationships: parseInt(options.relationships),
includeEmbeddings: options.embeddings || false
});
const cypher = generator.generateCypher(result.data, {
useConstraints: true,
useIndexes: true
});
if (options.output) {
fs.writeFileSync(options.output, cypher);
console.error(`✓ Written to ${options.output}`);
} else {
console.log(cypher);
}
console.error(`✓ Generated ${result.data.nodes.length} nodes and ${result.data.edges.length} edges`);
} catch (error) {
console.error('Error:', error.message);
process.exit(1);
}
});
program
.command('social-network')
.description('Generate a social network')
.requiredOption('-u, --users <number>', 'Number of users to generate')
.requiredOption('-c, --connections <number>', 'Average connections per user')
.option('-t, --type <type>', 'Network type (random|small-world|scale-free|clustered)', 'random')
.option('--embeddings', 'Include vector embeddings')
.option('-o, --output <file>', 'Output file (default: stdout)')
.action(async (options) => {
try {
const generator = createGraphDataGenerator();
console.error('Generating social network...');
const result = await generator.generateSocialNetwork({
users: parseInt(options.users),
avgConnections: parseInt(options.connections),
networkType: options.type,
includeEmbeddings: options.embeddings || false
});
const cypher = generator.generateCypher(result.data, {
useConstraints: true,
useIndexes: true
});
if (options.output) {
fs.writeFileSync(options.output, cypher);
console.error(`✓ Written to ${options.output}`);
} else {
console.log(cypher);
}
console.error(`✓ Generated ${result.data.nodes.length} users and ${result.data.edges.length} connections`);
} catch (error) {
console.error('Error:', error.message);
process.exit(1);
}
});
program
.command('temporal-events')
.description('Generate temporal event graph')
.requiredOption('-s, --start <date>', 'Start date (ISO format)')
.requiredOption('-e, --end <date>', 'End date (ISO format)')
.requiredOption('-t, --types <types>', 'Event types (comma-separated)')
.option('-d, --events-per-day <number>', 'Events per day', '10')
.option('--embeddings', 'Include vector embeddings')
.option('-o, --output <file>', 'Output file (default: stdout)')
.action(async (options) => {
try {
const generator = createGraphDataGenerator();
console.error('Generating temporal events...');
const result = await generator.generateTemporalEvents({
startDate: options.start,
endDate: options.end,
eventTypes: options.types.split(',').map(t => t.trim()),
eventsPerDay: parseInt(options.eventsPerDay),
includeEmbeddings: options.embeddings || false
});
const cypher = generator.generateCypher(result.data, {
useConstraints: true,
useIndexes: true
});
if (options.output) {
fs.writeFileSync(options.output, cypher);
console.error(`✓ Written to ${options.output}`);
} else {
console.log(cypher);
}
console.error(`✓ Generated ${result.data.nodes.length} nodes and ${result.data.edges.length} edges`);
} catch (error) {
console.error('Error:', error.message);
process.exit(1);
}
});
program
.command('entity-relationships')
.description('Generate entity-relationship graph')
.requiredOption('-d, --domain <domain>', 'Domain for the entities')
.requiredOption('-e, --entities <number>', 'Number of entities to generate')
.requiredOption('--density <number>', 'Relationship density (0-1)')
.option('--embeddings', 'Include vector embeddings')
.option('-o, --output <file>', 'Output file (default: stdout)')
.action(async (options) => {
try {
const generator = createGraphDataGenerator();
console.error('Generating entity-relationship graph...');
const result = await generator.generateEntityRelationships({
domain: options.domain,
entityCount: parseInt(options.entities),
relationshipDensity: parseFloat(options.density),
includeEmbeddings: options.embeddings || false
});
const cypher = generator.generateCypher(result.data, {
useConstraints: true,
useIndexes: true
});
if (options.output) {
fs.writeFileSync(options.output, cypher);
console.error(`✓ Written to ${options.output}`);
} else {
console.log(cypher);
}
console.error(`✓ Generated ${result.data.nodes.length} nodes and ${result.data.edges.length} edges`);
} catch (error) {
console.error('Error:', error.message);
process.exit(1);
}
});
program.parse();

View File

@@ -0,0 +1,5 @@
/**
* Basic usage examples for @ruvector/graph-data-generator
*/
export {};
//# sourceMappingURL=basic-usage.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"basic-usage.d.ts","sourceRoot":"","sources":["basic-usage.ts"],"names":[],"mappings":"AAAA;;GAEG"}

View File

@@ -0,0 +1,79 @@
"use strict";
/**
* Basic usage examples for @ruvector/graph-data-generator
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const index_js_1 = require("../src/index.js");
const fs_1 = __importDefault(require("fs"));
async function main() {
// Initialize generator with OpenRouter API key
const generator = (0, index_js_1.createGraphDataGenerator)({
apiKey: process.env.OPENROUTER_API_KEY,
model: 'moonshot/kimi-k2-instruct'
});
console.log('=== Knowledge Graph Generation ===');
const knowledgeGraph = await generator.generateKnowledgeGraph({
domain: 'technology',
entities: 50,
relationships: 150,
includeEmbeddings: true,
embeddingDimension: 768
});
console.log(`Generated ${knowledgeGraph.data.nodes.length} nodes`);
console.log(`Generated ${knowledgeGraph.data.edges.length} edges`);
console.log(`Duration: ${knowledgeGraph.metadata.duration}ms`);
// Generate Cypher statements
const cypher = generator.generateCypher(knowledgeGraph.data, {
useConstraints: true,
useIndexes: true,
useMerge: false
});
// Save to file
fs_1.default.writeFileSync('knowledge-graph.cypher', cypher);
console.log('Saved Cypher to knowledge-graph.cypher');
console.log('\n=== Social Network Generation ===');
const socialNetwork = await generator.generateSocialNetwork({
users: 100,
avgConnections: 10,
networkType: 'small-world',
includeMetadata: true,
includeEmbeddings: false
});
console.log(`Generated ${socialNetwork.data.nodes.length} users`);
console.log(`Generated ${socialNetwork.data.edges.length} connections`);
const socialCypher = generator.generateCypher(socialNetwork.data);
fs_1.default.writeFileSync('social-network.cypher', socialCypher);
console.log('Saved Cypher to social-network.cypher');
console.log('\n=== Temporal Events Generation ===');
const temporalEvents = await generator.generateTemporalEvents({
startDate: '2024-01-01',
endDate: '2024-01-31',
eventTypes: ['login', 'purchase', 'logout', 'error'],
eventsPerDay: 20,
entities: 25,
includeEmbeddings: false
});
console.log(`Generated ${temporalEvents.data.nodes.length} nodes`);
console.log(`Generated ${temporalEvents.data.edges.length} edges`);
const temporalCypher = generator.generateCypher(temporalEvents.data);
fs_1.default.writeFileSync('temporal-events.cypher', temporalCypher);
console.log('Saved Cypher to temporal-events.cypher');
console.log('\n=== Entity Relationships Generation ===');
const erGraph = await generator.generateEntityRelationships({
domain: 'e-commerce',
entityCount: 75,
relationshipDensity: 0.2,
includeEmbeddings: false
});
console.log(`Generated ${erGraph.data.nodes.length} entities`);
console.log(`Generated ${erGraph.data.edges.length} relationships`);
const erCypher = generator.generateCypher(erGraph.data);
fs_1.default.writeFileSync('entity-relationships.cypher', erCypher);
console.log('Saved Cypher to entity-relationships.cypher');
console.log('\n✓ All examples completed successfully!');
}
main().catch(console.error);
//# sourceMappingURL=basic-usage.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"basic-usage.js","sourceRoot":"","sources":["basic-usage.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,90 @@
/**
* Basic usage examples for @ruvector/graph-data-generator
*/
import { createGraphDataGenerator } from '../src/index.js';
import fs from 'fs';
async function main() {
// Initialize generator with OpenRouter API key
const generator = createGraphDataGenerator({
apiKey: process.env.OPENROUTER_API_KEY,
model: 'moonshot/kimi-k2-instruct'
});
console.log('=== Knowledge Graph Generation ===');
const knowledgeGraph = await generator.generateKnowledgeGraph({
domain: 'technology',
entities: 50,
relationships: 150,
includeEmbeddings: true,
embeddingDimension: 768
});
console.log(`Generated ${knowledgeGraph.data.nodes.length} nodes`);
console.log(`Generated ${knowledgeGraph.data.edges.length} edges`);
console.log(`Duration: ${knowledgeGraph.metadata.duration}ms`);
// Generate Cypher statements
const cypher = generator.generateCypher(knowledgeGraph.data, {
useConstraints: true,
useIndexes: true,
useMerge: false
});
// Save to file
fs.writeFileSync('knowledge-graph.cypher', cypher);
console.log('Saved Cypher to knowledge-graph.cypher');
console.log('\n=== Social Network Generation ===');
const socialNetwork = await generator.generateSocialNetwork({
users: 100,
avgConnections: 10,
networkType: 'small-world',
includeMetadata: true,
includeEmbeddings: false
});
console.log(`Generated ${socialNetwork.data.nodes.length} users`);
console.log(`Generated ${socialNetwork.data.edges.length} connections`);
const socialCypher = generator.generateCypher(socialNetwork.data);
fs.writeFileSync('social-network.cypher', socialCypher);
console.log('Saved Cypher to social-network.cypher');
console.log('\n=== Temporal Events Generation ===');
const temporalEvents = await generator.generateTemporalEvents({
startDate: '2024-01-01',
endDate: '2024-01-31',
eventTypes: ['login', 'purchase', 'logout', 'error'],
eventsPerDay: 20,
entities: 25,
includeEmbeddings: false
});
console.log(`Generated ${temporalEvents.data.nodes.length} nodes`);
console.log(`Generated ${temporalEvents.data.edges.length} edges`);
const temporalCypher = generator.generateCypher(temporalEvents.data);
fs.writeFileSync('temporal-events.cypher', temporalCypher);
console.log('Saved Cypher to temporal-events.cypher');
console.log('\n=== Entity Relationships Generation ===');
const erGraph = await generator.generateEntityRelationships({
domain: 'e-commerce',
entityCount: 75,
relationshipDensity: 0.2,
includeEmbeddings: false
});
console.log(`Generated ${erGraph.data.nodes.length} entities`);
console.log(`Generated ${erGraph.data.edges.length} relationships`);
const erCypher = generator.generateCypher(erGraph.data);
fs.writeFileSync('entity-relationships.cypher', erCypher);
console.log('Saved Cypher to entity-relationships.cypher');
console.log('\n✓ All examples completed successfully!');
}
main().catch(console.error);

View File

@@ -0,0 +1,8 @@
/**
* Integration example with @ruvector/agentic-synth
*
* This example shows how to use both agentic-synth and graph-data-generator
* together to create comprehensive synthetic datasets.
*/
export {};
//# sourceMappingURL=integration-with-agentic-synth.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"integration-with-agentic-synth.d.ts","sourceRoot":"","sources":["integration-with-agentic-synth.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}

View File

@@ -0,0 +1,177 @@
"use strict";
/**
* Integration example with @ruvector/agentic-synth
*
* This example shows how to use both agentic-synth and graph-data-generator
* together to create comprehensive synthetic datasets.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const agentic_synth_1 = require("@ruvector/agentic-synth");
const index_js_1 = require("../src/index.js");
const fs_1 = __importDefault(require("fs"));
async function main() {
// Initialize both generators
const synth = (0, agentic_synth_1.createSynth)({
provider: 'gemini',
apiKey: process.env.GEMINI_API_KEY,
model: 'gemini-2.0-flash-exp'
});
const graphGen = (0, index_js_1.createGraphDataGenerator)({
apiKey: process.env.OPENROUTER_API_KEY,
model: 'moonshot/kimi-k2-instruct'
});
console.log('=== Hybrid Synthetic Data Generation ===\n');
// Step 1: Generate structured user data with agentic-synth
console.log('1. Generating user profiles with agentic-synth...');
const userProfiles = await synth.generateStructured({
count: 50,
schema: {
user_id: { type: 'string' },
name: { type: 'string' },
email: { type: 'string' },
role: { type: 'string', enum: ['developer', 'designer', 'manager', 'analyst'] },
skills: { type: 'array', items: { type: 'string' } },
experience_years: { type: 'number', minimum: 0, maximum: 30 }
}
});
console.log(`✓ Generated ${userProfiles.data.length} user profiles`);
// Step 2: Generate project data with agentic-synth
console.log('\n2. Generating project data with agentic-synth...');
const projects = await synth.generateStructured({
count: 20,
schema: {
project_id: { type: 'string' },
name: { type: 'string' },
description: { type: 'string' },
status: { type: 'string', enum: ['active', 'completed', 'on-hold'] },
start_date: { type: 'string' },
tech_stack: { type: 'array', items: { type: 'string' } }
}
});
console.log(`✓ Generated ${projects.data.length} projects`);
// Step 3: Generate knowledge graph relationships with graph-data-generator
console.log('\n3. Generating knowledge graph with relationships...');
const knowledgeGraph = await graphGen.generateKnowledgeGraph({
domain: 'software development teams',
entities: 100,
relationships: 300,
entityTypes: ['Person', 'Project', 'Skill', 'Technology', 'Team'],
relationshipTypes: [
'WORKS_ON',
'HAS_SKILL',
'USES_TECHNOLOGY',
'MEMBER_OF',
'DEPENDS_ON',
'MENTORS'
],
includeEmbeddings: true
});
console.log(`✓ Generated ${knowledgeGraph.data.nodes.length} nodes`);
console.log(`✓ Generated ${knowledgeGraph.data.edges.length} edges`);
// Step 4: Generate temporal event data
console.log('\n4. Generating temporal events for user activities...');
const temporalEvents = await graphGen.generateTemporalEvents({
startDate: '2024-01-01',
endDate: '2024-12-31',
eventTypes: [
'code_commit',
'pull_request',
'code_review',
'deployment',
'meeting',
'task_completed'
],
eventsPerDay: 50,
entities: 50,
includeEmbeddings: false
});
console.log(`✓ Generated ${temporalEvents.data.nodes.length} temporal nodes`);
console.log(`✓ Generated ${temporalEvents.data.edges.length} temporal edges`);
// Step 5: Generate time-series metrics with agentic-synth
console.log('\n5. Generating time-series metrics with agentic-synth...');
const metrics = await synth.generateTimeSeries({
startDate: '2024-01-01',
endDate: '2024-12-31',
interval: '1d',
metrics: ['code_quality', 'test_coverage', 'deployment_frequency'],
trend: 'up',
seasonality: true,
noise: 0.1
});
console.log(`✓ Generated ${metrics.data.length} time-series data points`);
// Step 6: Combine and export data
console.log('\n6. Combining and exporting datasets...');
// Save structured data as JSON
fs_1.default.writeFileSync('users.json', JSON.stringify(userProfiles.data, null, 2));
fs_1.default.writeFileSync('projects.json', JSON.stringify(projects.data, null, 2));
fs_1.default.writeFileSync('metrics.json', JSON.stringify(metrics.data, null, 2));
// Save graph data as Cypher
const knowledgeCypher = graphGen.generateCypher(knowledgeGraph.data, {
useConstraints: true,
useIndexes: true,
useMerge: true
});
fs_1.default.writeFileSync('knowledge-graph.cypher', knowledgeCypher);
const temporalCypher = graphGen.generateCypher(temporalEvents.data, {
useConstraints: true,
useIndexes: true
});
fs_1.default.writeFileSync('temporal-events.cypher', temporalCypher);
// Create a combined dataset summary
const summary = {
generation_timestamp: new Date().toISOString(),
datasets: {
user_profiles: {
count: userProfiles.data.length,
provider: 'gemini',
file: 'users.json'
},
projects: {
count: projects.data.length,
provider: 'gemini',
file: 'projects.json'
},
knowledge_graph: {
nodes: knowledgeGraph.data.nodes.length,
edges: knowledgeGraph.data.edges.length,
provider: 'openrouter/kimi-k2',
file: 'knowledge-graph.cypher',
has_embeddings: true
},
temporal_events: {
nodes: temporalEvents.data.nodes.length,
edges: temporalEvents.data.edges.length,
provider: 'openrouter/kimi-k2',
file: 'temporal-events.cypher'
},
time_series_metrics: {
count: metrics.data.length,
provider: 'gemini',
file: 'metrics.json'
}
},
total_generation_time: {
knowledge_graph: knowledgeGraph.metadata.duration,
temporal_events: temporalEvents.metadata.duration
}
};
fs_1.default.writeFileSync('dataset-summary.json', JSON.stringify(summary, null, 2));
console.log('\n✓ All datasets generated and saved!');
console.log('\nGenerated files:');
console.log('- users.json (structured user profiles)');
console.log('- projects.json (structured project data)');
console.log('- metrics.json (time-series metrics)');
console.log('- knowledge-graph.cypher (Neo4j graph with embeddings)');
console.log('- temporal-events.cypher (Neo4j temporal events)');
console.log('- dataset-summary.json (metadata and summary)');
console.log('\n=== Integration Complete ===');
console.log(`Total nodes in graphs: ${knowledgeGraph.data.nodes.length + temporalEvents.data.nodes.length}`);
console.log(`Total edges in graphs: ${knowledgeGraph.data.edges.length + temporalEvents.data.edges.length}`);
console.log(`Total structured records: ${userProfiles.data.length + projects.data.length}`);
console.log(`Total time-series points: ${metrics.data.length}`);
}
main().catch(console.error);
//# sourceMappingURL=integration-with-agentic-synth.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,194 @@
/**
* Integration example with @ruvector/agentic-synth
*
* This example shows how to use both agentic-synth and graph-data-generator
* together to create comprehensive synthetic datasets.
*/
import { createSynth } from '@ruvector/agentic-synth';
import { createGraphDataGenerator } from '../src/index.js';
import fs from 'fs';
async function main() {
// Initialize both generators
const synth = createSynth({
provider: 'gemini',
apiKey: process.env.GEMINI_API_KEY,
model: 'gemini-2.0-flash-exp'
});
const graphGen = createGraphDataGenerator({
apiKey: process.env.OPENROUTER_API_KEY,
model: 'moonshot/kimi-k2-instruct'
});
console.log('=== Hybrid Synthetic Data Generation ===\n');
// Step 1: Generate structured user data with agentic-synth
console.log('1. Generating user profiles with agentic-synth...');
const userProfiles = await synth.generateStructured({
count: 50,
schema: {
user_id: { type: 'string' },
name: { type: 'string' },
email: { type: 'string' },
role: { type: 'string', enum: ['developer', 'designer', 'manager', 'analyst'] },
skills: { type: 'array', items: { type: 'string' } },
experience_years: { type: 'number', minimum: 0, maximum: 30 }
}
});
console.log(`✓ Generated ${userProfiles.data.length} user profiles`);
// Step 2: Generate project data with agentic-synth
console.log('\n2. Generating project data with agentic-synth...');
const projects = await synth.generateStructured({
count: 20,
schema: {
project_id: { type: 'string' },
name: { type: 'string' },
description: { type: 'string' },
status: { type: 'string', enum: ['active', 'completed', 'on-hold'] },
start_date: { type: 'string' },
tech_stack: { type: 'array', items: { type: 'string' } }
}
});
console.log(`✓ Generated ${projects.data.length} projects`);
// Step 3: Generate knowledge graph relationships with graph-data-generator
console.log('\n3. Generating knowledge graph with relationships...');
const knowledgeGraph = await graphGen.generateKnowledgeGraph({
domain: 'software development teams',
entities: 100,
relationships: 300,
entityTypes: ['Person', 'Project', 'Skill', 'Technology', 'Team'],
relationshipTypes: [
'WORKS_ON',
'HAS_SKILL',
'USES_TECHNOLOGY',
'MEMBER_OF',
'DEPENDS_ON',
'MENTORS'
],
includeEmbeddings: true
});
console.log(`✓ Generated ${knowledgeGraph.data.nodes.length} nodes`);
console.log(`✓ Generated ${knowledgeGraph.data.edges.length} edges`);
// Step 4: Generate temporal event data
console.log('\n4. Generating temporal events for user activities...');
const temporalEvents = await graphGen.generateTemporalEvents({
startDate: '2024-01-01',
endDate: '2024-12-31',
eventTypes: [
'code_commit',
'pull_request',
'code_review',
'deployment',
'meeting',
'task_completed'
],
eventsPerDay: 50,
entities: 50,
includeEmbeddings: false
});
console.log(`✓ Generated ${temporalEvents.data.nodes.length} temporal nodes`);
console.log(`✓ Generated ${temporalEvents.data.edges.length} temporal edges`);
// Step 5: Generate time-series metrics with agentic-synth
console.log('\n5. Generating time-series metrics with agentic-synth...');
const metrics = await synth.generateTimeSeries({
startDate: '2024-01-01',
endDate: '2024-12-31',
interval: '1d',
metrics: ['code_quality', 'test_coverage', 'deployment_frequency'],
trend: 'up',
seasonality: true,
noise: 0.1
});
console.log(`✓ Generated ${metrics.data.length} time-series data points`);
// Step 6: Combine and export data
console.log('\n6. Combining and exporting datasets...');
// Save structured data as JSON
fs.writeFileSync('users.json', JSON.stringify(userProfiles.data, null, 2));
fs.writeFileSync('projects.json', JSON.stringify(projects.data, null, 2));
fs.writeFileSync('metrics.json', JSON.stringify(metrics.data, null, 2));
// Save graph data as Cypher
const knowledgeCypher = graphGen.generateCypher(knowledgeGraph.data, {
useConstraints: true,
useIndexes: true,
useMerge: true
});
fs.writeFileSync('knowledge-graph.cypher', knowledgeCypher);
const temporalCypher = graphGen.generateCypher(temporalEvents.data, {
useConstraints: true,
useIndexes: true
});
fs.writeFileSync('temporal-events.cypher', temporalCypher);
// Create a combined dataset summary
const summary = {
generation_timestamp: new Date().toISOString(),
datasets: {
user_profiles: {
count: userProfiles.data.length,
provider: 'gemini',
file: 'users.json'
},
projects: {
count: projects.data.length,
provider: 'gemini',
file: 'projects.json'
},
knowledge_graph: {
nodes: knowledgeGraph.data.nodes.length,
edges: knowledgeGraph.data.edges.length,
provider: 'openrouter/kimi-k2',
file: 'knowledge-graph.cypher',
has_embeddings: true
},
temporal_events: {
nodes: temporalEvents.data.nodes.length,
edges: temporalEvents.data.edges.length,
provider: 'openrouter/kimi-k2',
file: 'temporal-events.cypher'
},
time_series_metrics: {
count: metrics.data.length,
provider: 'gemini',
file: 'metrics.json'
}
},
total_generation_time: {
knowledge_graph: knowledgeGraph.metadata.duration,
temporal_events: temporalEvents.metadata.duration
}
};
fs.writeFileSync('dataset-summary.json', JSON.stringify(summary, null, 2));
console.log('\n✓ All datasets generated and saved!');
console.log('\nGenerated files:');
console.log('- users.json (structured user profiles)');
console.log('- projects.json (structured project data)');
console.log('- metrics.json (time-series metrics)');
console.log('- knowledge-graph.cypher (Neo4j graph with embeddings)');
console.log('- temporal-events.cypher (Neo4j temporal events)');
console.log('- dataset-summary.json (metadata and summary)');
console.log('\n=== Integration Complete ===');
console.log(`Total nodes in graphs: ${knowledgeGraph.data.nodes.length + temporalEvents.data.nodes.length}`);
console.log(`Total edges in graphs: ${knowledgeGraph.data.edges.length + temporalEvents.data.edges.length}`);
console.log(`Total structured records: ${userProfiles.data.length + projects.data.length}`);
console.log(`Total time-series points: ${metrics.data.length}`);
}
main().catch(console.error);

View File

@@ -0,0 +1,117 @@
{
"name": "@ruvector/graph-data-generator",
"version": "0.1.0",
"description": "AI-powered synthetic graph data generation with OpenRouter/Kimi K2 integration for Neo4j knowledge graphs, social networks, and temporal events",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"type": "module",
"bin": {
"graph-synth": "./bin/cli.js"
},
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"require": "./dist/index.cjs"
},
"./generators": {
"types": "./dist/generators/index.d.ts",
"import": "./dist/generators/index.js",
"require": "./dist/generators/index.cjs"
},
"./schemas": {
"types": "./dist/schemas/index.d.ts",
"import": "./dist/schemas/index.js",
"require": "./dist/schemas/index.cjs"
}
},
"files": [
"dist/**/*.js",
"dist/**/*.cjs",
"dist/**/*.d.ts",
"dist/**/*.map",
"bin",
"config",
"README.md",
"LICENSE"
],
"scripts": {
"build": "tsup src/index.ts --format esm,cjs --dts --clean",
"build:generators": "tsup src/generators/index.ts --format esm,cjs --dts --out-dir dist/generators",
"build:schemas": "tsup src/schemas/index.ts --format esm,cjs --dts --out-dir dist/schemas",
"build:all": "npm run build && npm run build:generators && npm run build:schemas",
"dev": "tsup src/index.ts --format esm --watch",
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage",
"typecheck": "tsc --noEmit",
"lint": "eslint src tests --ext .ts,.js",
"lint:fix": "eslint src tests --ext .ts,.js --fix",
"format": "prettier --write \"src/**/*.{ts,js}\" \"tests/**/*.{ts,js}\"",
"format:check": "prettier --check \"src/**/*.{ts,js}\" \"tests/**/*.{ts,js}\"",
"prepublishOnly": "npm run build:all"
},
"dependencies": {
"@ruvector/agentic-synth": "^0.1.0",
"dotenv": "^16.6.1",
"p-retry": "^6.2.1",
"p-throttle": "^6.2.0",
"zod": "^4.1.12"
},
"peerDependencies": {
"@ruvector/agentic-synth": "^0.1.0"
},
"peerDependenciesMeta": {
"@ruvector/agentic-synth": {
"optional": true
}
},
"devDependencies": {
"@types/node": "^20.19.25",
"@typescript-eslint/eslint-plugin": "^8.47.0",
"@typescript-eslint/parser": "^8.47.0",
"@vitest/coverage-v8": "^3.2.4",
"eslint": "^8.57.1",
"prettier": "^3.6.2",
"tsup": "^8.5.1",
"typescript": "^5.9.3",
"vitest": "^3.2.4"
},
"keywords": [
"graph-data",
"knowledge-graph",
"social-network",
"neo4j",
"cypher",
"synthetic-data",
"openrouter",
"kimi-k2",
"graph-generation",
"vector-embeddings",
"temporal-graphs",
"entity-relationships",
"ruvector",
"ai-training",
"llm",
"typescript"
],
"author": {
"name": "rUv",
"url": "https://github.com/ruvnet"
},
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/ruvnet/ruvector.git",
"directory": "packages/graph-data-generator"
},
"homepage": "https://github.com/ruvnet/ruvector/tree/main/packages/graph-data-generator#readme",
"bugs": {
"url": "https://github.com/ruvnet/ruvector/issues"
},
"engines": {
"node": ">=18.0.0",
"npm": ">=9.0.0"
}
}

View File

@@ -0,0 +1,63 @@
/**
* Cypher statement generator for Neo4j
*/
import { GraphData, CypherStatement, CypherBatch } from './types.js';
export declare class CypherGenerator {
/**
* Generate Cypher statements from graph data
*/
generate(data: GraphData): CypherBatch;
/**
* Generate CREATE statement for a node
*/
private generateNodeStatement;
/**
* Generate CREATE statement for an edge
*/
private generateEdgeStatement;
/**
* Generate MERGE statements (upsert)
*/
generateMergeStatements(data: GraphData): CypherBatch;
/**
* Generate MERGE statement for a node
*/
private generateNodeMergeStatement;
/**
* Generate MERGE statement for an edge
*/
private generateEdgeMergeStatement;
/**
* Generate index creation statements
*/
generateIndexStatements(data: GraphData): CypherStatement[];
/**
* Generate constraint creation statements
*/
generateConstraintStatements(data: GraphData): CypherStatement[];
/**
* Generate complete setup script
*/
generateSetupScript(data: GraphData, options?: {
useConstraints?: boolean;
useIndexes?: boolean;
useMerge?: boolean;
}): string;
/**
* Format a statement for output
*/
private formatStatement;
/**
* Escape label names for Cypher
*/
private escapeLabel;
/**
* Generate batch insert with transactions
*/
generateBatchInsert(data: GraphData, batchSize?: number): CypherStatement[];
}
/**
* Create a Cypher generator
*/
export declare function createCypherGenerator(): CypherGenerator;
//# sourceMappingURL=cypher-generator.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"cypher-generator.d.ts","sourceRoot":"","sources":["cypher-generator.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,SAAS,EAGT,eAAe,EACf,WAAW,EACZ,MAAM,YAAY,CAAC;AAEpB,qBAAa,eAAe;IAC1B;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,WAAW;IA+BtC;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAgB7B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAsB7B;;OAEG;IACH,uBAAuB,CAAC,IAAI,EAAE,SAAS,GAAG,WAAW;IA8BrD;;OAEG;IACH,OAAO,CAAC,0BAA0B;IAqBlC;;OAEG;IACH,OAAO,CAAC,0BAA0B;IAuBlC;;OAEG;IACH,uBAAuB,CAAC,IAAI,EAAE,SAAS,GAAG,eAAe,EAAE;IAoC3D;;OAEG;IACH,4BAA4B,CAAC,IAAI,EAAE,SAAS,GAAG,eAAe,EAAE;IAgBhE;;OAEG;IACH,mBAAmB,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE;QAC7C,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB,GAAG,MAAM;IAkCV;;OAEG;IACH,OAAO,CAAC,eAAe;IAcvB;;OAEG;IACH,OAAO,CAAC,WAAW;IAQnB;;OAEG;IACH,mBAAmB,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,GAAE,MAAa,GAAG,eAAe,EAAE;CAkDlF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,eAAe,CAEvD"}

View File

@@ -0,0 +1,312 @@
"use strict";
/**
* Cypher statement generator for Neo4j
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.CypherGenerator = void 0;
exports.createCypherGenerator = createCypherGenerator;
class CypherGenerator {
/**
* Generate Cypher statements from graph data
*/
generate(data) {
const statements = [];
// Generate node creation statements
for (const node of data.nodes) {
statements.push(this.generateNodeStatement(node));
}
// Generate relationship creation statements
for (const edge of data.edges) {
statements.push(this.generateEdgeStatement(edge));
}
// Collect metadata
const labels = new Set();
const relationshipTypes = new Set();
data.nodes.forEach(node => node.labels.forEach(label => labels.add(label)));
data.edges.forEach(edge => relationshipTypes.add(edge.type));
return {
statements,
metadata: {
total_nodes: data.nodes.length,
total_relationships: data.edges.length,
labels: Array.from(labels),
relationship_types: Array.from(relationshipTypes)
}
};
}
/**
* Generate CREATE statement for a node
*/
generateNodeStatement(node) {
const labels = node.labels.map(l => `:${this.escapeLabel(l)}`).join('');
const propsVar = 'props';
return {
query: `CREATE (n${labels} $${propsVar})`,
parameters: {
[propsVar]: {
id: node.id,
...node.properties,
...(node.embedding ? { embedding: node.embedding } : {})
}
}
};
}
/**
* Generate CREATE statement for an edge
*/
generateEdgeStatement(edge) {
const type = this.escapeLabel(edge.type);
const propsVar = 'props';
return {
query: `
MATCH (source { id: $sourceId })
MATCH (target { id: $targetId })
CREATE (source)-[r:${type} $${propsVar}]->(target)
`.trim(),
parameters: {
sourceId: edge.source,
targetId: edge.target,
[propsVar]: {
id: edge.id,
...edge.properties,
...(edge.embedding ? { embedding: edge.embedding } : {})
}
}
};
}
/**
* Generate MERGE statements (upsert)
*/
generateMergeStatements(data) {
const statements = [];
// Generate node merge statements
for (const node of data.nodes) {
statements.push(this.generateNodeMergeStatement(node));
}
// Generate relationship merge statements
for (const edge of data.edges) {
statements.push(this.generateEdgeMergeStatement(edge));
}
const labels = new Set();
const relationshipTypes = new Set();
data.nodes.forEach(node => node.labels.forEach(label => labels.add(label)));
data.edges.forEach(edge => relationshipTypes.add(edge.type));
return {
statements,
metadata: {
total_nodes: data.nodes.length,
total_relationships: data.edges.length,
labels: Array.from(labels),
relationship_types: Array.from(relationshipTypes)
}
};
}
/**
* Generate MERGE statement for a node
*/
generateNodeMergeStatement(node) {
const primaryLabel = node.labels[0];
const additionalLabels = node.labels.slice(1).map(l => `:${this.escapeLabel(l)}`).join('');
const propsVar = 'props';
return {
query: `
MERGE (n:${this.escapeLabel(primaryLabel)} { id: $id })
SET n${additionalLabels}
SET n += $${propsVar}
`.trim(),
parameters: {
id: node.id,
[propsVar]: {
...node.properties,
...(node.embedding ? { embedding: node.embedding } : {})
}
}
};
}
/**
* Generate MERGE statement for an edge
*/
generateEdgeMergeStatement(edge) {
const type = this.escapeLabel(edge.type);
const propsVar = 'props';
return {
query: `
MATCH (source { id: $sourceId })
MATCH (target { id: $targetId })
MERGE (source)-[r:${type} { id: $id }]->(target)
SET r += $${propsVar}
`.trim(),
parameters: {
sourceId: edge.source,
targetId: edge.target,
id: edge.id,
[propsVar]: {
...edge.properties,
...(edge.embedding ? { embedding: edge.embedding } : {})
}
}
};
}
/**
* Generate index creation statements
*/
generateIndexStatements(data) {
const statements = [];
const labels = new Set();
data.nodes.forEach(node => node.labels.forEach(label => labels.add(label)));
// Create index on id for each label
for (const label of labels) {
statements.push({
query: `CREATE INDEX IF NOT EXISTS FOR (n:${this.escapeLabel(label)}) ON (n.id)`
});
}
// Create vector indexes if embeddings are present
const hasEmbeddings = data.nodes.some(node => node.embedding);
if (hasEmbeddings) {
for (const label of labels) {
statements.push({
query: `
CREATE VECTOR INDEX IF NOT EXISTS ${this.escapeLabel(label)}_embedding
FOR (n:${this.escapeLabel(label)})
ON (n.embedding)
OPTIONS {
indexConfig: {
\`vector.dimensions\`: ${data.nodes.find(n => n.embedding)?.embedding?.length || 1536},
\`vector.similarity_function\`: 'cosine'
}
}
`.trim()
});
}
}
return statements;
}
/**
* Generate constraint creation statements
*/
generateConstraintStatements(data) {
const statements = [];
const labels = new Set();
data.nodes.forEach(node => node.labels.forEach(label => labels.add(label)));
// Create unique constraint on id for each label
for (const label of labels) {
statements.push({
query: `CREATE CONSTRAINT IF NOT EXISTS FOR (n:${this.escapeLabel(label)}) REQUIRE n.id IS UNIQUE`
});
}
return statements;
}
/**
* Generate complete setup script
*/
generateSetupScript(data, options) {
const statements = [];
// Add constraints
if (options?.useConstraints !== false) {
statements.push('// Create constraints');
this.generateConstraintStatements(data).forEach(stmt => {
statements.push(this.formatStatement(stmt) + ';');
});
statements.push('');
}
// Add indexes
if (options?.useIndexes !== false) {
statements.push('// Create indexes');
this.generateIndexStatements(data).forEach(stmt => {
statements.push(this.formatStatement(stmt) + ';');
});
statements.push('');
}
// Add data
statements.push('// Create data');
const batch = options?.useMerge
? this.generateMergeStatements(data)
: this.generate(data);
batch.statements.forEach(stmt => {
statements.push(this.formatStatement(stmt) + ';');
});
return statements.join('\n');
}
/**
* Format a statement for output
*/
formatStatement(stmt) {
if (!stmt.parameters || Object.keys(stmt.parameters).length === 0) {
return stmt.query;
}
let formatted = stmt.query;
for (const [key, value] of Object.entries(stmt.parameters)) {
const jsonValue = JSON.stringify(value);
formatted = formatted.replace(new RegExp(`\\$${key}\\b`, 'g'), jsonValue);
}
return formatted;
}
/**
* Escape label names for Cypher
*/
escapeLabel(label) {
// Remove special characters and use backticks if needed
if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(label)) {
return label;
}
return `\`${label.replace(/`/g, '``')}\``;
}
/**
* Generate batch insert with transactions
*/
generateBatchInsert(data, batchSize = 1000) {
const statements = [];
// Batch nodes
for (let i = 0; i < data.nodes.length; i += batchSize) {
const batch = data.nodes.slice(i, i + batchSize);
statements.push({
query: `
UNWIND $nodes AS node
CREATE (n)
SET n = node.properties
SET n.id = node.id
WITH n, node.labels AS labels
CALL apoc.create.addLabels(n, labels) YIELD node AS labeled
RETURN count(labeled)
`.trim(),
parameters: {
nodes: batch.map(node => ({
id: node.id,
labels: node.labels,
properties: node.properties
}))
}
});
}
// Batch edges
for (let i = 0; i < data.edges.length; i += batchSize) {
const batch = data.edges.slice(i, i + batchSize);
statements.push({
query: `
UNWIND $edges AS edge
MATCH (source { id: edge.source })
MATCH (target { id: edge.target })
CALL apoc.create.relationship(source, edge.type, edge.properties, target) YIELD rel
RETURN count(rel)
`.trim(),
parameters: {
edges: batch.map(edge => ({
source: edge.source,
target: edge.target,
type: edge.type,
properties: edge.properties
}))
}
});
}
return statements;
}
}
exports.CypherGenerator = CypherGenerator;
/**
* Create a Cypher generator
*/
function createCypherGenerator() {
return new CypherGenerator();
}
//# sourceMappingURL=cypher-generator.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,362 @@
/**
* Cypher statement generator for Neo4j
*/
import {
GraphData,
GraphNode,
GraphEdge,
CypherStatement,
CypherBatch
} from './types.js';
export class CypherGenerator {
/**
* Generate Cypher statements from graph data
*/
generate(data: GraphData): CypherBatch {
const statements: CypherStatement[] = [];
// Generate node creation statements
for (const node of data.nodes) {
statements.push(this.generateNodeStatement(node));
}
// Generate relationship creation statements
for (const edge of data.edges) {
statements.push(this.generateEdgeStatement(edge));
}
// Collect metadata
const labels = new Set<string>();
const relationshipTypes = new Set<string>();
data.nodes.forEach(node => node.labels.forEach(label => labels.add(label)));
data.edges.forEach(edge => relationshipTypes.add(edge.type));
return {
statements,
metadata: {
total_nodes: data.nodes.length,
total_relationships: data.edges.length,
labels: Array.from(labels),
relationship_types: Array.from(relationshipTypes)
}
};
}
/**
* Generate CREATE statement for a node
*/
private generateNodeStatement(node: GraphNode): CypherStatement {
const labels = node.labels.map(l => `:${this.escapeLabel(l)}`).join('');
const propsVar = 'props';
return {
query: `CREATE (n${labels} $${propsVar})`,
parameters: {
[propsVar]: {
id: node.id,
...node.properties,
...(node.embedding ? { embedding: node.embedding } : {})
}
}
};
}
/**
* Generate CREATE statement for an edge
*/
private generateEdgeStatement(edge: GraphEdge): CypherStatement {
const type = this.escapeLabel(edge.type);
const propsVar = 'props';
return {
query: `
MATCH (source { id: $sourceId })
MATCH (target { id: $targetId })
CREATE (source)-[r:${type} $${propsVar}]->(target)
`.trim(),
parameters: {
sourceId: edge.source,
targetId: edge.target,
[propsVar]: {
id: edge.id,
...edge.properties,
...(edge.embedding ? { embedding: edge.embedding } : {})
}
}
};
}
/**
* Generate MERGE statements (upsert)
*/
generateMergeStatements(data: GraphData): CypherBatch {
const statements: CypherStatement[] = [];
// Generate node merge statements
for (const node of data.nodes) {
statements.push(this.generateNodeMergeStatement(node));
}
// Generate relationship merge statements
for (const edge of data.edges) {
statements.push(this.generateEdgeMergeStatement(edge));
}
const labels = new Set<string>();
const relationshipTypes = new Set<string>();
data.nodes.forEach(node => node.labels.forEach(label => labels.add(label)));
data.edges.forEach(edge => relationshipTypes.add(edge.type));
return {
statements,
metadata: {
total_nodes: data.nodes.length,
total_relationships: data.edges.length,
labels: Array.from(labels),
relationship_types: Array.from(relationshipTypes)
}
};
}
/**
* Generate MERGE statement for a node
*/
private generateNodeMergeStatement(node: GraphNode): CypherStatement {
const primaryLabel = node.labels[0];
const additionalLabels = node.labels.slice(1).map(l => `:${this.escapeLabel(l)}`).join('');
const propsVar = 'props';
return {
query: `
MERGE (n:${this.escapeLabel(primaryLabel)} { id: $id })
SET n${additionalLabels}
SET n += $${propsVar}
`.trim(),
parameters: {
id: node.id,
[propsVar]: {
...node.properties,
...(node.embedding ? { embedding: node.embedding } : {})
}
}
};
}
/**
* Generate MERGE statement for an edge
*/
private generateEdgeMergeStatement(edge: GraphEdge): CypherStatement {
const type = this.escapeLabel(edge.type);
const propsVar = 'props';
return {
query: `
MATCH (source { id: $sourceId })
MATCH (target { id: $targetId })
MERGE (source)-[r:${type} { id: $id }]->(target)
SET r += $${propsVar}
`.trim(),
parameters: {
sourceId: edge.source,
targetId: edge.target,
id: edge.id,
[propsVar]: {
...edge.properties,
...(edge.embedding ? { embedding: edge.embedding } : {})
}
}
};
}
/**
* Generate index creation statements
*/
generateIndexStatements(data: GraphData): CypherStatement[] {
const statements: CypherStatement[] = [];
const labels = new Set<string>();
data.nodes.forEach(node => node.labels.forEach(label => labels.add(label)));
// Create index on id for each label
for (const label of labels) {
statements.push({
query: `CREATE INDEX IF NOT EXISTS FOR (n:${this.escapeLabel(label)}) ON (n.id)`
});
}
// Create vector indexes if embeddings are present
const hasEmbeddings = data.nodes.some(node => node.embedding);
if (hasEmbeddings) {
for (const label of labels) {
statements.push({
query: `
CREATE VECTOR INDEX IF NOT EXISTS ${this.escapeLabel(label)}_embedding
FOR (n:${this.escapeLabel(label)})
ON (n.embedding)
OPTIONS {
indexConfig: {
\`vector.dimensions\`: ${data.nodes.find(n => n.embedding)?.embedding?.length || 1536},
\`vector.similarity_function\`: 'cosine'
}
}
`.trim()
});
}
}
return statements;
}
/**
* Generate constraint creation statements
*/
generateConstraintStatements(data: GraphData): CypherStatement[] {
const statements: CypherStatement[] = [];
const labels = new Set<string>();
data.nodes.forEach(node => node.labels.forEach(label => labels.add(label)));
// Create unique constraint on id for each label
for (const label of labels) {
statements.push({
query: `CREATE CONSTRAINT IF NOT EXISTS FOR (n:${this.escapeLabel(label)}) REQUIRE n.id IS UNIQUE`
});
}
return statements;
}
/**
* Generate complete setup script
*/
generateSetupScript(data: GraphData, options?: {
useConstraints?: boolean;
useIndexes?: boolean;
useMerge?: boolean;
}): string {
const statements: string[] = [];
// Add constraints
if (options?.useConstraints !== false) {
statements.push('// Create constraints');
this.generateConstraintStatements(data).forEach(stmt => {
statements.push(this.formatStatement(stmt) + ';');
});
statements.push('');
}
// Add indexes
if (options?.useIndexes !== false) {
statements.push('// Create indexes');
this.generateIndexStatements(data).forEach(stmt => {
statements.push(this.formatStatement(stmt) + ';');
});
statements.push('');
}
// Add data
statements.push('// Create data');
const batch = options?.useMerge
? this.generateMergeStatements(data)
: this.generate(data);
batch.statements.forEach(stmt => {
statements.push(this.formatStatement(stmt) + ';');
});
return statements.join('\n');
}
/**
* Format a statement for output
*/
private formatStatement(stmt: CypherStatement): string {
if (!stmt.parameters || Object.keys(stmt.parameters).length === 0) {
return stmt.query;
}
let formatted = stmt.query;
for (const [key, value] of Object.entries(stmt.parameters)) {
const jsonValue = JSON.stringify(value);
formatted = formatted.replace(new RegExp(`\\$${key}\\b`, 'g'), jsonValue);
}
return formatted;
}
/**
* Escape label names for Cypher
*/
private escapeLabel(label: string): string {
// Remove special characters and use backticks if needed
if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(label)) {
return label;
}
return `\`${label.replace(/`/g, '``')}\``;
}
/**
* Generate batch insert with transactions
*/
generateBatchInsert(data: GraphData, batchSize: number = 1000): CypherStatement[] {
const statements: CypherStatement[] = [];
// Batch nodes
for (let i = 0; i < data.nodes.length; i += batchSize) {
const batch = data.nodes.slice(i, i + batchSize);
statements.push({
query: `
UNWIND $nodes AS node
CREATE (n)
SET n = node.properties
SET n.id = node.id
WITH n, node.labels AS labels
CALL apoc.create.addLabels(n, labels) YIELD node AS labeled
RETURN count(labeled)
`.trim(),
parameters: {
nodes: batch.map(node => ({
id: node.id,
labels: node.labels,
properties: node.properties
}))
}
});
}
// Batch edges
for (let i = 0; i < data.edges.length; i += batchSize) {
const batch = data.edges.slice(i, i + batchSize);
statements.push({
query: `
UNWIND $edges AS edge
MATCH (source { id: edge.source })
MATCH (target { id: edge.target })
CALL apoc.create.relationship(source, edge.type, edge.properties, target) YIELD rel
RETURN count(rel)
`.trim(),
parameters: {
edges: batch.map(edge => ({
source: edge.source,
target: edge.target,
type: edge.type,
properties: edge.properties
}))
}
});
}
return statements;
}
}
/**
* Create a Cypher generator
*/
export function createCypherGenerator(): CypherGenerator {
return new CypherGenerator();
}

View File

@@ -0,0 +1,82 @@
/**
* Vector embedding enrichment for graph nodes and edges
*/
import { OpenRouterClient } from './openrouter-client.js';
import { GraphData, GraphNode, EmbeddingConfig } from './types.js';
export declare class EmbeddingEnrichment {
private client;
private config;
constructor(client: OpenRouterClient, config?: Partial<EmbeddingConfig>);
/**
* Enrich graph data with vector embeddings
*/
enrichGraphData(data: GraphData): Promise<GraphData>;
/**
* Enrich nodes with embeddings
*/
private enrichNodes;
/**
* Enrich edges with embeddings
*/
private enrichEdges;
/**
* Generate embedding for a node
*/
private generateNodeEmbedding;
/**
* Generate embedding for an edge
*/
private generateEdgeEmbedding;
/**
* Convert node to text for embedding
*/
private nodeToText;
/**
* Convert edge to text for embedding
*/
private edgeToText;
/**
* Generate embedding using OpenRouter or local model
*/
private generateEmbedding;
/**
* Generate semantic embedding using chat model
*/
private generateSemanticEmbedding;
/**
* Generate local embedding (placeholder)
*/
private generateLocalEmbedding;
/**
* Generate random embedding (fallback)
*/
private generateRandomEmbedding;
/**
* Calculate similarity between embeddings
*/
calculateSimilarity(embedding1: number[], embedding2: number[], metric?: 'cosine' | 'euclidean' | 'dot'): number;
/**
* Calculate cosine similarity
*/
private cosineSimilarity;
/**
* Calculate Euclidean distance
*/
private euclideanDistance;
/**
* Calculate dot product
*/
private dotProduct;
/**
* Find similar nodes using embeddings
*/
findSimilarNodes(node: GraphNode, allNodes: GraphNode[], topK?: number, metric?: 'cosine' | 'euclidean' | 'dot'): Array<{
node: GraphNode;
similarity: number;
}>;
}
/**
* Create an embedding enrichment instance
*/
export declare function createEmbeddingEnrichment(client: OpenRouterClient, config?: Partial<EmbeddingConfig>): EmbeddingEnrichment;
//# sourceMappingURL=embedding-enrichment.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"embedding-enrichment.d.ts","sourceRoot":"","sources":["embedding-enrichment.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EACL,SAAS,EACT,SAAS,EAET,eAAe,EAEhB,MAAM,YAAY,CAAC;AAEpB,qBAAa,mBAAmB;IAI5B,OAAO,CAAC,MAAM;IAHhB,OAAO,CAAC,MAAM,CAAkB;gBAGtB,MAAM,EAAE,gBAAgB,EAChC,MAAM,GAAE,OAAO,CAAC,eAAe,CAAM;IAUvC;;OAEG;IACG,eAAe,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;IAc1D;;OAEG;YACW,WAAW;IAgBzB;;OAEG;YACW,WAAW;IAgBzB;;OAEG;YACW,qBAAqB;IAanC;;OAEG;YACW,qBAAqB;IAanC;;OAEG;IACH,OAAO,CAAC,UAAU;IAgBlB;;OAEG;IACH,OAAO,CAAC,UAAU;IAgBlB;;OAEG;YACW,iBAAiB;IAiB/B;;OAEG;YACW,yBAAyB;IA6CvC;;OAEG;YACW,sBAAsB;IAUpC;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAW/B;;OAEG;IACH,mBAAmB,CACjB,UAAU,EAAE,MAAM,EAAE,EACpB,UAAU,EAAE,MAAM,EAAE,EACpB,MAAM,GAAE,QAAQ,GAAG,WAAW,GAAG,KAAgB,GAChD,MAAM;IAiBT;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAOxB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;OAEG;IACH,OAAO,CAAC,UAAU;IAIlB;;OAEG;IACH,gBAAgB,CACd,IAAI,EAAE,SAAS,EACf,QAAQ,EAAE,SAAS,EAAE,EACrB,IAAI,GAAE,MAAW,EACjB,MAAM,GAAE,QAAQ,GAAG,WAAW,GAAG,KAAgB,GAChD,KAAK,CAAC;QAAE,IAAI,EAAE,SAAS,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;CAgBlD;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,gBAAgB,EACxB,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAChC,mBAAmB,CAErB"}

View File

@@ -0,0 +1,257 @@
"use strict";
/**
* Vector embedding enrichment for graph nodes and edges
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.EmbeddingEnrichment = void 0;
exports.createEmbeddingEnrichment = createEmbeddingEnrichment;
class EmbeddingEnrichment {
constructor(client, config = {}) {
this.client = client;
this.config = {
provider: 'openrouter',
dimensions: 1536,
batchSize: 100,
...config
};
}
/**
* Enrich graph data with vector embeddings
*/
async enrichGraphData(data) {
// Generate embeddings for nodes
const enrichedNodes = await this.enrichNodes(data.nodes);
// Generate embeddings for edges (optional)
const enrichedEdges = await this.enrichEdges(data.edges);
return {
...data,
nodes: enrichedNodes,
edges: enrichedEdges
};
}
/**
* Enrich nodes with embeddings
*/
async enrichNodes(nodes) {
const enriched = [];
// Process in batches
for (let i = 0; i < nodes.length; i += this.config.batchSize) {
const batch = nodes.slice(i, i + this.config.batchSize);
const batchResults = await Promise.all(batch.map(node => this.generateNodeEmbedding(node)));
enriched.push(...batchResults);
}
return enriched;
}
/**
* Enrich edges with embeddings
*/
async enrichEdges(edges) {
const enriched = [];
// Process in batches
for (let i = 0; i < edges.length; i += this.config.batchSize) {
const batch = edges.slice(i, i + this.config.batchSize);
const batchResults = await Promise.all(batch.map(edge => this.generateEdgeEmbedding(edge)));
enriched.push(...batchResults);
}
return enriched;
}
/**
* Generate embedding for a node
*/
async generateNodeEmbedding(node) {
// Create text representation of node
const text = this.nodeToText(node);
// Generate embedding
const embedding = await this.generateEmbedding(text);
return {
...node,
embedding: embedding.embedding
};
}
/**
* Generate embedding for an edge
*/
async generateEdgeEmbedding(edge) {
// Create text representation of edge
const text = this.edgeToText(edge);
// Generate embedding
const embedding = await this.generateEmbedding(text);
return {
...edge,
embedding: embedding.embedding
};
}
/**
* Convert node to text for embedding
*/
nodeToText(node) {
const parts = [];
// Add labels
parts.push(`Type: ${node.labels.join(', ')}`);
// Add properties
for (const [key, value] of Object.entries(node.properties)) {
if (typeof value === 'string' || typeof value === 'number') {
parts.push(`${key}: ${value}`);
}
}
return parts.join('. ');
}
/**
* Convert edge to text for embedding
*/
edgeToText(edge) {
const parts = [];
// Add relationship type
parts.push(`Relationship: ${edge.type}`);
// Add properties
for (const [key, value] of Object.entries(edge.properties)) {
if (typeof value === 'string' || typeof value === 'number') {
parts.push(`${key}: ${value}`);
}
}
return parts.join('. ');
}
/**
* Generate embedding using OpenRouter or local model
*/
async generateEmbedding(text) {
if (this.config.provider === 'local') {
return this.generateLocalEmbedding(text);
}
// Use OpenRouter with embedding-capable model
// Note: Kimi K2 may not support embeddings, so we use a workaround
// by generating semantic vectors through the chat API
const embedding = await this.generateSemanticEmbedding(text);
return {
embedding,
model: this.config.model || 'moonshot/kimi-k2-instruct',
dimensions: embedding.length
};
}
/**
* Generate semantic embedding using chat model
*/
async generateSemanticEmbedding(text) {
// Use the chat API to generate a semantic representation
// This is a workaround for models without native embedding support
const systemPrompt = `You are a semantic encoder. Convert the input text into a semantic representation by analyzing its key concepts, entities, and relationships. Output ONLY a JSON array of ${this.config.dimensions} floating point numbers between -1 and 1 representing the semantic vector.`;
const userPrompt = `Encode this text into a ${this.config.dimensions}-dimensional semantic vector:\n\n${text}`;
try {
const response = await this.client.createCompletion([
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userPrompt }
], {
temperature: 0.3,
max_tokens: this.config.dimensions * 10
});
const content = response.choices[0]?.message?.content;
if (!content) {
throw new Error('No content in embedding response');
}
// Extract JSON array
const match = content.match(/\[([\s\S]*?)\]/);
if (match) {
const embedding = JSON.parse(`[${match[1]}]`);
// Ensure correct dimensions
if (embedding.length !== this.config.dimensions) {
return this.generateRandomEmbedding();
}
return embedding;
}
// Fallback to random embedding
return this.generateRandomEmbedding();
}
catch (error) {
console.warn('Failed to generate semantic embedding, using random:', error);
return this.generateRandomEmbedding();
}
}
/**
* Generate local embedding (placeholder)
*/
async generateLocalEmbedding(_text) {
// This would use a local embedding model
// For now, return a random embedding
return {
embedding: this.generateRandomEmbedding(),
model: 'local',
dimensions: this.config.dimensions
};
}
/**
* Generate random embedding (fallback)
*/
generateRandomEmbedding() {
const embedding = [];
for (let i = 0; i < this.config.dimensions; i++) {
embedding.push((Math.random() * 2) - 1); // Random value between -1 and 1
}
// Normalize to unit length
const magnitude = Math.sqrt(embedding.reduce((sum, val) => sum + val * val, 0));
return embedding.map(val => val / magnitude);
}
/**
* Calculate similarity between embeddings
*/
calculateSimilarity(embedding1, embedding2, metric = 'cosine') {
if (embedding1.length !== embedding2.length) {
throw new Error('Embeddings must have the same dimensions');
}
switch (metric) {
case 'cosine':
return this.cosineSimilarity(embedding1, embedding2);
case 'euclidean':
return this.euclideanDistance(embedding1, embedding2);
case 'dot':
return this.dotProduct(embedding1, embedding2);
default:
return this.cosineSimilarity(embedding1, embedding2);
}
}
/**
* Calculate cosine similarity
*/
cosineSimilarity(a, b) {
const dotProduct = a.reduce((sum, val, i) => sum + val * b[i], 0);
const magnitudeA = Math.sqrt(a.reduce((sum, val) => sum + val * val, 0));
const magnitudeB = Math.sqrt(b.reduce((sum, val) => sum + val * val, 0));
return dotProduct / (magnitudeA * magnitudeB);
}
/**
* Calculate Euclidean distance
*/
euclideanDistance(a, b) {
return Math.sqrt(a.reduce((sum, val, i) => sum + Math.pow(val - b[i], 2), 0));
}
/**
* Calculate dot product
*/
dotProduct(a, b) {
return a.reduce((sum, val, i) => sum + val * b[i], 0);
}
/**
* Find similar nodes using embeddings
*/
findSimilarNodes(node, allNodes, topK = 10, metric = 'cosine') {
if (!node.embedding) {
throw new Error('Node does not have an embedding');
}
const similarities = allNodes
.filter(n => n.id !== node.id && n.embedding)
.map(n => ({
node: n,
similarity: this.calculateSimilarity(node.embedding, n.embedding, metric)
}))
.sort((a, b) => b.similarity - a.similarity)
.slice(0, topK);
return similarities;
}
}
exports.EmbeddingEnrichment = EmbeddingEnrichment;
/**
* Create an embedding enrichment instance
*/
function createEmbeddingEnrichment(client, config) {
return new EmbeddingEnrichment(client, config);
}
//# sourceMappingURL=embedding-enrichment.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,331 @@
/**
* Vector embedding enrichment for graph nodes and edges
*/
import { OpenRouterClient } from './openrouter-client.js';
import {
GraphData,
GraphNode,
GraphEdge,
EmbeddingConfig,
EmbeddingResult
} from './types.js';
export class EmbeddingEnrichment {
private config: EmbeddingConfig;
constructor(
private client: OpenRouterClient,
config: Partial<EmbeddingConfig> = {}
) {
this.config = {
provider: 'openrouter',
dimensions: 1536,
batchSize: 100,
...config
};
}
/**
* Enrich graph data with vector embeddings
*/
async enrichGraphData(data: GraphData): Promise<GraphData> {
// Generate embeddings for nodes
const enrichedNodes = await this.enrichNodes(data.nodes);
// Generate embeddings for edges (optional)
const enrichedEdges = await this.enrichEdges(data.edges);
return {
...data,
nodes: enrichedNodes,
edges: enrichedEdges
};
}
/**
* Enrich nodes with embeddings
*/
private async enrichNodes(nodes: GraphNode[]): Promise<GraphNode[]> {
const enriched: GraphNode[] = [];
// Process in batches
for (let i = 0; i < nodes.length; i += this.config.batchSize!) {
const batch = nodes.slice(i, i + this.config.batchSize!);
const batchResults = await Promise.all(
batch.map(node => this.generateNodeEmbedding(node))
);
enriched.push(...batchResults);
}
return enriched;
}
/**
* Enrich edges with embeddings
*/
private async enrichEdges(edges: GraphEdge[]): Promise<GraphEdge[]> {
const enriched: GraphEdge[] = [];
// Process in batches
for (let i = 0; i < edges.length; i += this.config.batchSize!) {
const batch = edges.slice(i, i + this.config.batchSize!);
const batchResults = await Promise.all(
batch.map(edge => this.generateEdgeEmbedding(edge))
);
enriched.push(...batchResults);
}
return enriched;
}
/**
* Generate embedding for a node
*/
private async generateNodeEmbedding(node: GraphNode): Promise<GraphNode> {
// Create text representation of node
const text = this.nodeToText(node);
// Generate embedding
const embedding = await this.generateEmbedding(text);
return {
...node,
embedding: embedding.embedding
};
}
/**
* Generate embedding for an edge
*/
private async generateEdgeEmbedding(edge: GraphEdge): Promise<GraphEdge> {
// Create text representation of edge
const text = this.edgeToText(edge);
// Generate embedding
const embedding = await this.generateEmbedding(text);
return {
...edge,
embedding: embedding.embedding
};
}
/**
* Convert node to text for embedding
*/
private nodeToText(node: GraphNode): string {
const parts: string[] = [];
// Add labels
parts.push(`Type: ${node.labels.join(', ')}`);
// Add properties
for (const [key, value] of Object.entries(node.properties)) {
if (typeof value === 'string' || typeof value === 'number') {
parts.push(`${key}: ${value}`);
}
}
return parts.join('. ');
}
/**
* Convert edge to text for embedding
*/
private edgeToText(edge: GraphEdge): string {
const parts: string[] = [];
// Add relationship type
parts.push(`Relationship: ${edge.type}`);
// Add properties
for (const [key, value] of Object.entries(edge.properties)) {
if (typeof value === 'string' || typeof value === 'number') {
parts.push(`${key}: ${value}`);
}
}
return parts.join('. ');
}
/**
* Generate embedding using OpenRouter or local model
*/
private async generateEmbedding(text: string): Promise<EmbeddingResult> {
if (this.config.provider === 'local') {
return this.generateLocalEmbedding(text);
}
// Use OpenRouter with embedding-capable model
// Note: Kimi K2 may not support embeddings, so we use a workaround
// by generating semantic vectors through the chat API
const embedding = await this.generateSemanticEmbedding(text);
return {
embedding,
model: this.config.model || 'moonshot/kimi-k2-instruct',
dimensions: embedding.length
};
}
/**
* Generate semantic embedding using chat model
*/
private async generateSemanticEmbedding(text: string): Promise<number[]> {
// Use the chat API to generate a semantic representation
// This is a workaround for models without native embedding support
const systemPrompt = `You are a semantic encoder. Convert the input text into a semantic representation by analyzing its key concepts, entities, and relationships. Output ONLY a JSON array of ${this.config.dimensions} floating point numbers between -1 and 1 representing the semantic vector.`;
const userPrompt = `Encode this text into a ${this.config.dimensions}-dimensional semantic vector:\n\n${text}`;
try {
const response = await this.client.createCompletion(
[
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userPrompt }
],
{
temperature: 0.3,
max_tokens: this.config.dimensions! * 10
}
);
const content = response.choices[0]?.message?.content;
if (!content) {
throw new Error('No content in embedding response');
}
// Extract JSON array
const match = content.match(/\[([\s\S]*?)\]/);
if (match) {
const embedding = JSON.parse(`[${match[1]}]`) as number[];
// Ensure correct dimensions
if (embedding.length !== this.config.dimensions) {
return this.generateRandomEmbedding();
}
return embedding;
}
// Fallback to random embedding
return this.generateRandomEmbedding();
} catch (error) {
console.warn('Failed to generate semantic embedding, using random:', error);
return this.generateRandomEmbedding();
}
}
/**
* Generate local embedding (placeholder)
*/
private async generateLocalEmbedding(_text: string): Promise<EmbeddingResult> {
// This would use a local embedding model
// For now, return a random embedding
return {
embedding: this.generateRandomEmbedding(),
model: 'local',
dimensions: this.config.dimensions!
};
}
/**
* Generate random embedding (fallback)
*/
private generateRandomEmbedding(): number[] {
const embedding: number[] = [];
for (let i = 0; i < this.config.dimensions!; i++) {
embedding.push((Math.random() * 2) - 1); // Random value between -1 and 1
}
// Normalize to unit length
const magnitude = Math.sqrt(embedding.reduce((sum, val) => sum + val * val, 0));
return embedding.map(val => val / magnitude);
}
/**
* Calculate similarity between embeddings
*/
calculateSimilarity(
embedding1: number[],
embedding2: number[],
metric: 'cosine' | 'euclidean' | 'dot' = 'cosine'
): number {
if (embedding1.length !== embedding2.length) {
throw new Error('Embeddings must have the same dimensions');
}
switch (metric) {
case 'cosine':
return this.cosineSimilarity(embedding1, embedding2);
case 'euclidean':
return this.euclideanDistance(embedding1, embedding2);
case 'dot':
return this.dotProduct(embedding1, embedding2);
default:
return this.cosineSimilarity(embedding1, embedding2);
}
}
/**
* Calculate cosine similarity
*/
private cosineSimilarity(a: number[], b: number[]): number {
const dotProduct = a.reduce((sum, val, i) => sum + val * b[i], 0);
const magnitudeA = Math.sqrt(a.reduce((sum, val) => sum + val * val, 0));
const magnitudeB = Math.sqrt(b.reduce((sum, val) => sum + val * val, 0));
return dotProduct / (magnitudeA * magnitudeB);
}
/**
* Calculate Euclidean distance
*/
private euclideanDistance(a: number[], b: number[]): number {
return Math.sqrt(a.reduce((sum, val, i) => sum + Math.pow(val - b[i], 2), 0));
}
/**
* Calculate dot product
*/
private dotProduct(a: number[], b: number[]): number {
return a.reduce((sum, val, i) => sum + val * b[i], 0);
}
/**
* Find similar nodes using embeddings
*/
findSimilarNodes(
node: GraphNode,
allNodes: GraphNode[],
topK: number = 10,
metric: 'cosine' | 'euclidean' | 'dot' = 'cosine'
): Array<{ node: GraphNode; similarity: number }> {
if (!node.embedding) {
throw new Error('Node does not have an embedding');
}
const similarities = allNodes
.filter(n => n.id !== node.id && n.embedding)
.map(n => ({
node: n,
similarity: this.calculateSimilarity(node.embedding!, n.embedding!, metric)
}))
.sort((a, b) => b.similarity - a.similarity)
.slice(0, topK);
return similarities;
}
}
/**
* Create an embedding enrichment instance
*/
export function createEmbeddingEnrichment(
client: OpenRouterClient,
config?: Partial<EmbeddingConfig>
): EmbeddingEnrichment {
return new EmbeddingEnrichment(client, config);
}

View File

@@ -0,0 +1,49 @@
/**
* Entity relationship generator for domain-specific graphs
*/
import { OpenRouterClient } from '../openrouter-client.js';
import { EntityRelationshipOptions, GraphData, GraphGenerationResult } from '../types.js';
export declare class EntityRelationshipGenerator {
private client;
constructor(client: OpenRouterClient);
/**
* Generate entity-relationship graph
*/
generate(options: EntityRelationshipOptions): Promise<GraphGenerationResult<GraphData>>;
/**
* Generate domain-specific entities
*/
private generateEntities;
/**
* Generate relationships between entities
*/
private generateRelationships;
/**
* Generate schema-aware entities and relationships
*/
generateWithSchema(schema: {
entities: Record<string, {
properties: Record<string, string>;
relationships?: string[];
}>;
relationships: Record<string, {
from: string;
to: string;
properties?: Record<string, string>;
}>;
}, count: number): Promise<GraphData>;
/**
* Analyze entity-relationship patterns
*/
analyzeERPatterns(data: GraphData): Promise<{
entityTypeDistribution: Record<string, number>;
relationshipTypeDistribution: Record<string, number>;
avgRelationshipsPerEntity: number;
densityScore: number;
}>;
}
/**
* Create an entity relationship generator
*/
export declare function createEntityRelationshipGenerator(client: OpenRouterClient): EntityRelationshipGenerator;
//# sourceMappingURL=entity-relationships.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"entity-relationships.d.ts","sourceRoot":"","sources":["entity-relationships.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EACL,yBAAyB,EACzB,SAAS,EAGT,qBAAqB,EACtB,MAAM,aAAa,CAAC;AAerB,qBAAa,2BAA2B;IAC1B,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,gBAAgB;IAE5C;;OAEG;IACG,QAAQ,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;IA6C7F;;OAEG;YACW,gBAAgB;IA2C9B;;OAEG;YACW,qBAAqB;IA6DnC;;OAEG;IACG,kBAAkB,CACtB,MAAM,EAAE;QACN,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE;YACvB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACnC,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;SAC1B,CAAC,CAAC;QACH,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE;YAC5B,IAAI,EAAE,MAAM,CAAC;YACb,EAAE,EAAE,MAAM,CAAC;YACX,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;SACrC,CAAC,CAAC;KACJ,EACD,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,SAAS,CAAC;IA+BrB;;OAEG;IACG,iBAAiB,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC;QAChD,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC/C,4BAA4B,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACrD,yBAAyB,EAAE,MAAM,CAAC;QAClC,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;CAoCH;AAED;;GAEG;AACH,wBAAgB,iCAAiC,CAAC,MAAM,EAAE,gBAAgB,GAAG,2BAA2B,CAEvG"}

View File

@@ -0,0 +1,217 @@
"use strict";
/**
* Entity relationship generator for domain-specific graphs
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.EntityRelationshipGenerator = void 0;
exports.createEntityRelationshipGenerator = createEntityRelationshipGenerator;
class EntityRelationshipGenerator {
constructor(client) {
this.client = client;
}
/**
* Generate entity-relationship graph
*/
async generate(options) {
const startTime = Date.now();
// Generate entities
const entities = await this.generateEntities(options);
// Generate relationships
const relationships = await this.generateRelationships(entities, options);
// Convert to graph structure
const nodes = entities.map(entity => ({
id: entity.id,
labels: entity.labels || ['Entity'],
properties: entity.properties
}));
const edges = relationships.map((rel, idx) => ({
id: `rel_${idx}`,
type: rel.type,
source: rel.source,
target: rel.target,
properties: rel.properties || {}
}));
const data = {
nodes,
edges,
metadata: {
domain: options.domain,
generated_at: new Date(),
total_nodes: nodes.length,
total_edges: edges.length
}
};
return {
data,
metadata: {
generated_at: new Date(),
model: this.client.getConfig().model || 'moonshot/kimi-k2-instruct',
duration: Date.now() - startTime
}
};
}
/**
* Generate domain-specific entities
*/
async generateEntities(options) {
const systemPrompt = `You are an expert in ${options.domain} domain modeling. Generate realistic entities following best practices for ${options.domain} data models.`;
const schemaInfo = options.entitySchema
? `\n\nEntity schema to follow:\n${JSON.stringify(options.entitySchema, null, 2)}`
: '';
const userPrompt = `Generate ${options.entityCount} diverse entities for a ${options.domain} domain model.${schemaInfo}
Each entity should have:
- id: unique identifier (use snake_case)
- labels: array of entity type labels (e.g., ["Product", "Digital"])
- properties: object with entity properties (at least 3-5 meaningful properties)
Make entities realistic and relevant to ${options.domain}. Include variety in types and attributes.
Return a JSON array of entities.
Example format:
\`\`\`json
[
{
"id": "product_laptop_001",
"labels": ["Product", "Electronics", "Computer"],
"properties": {
"name": "UltraBook Pro 15",
"category": "Laptops",
"price": 1299.99,
"brand": "TechCorp",
"release_date": "2024-01-15",
"stock": 45,
"rating": 4.7
}
}
]
\`\`\``;
return this.client.generateStructured(systemPrompt, userPrompt, {
temperature: 0.8,
maxTokens: Math.min(8000, options.entityCount * 150)
});
}
/**
* Generate relationships between entities
*/
async generateRelationships(entities, options) {
// Calculate target relationship count based on density
const maxPossibleRelationships = entities.length * (entities.length - 1);
const targetRelationships = Math.floor(maxPossibleRelationships * options.relationshipDensity);
const relationshipTypes = options.relationshipTypes || [
'RELATES_TO',
'PART_OF',
'DEPENDS_ON',
'SIMILAR_TO',
'CONTAINS'
];
const systemPrompt = `You are an expert in ${options.domain} domain modeling. Create meaningful, realistic relationships between entities.`;
const entityList = entities.slice(0, 100).map(e => `- ${e.id} (${e.labels.join(', ')}): ${JSON.stringify(e.properties).substring(0, 100)}`).join('\n');
const userPrompt = `Given these entities from a ${options.domain} domain:
${entityList}
Generate ${targetRelationships} meaningful relationships between them.
Relationship types to use: ${relationshipTypes.join(', ')}
Each relationship should have:
- source: source entity id
- target: target entity id
- type: relationship type (use UPPER_SNAKE_CASE)
- properties: optional properties describing the relationship
Make relationships logical and realistic for ${options.domain}. Avoid creating too many relationships from/to the same entity.
Return a JSON array of relationships.
Example format:
\`\`\`json
[
{
"source": "product_laptop_001",
"target": "category_electronics",
"type": "BELONGS_TO",
"properties": {
"primary": true,
"added_date": "2024-01-15"
}
}
]
\`\`\``;
return this.client.generateStructured(systemPrompt, userPrompt, {
temperature: 0.7,
maxTokens: Math.min(8000, targetRelationships * 80)
});
}
/**
* Generate schema-aware entities and relationships
*/
async generateWithSchema(schema, count) {
const systemPrompt = 'You are an expert at generating synthetic data that conforms to strict schemas.';
const userPrompt = `Generate ${count} instances of entities and relationships following this exact schema:
${JSON.stringify(schema, null, 2)}
Return a JSON object with:
- nodes: array of entities matching the entity types in the schema
- edges: array of relationships matching the relationship types in the schema
Ensure all properties match their specified types and all relationships connect valid entity types.
Example format:
\`\`\`json
{
"nodes": [...],
"edges": [...]
}
\`\`\``;
return this.client.generateStructured(systemPrompt, userPrompt, {
temperature: 0.7,
maxTokens: Math.min(8000, count * 200)
});
}
/**
* Analyze entity-relationship patterns
*/
async analyzeERPatterns(data) {
const entityTypeDistribution = {};
const relationshipTypeDistribution = {};
const entityDegrees = new Map();
// Count entity types
for (const node of data.nodes) {
for (const label of node.labels) {
entityTypeDistribution[label] = (entityTypeDistribution[label] || 0) + 1;
}
}
// Count relationship types and degrees
for (const edge of data.edges) {
relationshipTypeDistribution[edge.type] = (relationshipTypeDistribution[edge.type] || 0) + 1;
entityDegrees.set(edge.source, (entityDegrees.get(edge.source) || 0) + 1);
entityDegrees.set(edge.target, (entityDegrees.get(edge.target) || 0) + 1);
}
const degrees = Array.from(entityDegrees.values());
const avgRelationshipsPerEntity = degrees.length > 0
? degrees.reduce((a, b) => a + b, 0) / degrees.length
: 0;
const maxPossibleEdges = data.nodes.length * (data.nodes.length - 1);
const densityScore = maxPossibleEdges > 0
? data.edges.length / maxPossibleEdges
: 0;
return {
entityTypeDistribution,
relationshipTypeDistribution,
avgRelationshipsPerEntity,
densityScore
};
}
}
exports.EntityRelationshipGenerator = EntityRelationshipGenerator;
/**
* Create an entity relationship generator
*/
function createEntityRelationshipGenerator(client) {
return new EntityRelationshipGenerator(client);
}
//# sourceMappingURL=entity-relationships.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"entity-relationships.js","sourceRoot":"","sources":["entity-relationships.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,286 @@
/**
* Entity relationship generator for domain-specific graphs
*/
import { OpenRouterClient } from '../openrouter-client.js';
import {
EntityRelationshipOptions,
GraphData,
GraphNode,
GraphEdge,
GraphGenerationResult
} from '../types.js';
interface EntityData {
id: string;
labels: string[];
properties: Record<string, unknown>;
}
interface RelationshipData {
source: string;
target: string;
type: string;
properties?: Record<string, unknown>;
}
export class EntityRelationshipGenerator {
constructor(private client: OpenRouterClient) {}
/**
* Generate entity-relationship graph
*/
async generate(options: EntityRelationshipOptions): Promise<GraphGenerationResult<GraphData>> {
const startTime = Date.now();
// Generate entities
const entities = await this.generateEntities(options);
// Generate relationships
const relationships = await this.generateRelationships(entities, options);
// Convert to graph structure
const nodes: GraphNode[] = entities.map(entity => ({
id: entity.id,
labels: entity.labels || ['Entity'],
properties: entity.properties
}));
const edges: GraphEdge[] = relationships.map((rel, idx) => ({
id: `rel_${idx}`,
type: rel.type,
source: rel.source,
target: rel.target,
properties: rel.properties || {}
}));
const data: GraphData = {
nodes,
edges,
metadata: {
domain: options.domain,
generated_at: new Date(),
total_nodes: nodes.length,
total_edges: edges.length
}
};
return {
data,
metadata: {
generated_at: new Date(),
model: this.client.getConfig().model || 'moonshot/kimi-k2-instruct',
duration: Date.now() - startTime
}
};
}
/**
* Generate domain-specific entities
*/
private async generateEntities(options: EntityRelationshipOptions): Promise<EntityData[]> {
const systemPrompt = `You are an expert in ${options.domain} domain modeling. Generate realistic entities following best practices for ${options.domain} data models.`;
const schemaInfo = options.entitySchema
? `\n\nEntity schema to follow:\n${JSON.stringify(options.entitySchema, null, 2)}`
: '';
const userPrompt = `Generate ${options.entityCount} diverse entities for a ${options.domain} domain model.${schemaInfo}
Each entity should have:
- id: unique identifier (use snake_case)
- labels: array of entity type labels (e.g., ["Product", "Digital"])
- properties: object with entity properties (at least 3-5 meaningful properties)
Make entities realistic and relevant to ${options.domain}. Include variety in types and attributes.
Return a JSON array of entities.
Example format:
\`\`\`json
[
{
"id": "product_laptop_001",
"labels": ["Product", "Electronics", "Computer"],
"properties": {
"name": "UltraBook Pro 15",
"category": "Laptops",
"price": 1299.99,
"brand": "TechCorp",
"release_date": "2024-01-15",
"stock": 45,
"rating": 4.7
}
}
]
\`\`\``;
return this.client.generateStructured<EntityData[]>(systemPrompt, userPrompt, {
temperature: 0.8,
maxTokens: Math.min(8000, options.entityCount * 150)
});
}
/**
* Generate relationships between entities
*/
private async generateRelationships(
entities: EntityData[],
options: EntityRelationshipOptions
): Promise<RelationshipData[]> {
// Calculate target relationship count based on density
const maxPossibleRelationships = entities.length * (entities.length - 1);
const targetRelationships = Math.floor(maxPossibleRelationships * options.relationshipDensity);
const relationshipTypes = options.relationshipTypes || [
'RELATES_TO',
'PART_OF',
'DEPENDS_ON',
'SIMILAR_TO',
'CONTAINS'
];
const systemPrompt = `You are an expert in ${options.domain} domain modeling. Create meaningful, realistic relationships between entities.`;
const entityList = entities.slice(0, 100).map(e =>
`- ${e.id} (${e.labels.join(', ')}): ${JSON.stringify(e.properties).substring(0, 100)}`
).join('\n');
const userPrompt = `Given these entities from a ${options.domain} domain:
${entityList}
Generate ${targetRelationships} meaningful relationships between them.
Relationship types to use: ${relationshipTypes.join(', ')}
Each relationship should have:
- source: source entity id
- target: target entity id
- type: relationship type (use UPPER_SNAKE_CASE)
- properties: optional properties describing the relationship
Make relationships logical and realistic for ${options.domain}. Avoid creating too many relationships from/to the same entity.
Return a JSON array of relationships.
Example format:
\`\`\`json
[
{
"source": "product_laptop_001",
"target": "category_electronics",
"type": "BELONGS_TO",
"properties": {
"primary": true,
"added_date": "2024-01-15"
}
}
]
\`\`\``;
return this.client.generateStructured<RelationshipData[]>(systemPrompt, userPrompt, {
temperature: 0.7,
maxTokens: Math.min(8000, targetRelationships * 80)
});
}
/**
* Generate schema-aware entities and relationships
*/
async generateWithSchema(
schema: {
entities: Record<string, {
properties: Record<string, string>;
relationships?: string[];
}>;
relationships: Record<string, {
from: string;
to: string;
properties?: Record<string, string>;
}>;
},
count: number
): Promise<GraphData> {
const systemPrompt = 'You are an expert at generating synthetic data that conforms to strict schemas.';
const userPrompt = `Generate ${count} instances of entities and relationships following this exact schema:
${JSON.stringify(schema, null, 2)}
Return a JSON object with:
- nodes: array of entities matching the entity types in the schema
- edges: array of relationships matching the relationship types in the schema
Ensure all properties match their specified types and all relationships connect valid entity types.
Example format:
\`\`\`json
{
"nodes": [...],
"edges": [...]
}
\`\`\``;
return this.client.generateStructured<GraphData>(
systemPrompt,
userPrompt,
{
temperature: 0.7,
maxTokens: Math.min(8000, count * 200)
}
);
}
/**
* Analyze entity-relationship patterns
*/
async analyzeERPatterns(data: GraphData): Promise<{
entityTypeDistribution: Record<string, number>;
relationshipTypeDistribution: Record<string, number>;
avgRelationshipsPerEntity: number;
densityScore: number;
}> {
const entityTypeDistribution: Record<string, number> = {};
const relationshipTypeDistribution: Record<string, number> = {};
const entityDegrees = new Map<string, number>();
// Count entity types
for (const node of data.nodes) {
for (const label of node.labels) {
entityTypeDistribution[label] = (entityTypeDistribution[label] || 0) + 1;
}
}
// Count relationship types and degrees
for (const edge of data.edges) {
relationshipTypeDistribution[edge.type] = (relationshipTypeDistribution[edge.type] || 0) + 1;
entityDegrees.set(edge.source, (entityDegrees.get(edge.source) || 0) + 1);
entityDegrees.set(edge.target, (entityDegrees.get(edge.target) || 0) + 1);
}
const degrees = Array.from(entityDegrees.values());
const avgRelationshipsPerEntity = degrees.length > 0
? degrees.reduce((a, b) => a + b, 0) / degrees.length
: 0;
const maxPossibleEdges = data.nodes.length * (data.nodes.length - 1);
const densityScore = maxPossibleEdges > 0
? data.edges.length / maxPossibleEdges
: 0;
return {
entityTypeDistribution,
relationshipTypeDistribution,
avgRelationshipsPerEntity,
densityScore
};
}
}
/**
* Create an entity relationship generator
*/
export function createEntityRelationshipGenerator(client: OpenRouterClient): EntityRelationshipGenerator {
return new EntityRelationshipGenerator(client);
}

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC"}

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AAAA;;GAEG;;;;;;;;;;;;;;;;AAEH,uDAAqC;AACrC,sDAAoC;AACpC,uDAAqC;AACrC,4DAA0C"}

View File

@@ -0,0 +1,8 @@
/**
* Graph data generators exports
*/
export * from './knowledge-graph.js';
export * from './social-network.js';
export * from './temporal-events.js';
export * from './entity-relationships.js';

View File

@@ -0,0 +1,30 @@
/**
* Knowledge graph generator using OpenRouter/Kimi K2
*/
import { OpenRouterClient } from '../openrouter-client.js';
import { KnowledgeGraphOptions, GraphData, GraphGenerationResult, KnowledgeTriple } from '../types.js';
export declare class KnowledgeGraphGenerator {
private client;
constructor(client: OpenRouterClient);
/**
* Generate a knowledge graph
*/
generate(options: KnowledgeGraphOptions): Promise<GraphGenerationResult<GraphData>>;
/**
* Generate entities for the knowledge graph
*/
private generateEntities;
/**
* Generate relationships between entities
*/
private generateRelationships;
/**
* Generate knowledge triples (subject-predicate-object)
*/
generateTriples(domain: string, count: number): Promise<KnowledgeTriple[]>;
}
/**
* Create a knowledge graph generator
*/
export declare function createKnowledgeGraphGenerator(client: OpenRouterClient): KnowledgeGraphGenerator;
//# sourceMappingURL=knowledge-graph.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"knowledge-graph.d.ts","sourceRoot":"","sources":["knowledge-graph.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EACL,qBAAqB,EACrB,SAAS,EAGT,qBAAqB,EACrB,eAAe,EAChB,MAAM,aAAa,CAAC;AAoCrB,qBAAa,uBAAuB;IACtB,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,gBAAgB;IAE5C;;OAEG;IACG,QAAQ,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;IAgDzF;;OAEG;YACW,gBAAgB;IA8C9B;;OAEG;YACW,qBAAqB;IAiDnC;;OAEG;IACG,eAAe,CACnB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,eAAe,EAAE,CAAC;CA+B9B;AAED;;GAEG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,gBAAgB,GAAG,uBAAuB,CAE/F"}

View File

@@ -0,0 +1,192 @@
"use strict";
/**
* Knowledge graph generator using OpenRouter/Kimi K2
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.KnowledgeGraphGenerator = void 0;
exports.createKnowledgeGraphGenerator = createKnowledgeGraphGenerator;
const DEFAULT_ENTITY_TYPES = [
'Person',
'Organization',
'Location',
'Event',
'Concept',
'Technology',
'Product'
];
const DEFAULT_RELATIONSHIP_TYPES = [
'WORKS_FOR',
'LOCATED_IN',
'CREATED_BY',
'PART_OF',
'RELATED_TO',
'INFLUENCES',
'DEPENDS_ON'
];
class KnowledgeGraphGenerator {
constructor(client) {
this.client = client;
}
/**
* Generate a knowledge graph
*/
async generate(options) {
const startTime = Date.now();
// Generate entities first
const entities = await this.generateEntities(options);
// Generate relationships between entities
const relationships = await this.generateRelationships(entities, options);
// Convert to graph structure
const nodes = entities.map((entity, idx) => ({
id: entity.id || `entity_${idx}`,
labels: [entity.type || 'Entity'],
properties: {
name: entity.name,
...entity.properties
}
}));
const edges = relationships.map((rel, idx) => ({
id: `rel_${idx}`,
type: rel.type,
source: rel.source,
target: rel.target,
properties: rel.properties || {}
}));
const data = {
nodes,
edges,
metadata: {
domain: options.domain,
generated_at: new Date(),
total_nodes: nodes.length,
total_edges: edges.length
}
};
return {
data,
metadata: {
generated_at: new Date(),
model: this.client.getConfig().model || 'moonshot/kimi-k2-instruct',
duration: Date.now() - startTime
}
};
}
/**
* Generate entities for the knowledge graph
*/
async generateEntities(options) {
const entityTypes = options.entityTypes || DEFAULT_ENTITY_TYPES;
const systemPrompt = `You are an expert knowledge graph architect. Generate realistic entities for a knowledge graph about ${options.domain}.`;
const userPrompt = `Generate ${options.entities} diverse entities for a knowledge graph about ${options.domain}.
Entity types to include: ${entityTypes.join(', ')}
For each entity, provide:
- id: unique identifier (use snake_case)
- name: entity name
- type: one of the specified entity types
- properties: relevant properties (at least 2-3 properties per entity)
Return a JSON array of entities. Make them realistic and relevant to ${options.domain}.
Example format:
\`\`\`json
[
{
"id": "john_doe",
"name": "John Doe",
"type": "Person",
"properties": {
"role": "Software Engineer",
"expertise": "AI/ML",
"years_experience": 5
}
}
]
\`\`\``;
const entities = await this.client.generateStructured(systemPrompt, userPrompt, {
temperature: 0.8,
maxTokens: Math.min(8000, options.entities * 100)
});
return entities;
}
/**
* Generate relationships between entities
*/
async generateRelationships(entities, options) {
const relationshipTypes = options.relationshipTypes || DEFAULT_RELATIONSHIP_TYPES;
const systemPrompt = `You are an expert at creating meaningful relationships in knowledge graphs. Create realistic relationships that make sense for ${options.domain}.`;
const entityList = entities.slice(0, 50).map(e => `- ${e.id}: ${e.name} (${e.type})`).join('\n');
const userPrompt = `Given these entities from a ${options.domain} knowledge graph:
${entityList}
Generate ${options.relationships} meaningful relationships between them.
Relationship types to use: ${relationshipTypes.join(', ')}
For each relationship, provide:
- source: source entity id
- target: target entity id
- type: relationship type (use one of the specified types)
- properties: optional properties describing the relationship
Return a JSON array of relationships. Make them logical and realistic.
Example format:
\`\`\`json
[
{
"source": "john_doe",
"target": "acme_corp",
"type": "WORKS_FOR",
"properties": {
"since": "2020",
"position": "Senior Engineer"
}
}
]
\`\`\``;
const relationships = await this.client.generateStructured(systemPrompt, userPrompt, {
temperature: 0.7,
maxTokens: Math.min(8000, options.relationships * 80)
});
return relationships;
}
/**
* Generate knowledge triples (subject-predicate-object)
*/
async generateTriples(domain, count) {
const systemPrompt = `You are an expert at extracting knowledge triples from domains. Generate meaningful subject-predicate-object triples about ${domain}.`;
const userPrompt = `Generate ${count} knowledge triples about ${domain}.
Each triple should have:
- subject: the entity or concept
- predicate: the relationship or property
- object: the related entity, value, or concept
- confidence: confidence score (0-1)
Return a JSON array of triples.
Example format:
\`\`\`json
[
{
"subject": "Einstein",
"predicate": "developed",
"object": "Theory of Relativity",
"confidence": 1.0
}
]
\`\`\``;
return this.client.generateStructured(systemPrompt, userPrompt, { temperature: 0.7, maxTokens: count * 100 });
}
}
exports.KnowledgeGraphGenerator = KnowledgeGraphGenerator;
/**
* Create a knowledge graph generator
*/
function createKnowledgeGraphGenerator(client) {
return new KnowledgeGraphGenerator(client);
}
//# sourceMappingURL=knowledge-graph.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"knowledge-graph.js","sourceRoot":"","sources":["knowledge-graph.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,248 @@
/**
* Knowledge graph generator using OpenRouter/Kimi K2
*/
import { OpenRouterClient } from '../openrouter-client.js';
import {
KnowledgeGraphOptions,
GraphData,
GraphNode,
GraphEdge,
GraphGenerationResult,
KnowledgeTriple
} from '../types.js';
interface EntityData {
id: string;
name: string;
type: string;
properties: Record<string, unknown>;
}
interface RelationshipData {
source: string;
target: string;
type: string;
properties?: Record<string, unknown>;
}
const DEFAULT_ENTITY_TYPES = [
'Person',
'Organization',
'Location',
'Event',
'Concept',
'Technology',
'Product'
];
const DEFAULT_RELATIONSHIP_TYPES = [
'WORKS_FOR',
'LOCATED_IN',
'CREATED_BY',
'PART_OF',
'RELATED_TO',
'INFLUENCES',
'DEPENDS_ON'
];
export class KnowledgeGraphGenerator {
constructor(private client: OpenRouterClient) {}
/**
* Generate a knowledge graph
*/
async generate(options: KnowledgeGraphOptions): Promise<GraphGenerationResult<GraphData>> {
const startTime = Date.now();
// Generate entities first
const entities = await this.generateEntities(options);
// Generate relationships between entities
const relationships = await this.generateRelationships(entities, options);
// Convert to graph structure
const nodes: GraphNode[] = entities.map((entity, idx) => ({
id: entity.id || `entity_${idx}`,
labels: [entity.type || 'Entity'],
properties: {
name: entity.name,
...entity.properties
}
}));
const edges: GraphEdge[] = relationships.map((rel, idx) => ({
id: `rel_${idx}`,
type: rel.type,
source: rel.source,
target: rel.target,
properties: rel.properties || {}
}));
const data: GraphData = {
nodes,
edges,
metadata: {
domain: options.domain,
generated_at: new Date(),
total_nodes: nodes.length,
total_edges: edges.length
}
};
return {
data,
metadata: {
generated_at: new Date(),
model: this.client.getConfig().model || 'moonshot/kimi-k2-instruct',
duration: Date.now() - startTime
}
};
}
/**
* Generate entities for the knowledge graph
*/
private async generateEntities(options: KnowledgeGraphOptions): Promise<Array<{
id: string;
name: string;
type: string;
properties: Record<string, unknown>;
}>> {
const entityTypes = options.entityTypes || DEFAULT_ENTITY_TYPES;
const systemPrompt = `You are an expert knowledge graph architect. Generate realistic entities for a knowledge graph about ${options.domain}.`;
const userPrompt = `Generate ${options.entities} diverse entities for a knowledge graph about ${options.domain}.
Entity types to include: ${entityTypes.join(', ')}
For each entity, provide:
- id: unique identifier (use snake_case)
- name: entity name
- type: one of the specified entity types
- properties: relevant properties (at least 2-3 properties per entity)
Return a JSON array of entities. Make them realistic and relevant to ${options.domain}.
Example format:
\`\`\`json
[
{
"id": "john_doe",
"name": "John Doe",
"type": "Person",
"properties": {
"role": "Software Engineer",
"expertise": "AI/ML",
"years_experience": 5
}
}
]
\`\`\``;
const entities = await this.client.generateStructured<EntityData[]>(systemPrompt, userPrompt, {
temperature: 0.8,
maxTokens: Math.min(8000, options.entities * 100)
});
return entities;
}
/**
* Generate relationships between entities
*/
private async generateRelationships(
entities: EntityData[],
options: KnowledgeGraphOptions
): Promise<RelationshipData[]> {
const relationshipTypes = options.relationshipTypes || DEFAULT_RELATIONSHIP_TYPES;
const systemPrompt = `You are an expert at creating meaningful relationships in knowledge graphs. Create realistic relationships that make sense for ${options.domain}.`;
const entityList = entities.slice(0, 50).map(e => `- ${e.id}: ${e.name} (${e.type})`).join('\n');
const userPrompt = `Given these entities from a ${options.domain} knowledge graph:
${entityList}
Generate ${options.relationships} meaningful relationships between them.
Relationship types to use: ${relationshipTypes.join(', ')}
For each relationship, provide:
- source: source entity id
- target: target entity id
- type: relationship type (use one of the specified types)
- properties: optional properties describing the relationship
Return a JSON array of relationships. Make them logical and realistic.
Example format:
\`\`\`json
[
{
"source": "john_doe",
"target": "acme_corp",
"type": "WORKS_FOR",
"properties": {
"since": "2020",
"position": "Senior Engineer"
}
}
]
\`\`\``;
const relationships = await this.client.generateStructured<RelationshipData[]>(systemPrompt, userPrompt, {
temperature: 0.7,
maxTokens: Math.min(8000, options.relationships * 80)
});
return relationships;
}
/**
* Generate knowledge triples (subject-predicate-object)
*/
async generateTriples(
domain: string,
count: number
): Promise<KnowledgeTriple[]> {
const systemPrompt = `You are an expert at extracting knowledge triples from domains. Generate meaningful subject-predicate-object triples about ${domain}.`;
const userPrompt = `Generate ${count} knowledge triples about ${domain}.
Each triple should have:
- subject: the entity or concept
- predicate: the relationship or property
- object: the related entity, value, or concept
- confidence: confidence score (0-1)
Return a JSON array of triples.
Example format:
\`\`\`json
[
{
"subject": "Einstein",
"predicate": "developed",
"object": "Theory of Relativity",
"confidence": 1.0
}
]
\`\`\``;
return this.client.generateStructured<KnowledgeTriple[]>(
systemPrompt,
userPrompt,
{ temperature: 0.7, maxTokens: count * 100 }
);
}
}
/**
* Create a knowledge graph generator
*/
export function createKnowledgeGraphGenerator(client: OpenRouterClient): KnowledgeGraphGenerator {
return new KnowledgeGraphGenerator(client);
}

View File

@@ -0,0 +1,39 @@
/**
* Social network generator using OpenRouter/Kimi K2
*/
import { OpenRouterClient } from '../openrouter-client.js';
import { SocialNetworkOptions, GraphData, GraphGenerationResult } from '../types.js';
export declare class SocialNetworkGenerator {
private client;
constructor(client: OpenRouterClient);
/**
* Generate a social network graph
*/
generate(options: SocialNetworkOptions): Promise<GraphGenerationResult<GraphData>>;
/**
* Generate realistic social network users
*/
private generateUsers;
/**
* Generate connections between users
*/
private generateConnections;
/**
* Get guidance for network type
*/
private getNetworkTypeGuidance;
/**
* Analyze network properties
*/
analyzeNetwork(data: GraphData): Promise<{
avgDegree: number;
maxDegree: number;
communities?: number;
clustering?: number;
}>;
}
/**
* Create a social network generator
*/
export declare function createSocialNetworkGenerator(client: OpenRouterClient): SocialNetworkGenerator;
//# sourceMappingURL=social-network.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"social-network.d.ts","sourceRoot":"","sources":["social-network.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EACL,oBAAoB,EAEpB,SAAS,EAGT,qBAAqB,EACtB,MAAM,aAAa,CAAC;AASrB,qBAAa,sBAAsB;IACrB,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,gBAAgB;IAE5C;;OAEG;IACG,QAAQ,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;IAiDxF;;OAEG;YACW,aAAa;IA6C3B;;OAEG;YACW,mBAAmB;IA+CjC;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAa9B;;OAEG;IACG,cAAc,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC;QAC7C,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;CAiBH;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,gBAAgB,GAAG,sBAAsB,CAE7F"}

View File

@@ -0,0 +1,180 @@
"use strict";
/**
* Social network generator using OpenRouter/Kimi K2
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.SocialNetworkGenerator = void 0;
exports.createSocialNetworkGenerator = createSocialNetworkGenerator;
class SocialNetworkGenerator {
constructor(client) {
this.client = client;
}
/**
* Generate a social network graph
*/
async generate(options) {
const startTime = Date.now();
// Generate users
const users = await this.generateUsers(options);
// Generate connections based on network type
const connections = await this.generateConnections(users, options);
// Convert to graph structure
const nodes = users.map(user => ({
id: user.id,
labels: ['User'],
properties: {
username: user.username,
...user.profile,
...(user.metadata || {})
}
}));
const edges = connections.map((conn, idx) => ({
id: `connection_${idx}`,
type: conn.type || 'FOLLOWS',
source: conn.source,
target: conn.target,
properties: conn.properties || {}
}));
const data = {
nodes,
edges,
metadata: {
domain: 'social-network',
generated_at: new Date(),
total_nodes: nodes.length,
total_edges: edges.length
}
};
return {
data,
metadata: {
generated_at: new Date(),
model: this.client.getConfig().model || 'moonshot/kimi-k2-instruct',
duration: Date.now() - startTime
}
};
}
/**
* Generate realistic social network users
*/
async generateUsers(options) {
const systemPrompt = 'You are an expert at creating realistic social network user profiles. Generate diverse, believable users.';
const userPrompt = `Generate ${options.users} realistic social network user profiles.
Each user should have:
- id: unique user ID (format: user_XXXXX)
- username: unique username
- profile: object with name, bio, joined (ISO date), followers (number), following (number)
${options.includeMetadata ? '- metadata: additional information like interests, location, verified status' : ''}
Make the profiles diverse and realistic. Return a JSON array.
Example format:
\`\`\`json
[
{
"id": "user_12345",
"username": "tech_enthusiast_42",
"profile": {
"name": "Alex Johnson",
"bio": "Software developer passionate about AI and open source",
"joined": "2020-03-15T00:00:00Z",
"followers": 1250,
"following": 430
}${options.includeMetadata ? `,
"metadata": {
"interests": ["technology", "AI", "coding"],
"location": "San Francisco, CA",
"verified": false
}` : ''}
}
]
\`\`\``;
return this.client.generateStructured(systemPrompt, userPrompt, {
temperature: 0.9,
maxTokens: Math.min(8000, options.users * 150)
});
}
/**
* Generate connections between users
*/
async generateConnections(users, options) {
const totalConnections = Math.floor(options.users * options.avgConnections / 2);
const systemPrompt = `You are an expert at modeling social network connections. Create realistic ${options.networkType || 'random'} network patterns.`;
const userList = users.slice(0, 100).map(u => `- ${u.id}: @${u.username}`).join('\n');
const userPrompt = `Given these social network users:
${userList}
Generate ${totalConnections} connections creating a ${options.networkType || 'random'} network structure.
${this.getNetworkTypeGuidance(options.networkType)}
Each connection should have:
- source: user id who initiates the connection
- target: user id being connected to
- type: connection type (FOLLOWS, FRIEND, BLOCKS, MUTES)
- properties: optional properties like since (ISO date), strength (0-1)
Return a JSON array of connections.
Example format:
\`\`\`json
[
{
"source": "user_12345",
"target": "user_67890",
"type": "FOLLOWS",
"properties": {
"since": "2021-06-15T00:00:00Z",
"strength": 0.8
}
}
]
\`\`\``;
return this.client.generateStructured(systemPrompt, userPrompt, {
temperature: 0.7,
maxTokens: Math.min(8000, totalConnections * 80)
});
}
/**
* Get guidance for network type
*/
getNetworkTypeGuidance(networkType) {
switch (networkType) {
case 'small-world':
return 'Create clusters of highly connected users with occasional bridges between clusters (small-world property).';
case 'scale-free':
return 'Create a power-law distribution where a few users have many connections (influencers) and most have few connections.';
case 'clustered':
return 'Create distinct communities/clusters with high internal connectivity and sparse connections between clusters.';
default:
return 'Create random connections with varying connection strengths.';
}
}
/**
* Analyze network properties
*/
async analyzeNetwork(data) {
const degrees = new Map();
for (const edge of data.edges) {
degrees.set(edge.source, (degrees.get(edge.source) || 0) + 1);
degrees.set(edge.target, (degrees.get(edge.target) || 0) + 1);
}
const degreeValues = Array.from(degrees.values());
const avgDegree = degreeValues.reduce((a, b) => a + b, 0) / degreeValues.length;
const maxDegree = Math.max(...degreeValues);
return {
avgDegree,
maxDegree
};
}
}
exports.SocialNetworkGenerator = SocialNetworkGenerator;
/**
* Create a social network generator
*/
function createSocialNetworkGenerator(client) {
return new SocialNetworkGenerator(client);
}
//# sourceMappingURL=social-network.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"social-network.js","sourceRoot":"","sources":["social-network.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,223 @@
/**
* Social network generator using OpenRouter/Kimi K2
*/
import { OpenRouterClient } from '../openrouter-client.js';
import {
SocialNetworkOptions,
SocialNode,
GraphData,
GraphNode,
GraphEdge,
GraphGenerationResult
} from '../types.js';
interface ConnectionData {
source: string;
target: string;
type: string;
properties?: Record<string, unknown>;
}
export class SocialNetworkGenerator {
constructor(private client: OpenRouterClient) {}
/**
* Generate a social network graph
*/
async generate(options: SocialNetworkOptions): Promise<GraphGenerationResult<GraphData>> {
const startTime = Date.now();
// Generate users
const users = await this.generateUsers(options);
// Generate connections based on network type
const connections = await this.generateConnections(users, options);
// Convert to graph structure
const nodes: GraphNode[] = users.map(user => ({
id: user.id,
labels: ['User'],
properties: {
username: user.username,
...user.profile,
...(user.metadata || {})
}
}));
const edges: GraphEdge[] = connections.map((conn, idx) => ({
id: `connection_${idx}`,
type: conn.type || 'FOLLOWS',
source: conn.source,
target: conn.target,
properties: conn.properties || {}
}));
const data: GraphData = {
nodes,
edges,
metadata: {
domain: 'social-network',
generated_at: new Date(),
total_nodes: nodes.length,
total_edges: edges.length
}
};
return {
data,
metadata: {
generated_at: new Date(),
model: this.client.getConfig().model || 'moonshot/kimi-k2-instruct',
duration: Date.now() - startTime
}
};
}
/**
* Generate realistic social network users
*/
private async generateUsers(options: SocialNetworkOptions): Promise<SocialNode[]> {
const systemPrompt = 'You are an expert at creating realistic social network user profiles. Generate diverse, believable users.';
const userPrompt = `Generate ${options.users} realistic social network user profiles.
Each user should have:
- id: unique user ID (format: user_XXXXX)
- username: unique username
- profile: object with name, bio, joined (ISO date), followers (number), following (number)
${options.includeMetadata ? '- metadata: additional information like interests, location, verified status' : ''}
Make the profiles diverse and realistic. Return a JSON array.
Example format:
\`\`\`json
[
{
"id": "user_12345",
"username": "tech_enthusiast_42",
"profile": {
"name": "Alex Johnson",
"bio": "Software developer passionate about AI and open source",
"joined": "2020-03-15T00:00:00Z",
"followers": 1250,
"following": 430
}${options.includeMetadata ? `,
"metadata": {
"interests": ["technology", "AI", "coding"],
"location": "San Francisco, CA",
"verified": false
}` : ''}
}
]
\`\`\``;
return this.client.generateStructured<SocialNode[]>(
systemPrompt,
userPrompt,
{
temperature: 0.9,
maxTokens: Math.min(8000, options.users * 150)
}
);
}
/**
* Generate connections between users
*/
private async generateConnections(
users: SocialNode[],
options: SocialNetworkOptions
): Promise<ConnectionData[]> {
const totalConnections = Math.floor(options.users * options.avgConnections / 2);
const systemPrompt = `You are an expert at modeling social network connections. Create realistic ${options.networkType || 'random'} network patterns.`;
const userList = users.slice(0, 100).map(u => `- ${u.id}: @${u.username}`).join('\n');
const userPrompt = `Given these social network users:
${userList}
Generate ${totalConnections} connections creating a ${options.networkType || 'random'} network structure.
${this.getNetworkTypeGuidance(options.networkType)}
Each connection should have:
- source: user id who initiates the connection
- target: user id being connected to
- type: connection type (FOLLOWS, FRIEND, BLOCKS, MUTES)
- properties: optional properties like since (ISO date), strength (0-1)
Return a JSON array of connections.
Example format:
\`\`\`json
[
{
"source": "user_12345",
"target": "user_67890",
"type": "FOLLOWS",
"properties": {
"since": "2021-06-15T00:00:00Z",
"strength": 0.8
}
}
]
\`\`\``;
return this.client.generateStructured<ConnectionData[]>(systemPrompt, userPrompt, {
temperature: 0.7,
maxTokens: Math.min(8000, totalConnections * 80)
});
}
/**
* Get guidance for network type
*/
private getNetworkTypeGuidance(networkType?: string): string {
switch (networkType) {
case 'small-world':
return 'Create clusters of highly connected users with occasional bridges between clusters (small-world property).';
case 'scale-free':
return 'Create a power-law distribution where a few users have many connections (influencers) and most have few connections.';
case 'clustered':
return 'Create distinct communities/clusters with high internal connectivity and sparse connections between clusters.';
default:
return 'Create random connections with varying connection strengths.';
}
}
/**
* Analyze network properties
*/
async analyzeNetwork(data: GraphData): Promise<{
avgDegree: number;
maxDegree: number;
communities?: number;
clustering?: number;
}> {
const degrees = new Map<string, number>();
for (const edge of data.edges) {
degrees.set(edge.source, (degrees.get(edge.source) || 0) + 1);
degrees.set(edge.target, (degrees.get(edge.target) || 0) + 1);
}
const degreeValues = Array.from(degrees.values());
const avgDegree = degreeValues.reduce((a, b) => a + b, 0) / degreeValues.length;
const maxDegree = Math.max(...degreeValues);
return {
avgDegree,
maxDegree
};
}
}
/**
* Create a social network generator
*/
export function createSocialNetworkGenerator(client: OpenRouterClient): SocialNetworkGenerator {
return new SocialNetworkGenerator(client);
}

View File

@@ -0,0 +1,34 @@
/**
* Temporal events generator for time-series graph data
*/
import { OpenRouterClient } from '../openrouter-client.js';
import { TemporalEventOptions, TemporalEvent, GraphData, GraphGenerationResult } from '../types.js';
export declare class TemporalEventsGenerator {
private client;
constructor(client: OpenRouterClient);
/**
* Generate temporal event graph data
*/
generate(options: TemporalEventOptions): Promise<GraphGenerationResult<GraphData>>;
/**
* Generate temporal events
*/
private generateEvents;
/**
* Generate entities from events
*/
private generateEntities;
/**
* Analyze temporal patterns
*/
analyzeTemporalPatterns(events: TemporalEvent[]): Promise<{
eventsPerHour: Record<string, number>;
eventTypeDistribution: Record<string, number>;
avgTimeBetweenEvents: number;
}>;
}
/**
* Create a temporal events generator
*/
export declare function createTemporalEventsGenerator(client: OpenRouterClient): TemporalEventsGenerator;
//# sourceMappingURL=temporal-events.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"temporal-events.d.ts","sourceRoot":"","sources":["temporal-events.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,SAAS,EAGT,qBAAqB,EACtB,MAAM,aAAa,CAAC;AAQrB,qBAAa,uBAAuB;IACtB,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,gBAAgB;IAE5C;;OAEG;IACG,QAAQ,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;IAiGxF;;OAEG;YACW,cAAc;IA+D5B;;OAEG;YACW,gBAAgB;IAiD9B;;OAEG;IACG,uBAAuB,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC;QAC9D,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACtC,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC9C,oBAAoB,EAAE,MAAM,CAAC;KAC9B,CAAC;CAgCH;AAED;;GAEG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,gBAAgB,GAAG,uBAAuB,CAE/F"}

View File

@@ -0,0 +1,232 @@
"use strict";
/**
* Temporal events generator for time-series graph data
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.TemporalEventsGenerator = void 0;
exports.createTemporalEventsGenerator = createTemporalEventsGenerator;
class TemporalEventsGenerator {
constructor(client) {
this.client = client;
}
/**
* Generate temporal event graph data
*/
async generate(options) {
const startTime = Date.now();
// Generate events
const events = await this.generateEvents(options);
// Generate entities involved in events
const entities = await this.generateEntities(events, options);
// Convert to graph structure
const eventNodes = events.map(event => ({
id: event.id,
labels: ['Event', event.type],
properties: {
type: event.type,
timestamp: event.timestamp.toISOString(),
...event.properties
}
}));
const entityNodes = entities.map(entity => ({
id: entity.id,
labels: ['Entity', entity.type],
properties: entity.properties
}));
const edges = [];
let edgeId = 0;
// Create edges between events and entities
for (const event of events) {
for (const entityId of event.entities) {
edges.push({
id: `edge_${edgeId++}`,
type: 'INVOLVES',
source: event.id,
target: entityId,
properties: {
timestamp: event.timestamp.toISOString()
}
});
}
// Create edges for relationships
if (event.relationships) {
for (const rel of event.relationships) {
edges.push({
id: `edge_${edgeId++}`,
type: rel.type,
source: event.id,
target: rel.target,
properties: {
timestamp: event.timestamp.toISOString()
}
});
}
}
}
// Create temporal sequences (NEXT relationships)
const sortedEvents = [...events].sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
for (let i = 0; i < sortedEvents.length - 1; i++) {
edges.push({
id: `edge_${edgeId++}`,
type: 'NEXT',
source: sortedEvents[i].id,
target: sortedEvents[i + 1].id,
properties: {
time_diff_ms: sortedEvents[i + 1].timestamp.getTime() - sortedEvents[i].timestamp.getTime()
}
});
}
const data = {
nodes: [...eventNodes, ...entityNodes],
edges,
metadata: {
domain: 'temporal-events',
generated_at: new Date(),
total_nodes: eventNodes.length + entityNodes.length,
total_edges: edges.length
}
};
return {
data,
metadata: {
generated_at: new Date(),
model: this.client.getConfig().model || 'moonshot/kimi-k2-instruct',
duration: Date.now() - startTime
}
};
}
/**
* Generate temporal events
*/
async generateEvents(options) {
const startDate = new Date(options.startDate);
const endDate = new Date(options.endDate);
const daysDiff = Math.ceil((endDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24));
const totalEvents = (options.eventsPerDay || 10) * daysDiff;
const systemPrompt = 'You are an expert at generating realistic temporal event sequences. Create events that follow logical patterns and causality.';
const userPrompt = `Generate ${totalEvents} temporal events between ${startDate.toISOString()} and ${endDate.toISOString()}.
Event types to include: ${options.eventTypes.join(', ')}
Each event should have:
- id: unique event ID (format: event_XXXXX)
- type: one of the specified event types
- timestamp: ISO 8601 timestamp within the date range
- entities: array of entity IDs involved (format: entity_XXXXX)
- properties: relevant properties for the event
- relationships: (optional) array of relationships to other events/entities
Create realistic temporal patterns (e.g., business hours for work events, clustering of related events).
Return a JSON array sorted by timestamp.
Example format:
\`\`\`json
[
{
"id": "event_00001",
"type": "login",
"timestamp": "2024-01-15T09:23:15Z",
"entities": ["entity_user_001"],
"properties": {
"ip_address": "192.168.1.100",
"device": "desktop",
"success": true
},
"relationships": [
{
"type": "TRIGGERED_BY",
"target": "entity_user_001"
}
]
}
]
\`\`\``;
const events = await this.client.generateStructured(systemPrompt, userPrompt, {
temperature: 0.8,
maxTokens: Math.min(8000, totalEvents * 150)
});
// Convert timestamp strings to Date objects
return events.map(event => ({
...event,
timestamp: new Date(event.timestamp)
}));
}
/**
* Generate entities from events
*/
async generateEntities(events, options) {
const uniqueEntityIds = new Set();
events.forEach(event => {
event.entities.forEach(entityId => uniqueEntityIds.add(entityId));
});
const entityIds = Array.from(uniqueEntityIds);
const entityCount = options.entities || entityIds.length;
const systemPrompt = 'You are an expert at creating entity profiles for event-driven systems.';
const sampleIds = entityIds.slice(0, 50).join(', ');
const userPrompt = `Generate ${entityCount} entity profiles for entities involved in temporal events.
Sample entity IDs that must be included: ${sampleIds}
Each entity should have:
- id: the entity ID
- type: entity type (User, System, Device, Service, etc.)
- properties: relevant properties for the entity
Return a JSON array of entities.
Example format:
\`\`\`json
[
{
"id": "entity_user_001",
"type": "User",
"properties": {
"name": "Alice Smith",
"email": "alice@example.com",
"role": "developer",
"created_at": "2023-01-15T00:00:00Z"
}
}
]
\`\`\``;
return this.client.generateStructured(systemPrompt, userPrompt, {
temperature: 0.7,
maxTokens: Math.min(8000, entityCount * 100)
});
}
/**
* Analyze temporal patterns
*/
async analyzeTemporalPatterns(events) {
const eventsPerHour = {};
const eventTypeDistribution = {};
const timeDiffs = [];
const sortedEvents = [...events].sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
for (let i = 0; i < sortedEvents.length; i++) {
const event = sortedEvents[i];
const hour = event.timestamp.toISOString().substring(0, 13);
eventsPerHour[hour] = (eventsPerHour[hour] || 0) + 1;
eventTypeDistribution[event.type] = (eventTypeDistribution[event.type] || 0) + 1;
if (i > 0) {
timeDiffs.push(event.timestamp.getTime() - sortedEvents[i - 1].timestamp.getTime());
}
}
const avgTimeBetweenEvents = timeDiffs.length > 0
? timeDiffs.reduce((a, b) => a + b, 0) / timeDiffs.length
: 0;
return {
eventsPerHour,
eventTypeDistribution,
avgTimeBetweenEvents
};
}
}
exports.TemporalEventsGenerator = TemporalEventsGenerator;
/**
* Create a temporal events generator
*/
function createTemporalEventsGenerator(client) {
return new TemporalEventsGenerator(client);
}
//# sourceMappingURL=temporal-events.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,288 @@
/**
* Temporal events generator for time-series graph data
*/
import { OpenRouterClient } from '../openrouter-client.js';
import {
TemporalEventOptions,
TemporalEvent,
GraphData,
GraphNode,
GraphEdge,
GraphGenerationResult
} from '../types.js';
interface EntityData {
id: string;
type: string;
properties: Record<string, unknown>;
}
export class TemporalEventsGenerator {
constructor(private client: OpenRouterClient) {}
/**
* Generate temporal event graph data
*/
async generate(options: TemporalEventOptions): Promise<GraphGenerationResult<GraphData>> {
const startTime = Date.now();
// Generate events
const events = await this.generateEvents(options);
// Generate entities involved in events
const entities = await this.generateEntities(events, options);
// Convert to graph structure
const eventNodes: GraphNode[] = events.map(event => ({
id: event.id,
labels: ['Event', event.type],
properties: {
type: event.type,
timestamp: event.timestamp.toISOString(),
...event.properties
}
}));
const entityNodes: GraphNode[] = entities.map(entity => ({
id: entity.id,
labels: ['Entity', entity.type],
properties: entity.properties
}));
const edges: GraphEdge[] = [];
let edgeId = 0;
// Create edges between events and entities
for (const event of events) {
for (const entityId of event.entities) {
edges.push({
id: `edge_${edgeId++}`,
type: 'INVOLVES',
source: event.id,
target: entityId,
properties: {
timestamp: event.timestamp.toISOString()
}
});
}
// Create edges for relationships
if (event.relationships) {
for (const rel of event.relationships) {
edges.push({
id: `edge_${edgeId++}`,
type: rel.type,
source: event.id,
target: rel.target,
properties: {
timestamp: event.timestamp.toISOString()
}
});
}
}
}
// Create temporal sequences (NEXT relationships)
const sortedEvents = [...events].sort((a, b) =>
a.timestamp.getTime() - b.timestamp.getTime()
);
for (let i = 0; i < sortedEvents.length - 1; i++) {
edges.push({
id: `edge_${edgeId++}`,
type: 'NEXT',
source: sortedEvents[i].id,
target: sortedEvents[i + 1].id,
properties: {
time_diff_ms: sortedEvents[i + 1].timestamp.getTime() - sortedEvents[i].timestamp.getTime()
}
});
}
const data: GraphData = {
nodes: [...eventNodes, ...entityNodes],
edges,
metadata: {
domain: 'temporal-events',
generated_at: new Date(),
total_nodes: eventNodes.length + entityNodes.length,
total_edges: edges.length
}
};
return {
data,
metadata: {
generated_at: new Date(),
model: this.client.getConfig().model || 'moonshot/kimi-k2-instruct',
duration: Date.now() - startTime
}
};
}
/**
* Generate temporal events
*/
private async generateEvents(options: TemporalEventOptions): Promise<TemporalEvent[]> {
const startDate = new Date(options.startDate);
const endDate = new Date(options.endDate);
const daysDiff = Math.ceil((endDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24));
const totalEvents = (options.eventsPerDay || 10) * daysDiff;
const systemPrompt = 'You are an expert at generating realistic temporal event sequences. Create events that follow logical patterns and causality.';
const userPrompt = `Generate ${totalEvents} temporal events between ${startDate.toISOString()} and ${endDate.toISOString()}.
Event types to include: ${options.eventTypes.join(', ')}
Each event should have:
- id: unique event ID (format: event_XXXXX)
- type: one of the specified event types
- timestamp: ISO 8601 timestamp within the date range
- entities: array of entity IDs involved (format: entity_XXXXX)
- properties: relevant properties for the event
- relationships: (optional) array of relationships to other events/entities
Create realistic temporal patterns (e.g., business hours for work events, clustering of related events).
Return a JSON array sorted by timestamp.
Example format:
\`\`\`json
[
{
"id": "event_00001",
"type": "login",
"timestamp": "2024-01-15T09:23:15Z",
"entities": ["entity_user_001"],
"properties": {
"ip_address": "192.168.1.100",
"device": "desktop",
"success": true
},
"relationships": [
{
"type": "TRIGGERED_BY",
"target": "entity_user_001"
}
]
}
]
\`\`\``;
const events = await this.client.generateStructured<TemporalEvent[]>(
systemPrompt,
userPrompt,
{
temperature: 0.8,
maxTokens: Math.min(8000, totalEvents * 150)
}
);
// Convert timestamp strings to Date objects
return events.map(event => ({
...event,
timestamp: new Date(event.timestamp)
}));
}
/**
* Generate entities from events
*/
private async generateEntities(
events: TemporalEvent[],
options: TemporalEventOptions
): Promise<EntityData[]> {
const uniqueEntityIds = new Set<string>();
events.forEach(event => {
event.entities.forEach(entityId => uniqueEntityIds.add(entityId));
});
const entityIds = Array.from(uniqueEntityIds);
const entityCount = options.entities || entityIds.length;
const systemPrompt = 'You are an expert at creating entity profiles for event-driven systems.';
const sampleIds = entityIds.slice(0, 50).join(', ');
const userPrompt = `Generate ${entityCount} entity profiles for entities involved in temporal events.
Sample entity IDs that must be included: ${sampleIds}
Each entity should have:
- id: the entity ID
- type: entity type (User, System, Device, Service, etc.)
- properties: relevant properties for the entity
Return a JSON array of entities.
Example format:
\`\`\`json
[
{
"id": "entity_user_001",
"type": "User",
"properties": {
"name": "Alice Smith",
"email": "alice@example.com",
"role": "developer",
"created_at": "2023-01-15T00:00:00Z"
}
}
]
\`\`\``;
return this.client.generateStructured<EntityData[]>(systemPrompt, userPrompt, {
temperature: 0.7,
maxTokens: Math.min(8000, entityCount * 100)
});
}
/**
* Analyze temporal patterns
*/
async analyzeTemporalPatterns(events: TemporalEvent[]): Promise<{
eventsPerHour: Record<string, number>;
eventTypeDistribution: Record<string, number>;
avgTimeBetweenEvents: number;
}> {
const eventsPerHour: Record<string, number> = {};
const eventTypeDistribution: Record<string, number> = {};
const timeDiffs: number[] = [];
const sortedEvents = [...events].sort((a, b) =>
a.timestamp.getTime() - b.timestamp.getTime()
);
for (let i = 0; i < sortedEvents.length; i++) {
const event = sortedEvents[i];
const hour = event.timestamp.toISOString().substring(0, 13);
eventsPerHour[hour] = (eventsPerHour[hour] || 0) + 1;
eventTypeDistribution[event.type] = (eventTypeDistribution[event.type] || 0) + 1;
if (i > 0) {
timeDiffs.push(
event.timestamp.getTime() - sortedEvents[i - 1].timestamp.getTime()
);
}
}
const avgTimeBetweenEvents = timeDiffs.length > 0
? timeDiffs.reduce((a, b) => a + b, 0) / timeDiffs.length
: 0;
return {
eventsPerHour,
eventTypeDistribution,
avgTimeBetweenEvents
};
}
}
/**
* Create a temporal events generator
*/
export function createTemporalEventsGenerator(client: OpenRouterClient): TemporalEventsGenerator {
return new TemporalEventsGenerator(client);
}

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,eAAe,CAAC;AACvB,OAAO,EAAE,gBAAgB,EAA0B,MAAM,wBAAwB,CAAC;AAiBlF,OAAO,EAAE,eAAe,EAAyB,MAAM,uBAAuB,CAAC;AAC/E,OAAO,EAAE,mBAAmB,EAA6B,MAAM,2BAA2B,CAAC;AAC3F,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,EACpB,yBAAyB,EACzB,qBAAqB,EACrB,SAAS,EACT,eAAe,EAChB,MAAM,YAAY,CAAC;AAEpB;;GAEG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,iBAAiB,CAA0B;IACnD,OAAO,CAAC,gBAAgB,CAAyB;IACjD,OAAO,CAAC,iBAAiB,CAA0B;IACnD,OAAO,CAAC,qBAAqB,CAA8B;IAC3D,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,mBAAmB,CAAC,CAAsB;gBAEtC,MAAM,GAAE,OAAO,CAAC,gBAAgB,CAAM;IASlD;;OAEG;IACG,sBAAsB,CAC1B,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;IAgB5C;;OAEG;IACG,qBAAqB,CACzB,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;IAc5C;;OAEG;IACG,sBAAsB,CAC1B,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;IAc5C;;OAEG;IACG,2BAA2B,CAC/B,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;IAc5C;;OAEG;IACG,oBAAoB,CACxB,IAAI,EAAE,SAAS,EACf,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAChC,OAAO,CAAC,SAAS,CAAC;IAQrB;;OAEG;IACH,cAAc,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE;QACxC,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB,GAAG,MAAM;IAIV;;OAEG;IACH,SAAS,IAAI,gBAAgB;IAI7B;;OAEG;IACH,kBAAkB,IAAI,eAAe;IAIrC;;OAEG;IACH,sBAAsB,IAAI,mBAAmB,GAAG,SAAS;CAG1D;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,GACjC,kBAAkB,CAEpB;AAGD,cAAc,YAAY,CAAC;AAC3B,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oBAAoB,CAAC;AAGnC,eAAe,kBAAkB,CAAC"}

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,202 @@
/**
* @ruvector/graph-data-generator - AI-powered synthetic graph data generation
*
* @packageDocumentation
*/
import 'dotenv/config';
import { OpenRouterClient, createOpenRouterClient } from './openrouter-client.js';
import {
KnowledgeGraphGenerator,
createKnowledgeGraphGenerator
} from './generators/knowledge-graph.js';
import {
SocialNetworkGenerator,
createSocialNetworkGenerator
} from './generators/social-network.js';
import {
TemporalEventsGenerator,
createTemporalEventsGenerator
} from './generators/temporal-events.js';
import {
EntityRelationshipGenerator,
createEntityRelationshipGenerator
} from './generators/entity-relationships.js';
import { CypherGenerator, createCypherGenerator } from './cypher-generator.js';
import { EmbeddingEnrichment, createEmbeddingEnrichment } from './embedding-enrichment.js';
import {
OpenRouterConfig,
KnowledgeGraphOptions,
SocialNetworkOptions,
TemporalEventOptions,
EntityRelationshipOptions,
GraphGenerationResult,
GraphData,
EmbeddingConfig
} from './types.js';
/**
* Main GraphDataGenerator class
*/
export class GraphDataGenerator {
private client: OpenRouterClient;
private knowledgeGraphGen: KnowledgeGraphGenerator;
private socialNetworkGen: SocialNetworkGenerator;
private temporalEventsGen: TemporalEventsGenerator;
private entityRelationshipGen: EntityRelationshipGenerator;
private cypherGen: CypherGenerator;
private embeddingEnrichment?: EmbeddingEnrichment;
constructor(config: Partial<OpenRouterConfig> = {}) {
this.client = createOpenRouterClient(config);
this.knowledgeGraphGen = createKnowledgeGraphGenerator(this.client);
this.socialNetworkGen = createSocialNetworkGenerator(this.client);
this.temporalEventsGen = createTemporalEventsGenerator(this.client);
this.entityRelationshipGen = createEntityRelationshipGenerator(this.client);
this.cypherGen = createCypherGenerator();
}
/**
* Generate a knowledge graph
*/
async generateKnowledgeGraph(
options: KnowledgeGraphOptions
): Promise<GraphGenerationResult<GraphData>> {
const result = await this.knowledgeGraphGen.generate(options);
// Add embeddings if requested
if (options.includeEmbeddings) {
result.data = await this.enrichWithEmbeddings(result.data, {
dimensions: options.embeddingDimension
});
}
// Generate Cypher statements
result.cypher = this.cypherGen.generate(result.data);
return result;
}
/**
* Generate a social network
*/
async generateSocialNetwork(
options: SocialNetworkOptions
): Promise<GraphGenerationResult<GraphData>> {
const result = await this.socialNetworkGen.generate(options);
// Add embeddings if requested
if (options.includeEmbeddings) {
result.data = await this.enrichWithEmbeddings(result.data);
}
// Generate Cypher statements
result.cypher = this.cypherGen.generate(result.data);
return result;
}
/**
* Generate temporal events
*/
async generateTemporalEvents(
options: TemporalEventOptions
): Promise<GraphGenerationResult<GraphData>> {
const result = await this.temporalEventsGen.generate(options);
// Add embeddings if requested
if (options.includeEmbeddings) {
result.data = await this.enrichWithEmbeddings(result.data);
}
// Generate Cypher statements
result.cypher = this.cypherGen.generate(result.data);
return result;
}
/**
* Generate entity relationships
*/
async generateEntityRelationships(
options: EntityRelationshipOptions
): Promise<GraphGenerationResult<GraphData>> {
const result = await this.entityRelationshipGen.generate(options);
// Add embeddings if requested
if (options.includeEmbeddings) {
result.data = await this.enrichWithEmbeddings(result.data);
}
// Generate Cypher statements
result.cypher = this.cypherGen.generate(result.data);
return result;
}
/**
* Enrich graph data with embeddings
*/
async enrichWithEmbeddings(
data: GraphData,
config?: Partial<EmbeddingConfig>
): Promise<GraphData> {
if (!this.embeddingEnrichment) {
this.embeddingEnrichment = createEmbeddingEnrichment(this.client, config);
}
return this.embeddingEnrichment.enrichGraphData(data);
}
/**
* Generate Cypher statements from graph data
*/
generateCypher(data: GraphData, options?: {
useConstraints?: boolean;
useIndexes?: boolean;
useMerge?: boolean;
}): string {
return this.cypherGen.generateSetupScript(data, options);
}
/**
* Get OpenRouter client
*/
getClient(): OpenRouterClient {
return this.client;
}
/**
* Get Cypher generator
*/
getCypherGenerator(): CypherGenerator {
return this.cypherGen;
}
/**
* Get embedding enrichment
*/
getEmbeddingEnrichment(): EmbeddingEnrichment | undefined {
return this.embeddingEnrichment;
}
}
/**
* Create a new GraphDataGenerator instance
*/
export function createGraphDataGenerator(
config?: Partial<OpenRouterConfig>
): GraphDataGenerator {
return new GraphDataGenerator(config);
}
// Export all types and utilities
export * from './types.js';
export * from './openrouter-client.js';
export * from './generators/index.js';
export * from './cypher-generator.js';
export * from './embedding-enrichment.js';
export * from './schemas/index.js';
// Default export
export default GraphDataGenerator;

View File

@@ -0,0 +1,41 @@
/**
* OpenRouter API client with Kimi K2 support
*/
import { OpenRouterConfig, OpenRouterRequest, OpenRouterResponse, OpenRouterMessage } from './types.js';
export declare class OpenRouterClient {
private config;
private throttledFetch;
constructor(config?: Partial<OpenRouterConfig>);
/**
* Create a chat completion
*/
createCompletion(messages: OpenRouterMessage[], options?: Partial<Omit<OpenRouterRequest, 'messages' | 'model'>>): Promise<OpenRouterResponse>;
/**
* Create a streaming chat completion
*/
createStreamingCompletion(messages: OpenRouterMessage[], options?: Partial<Omit<OpenRouterRequest, 'messages' | 'model'>>): AsyncGenerator<string, void, unknown>;
/**
* Generate structured data using prompt engineering
*/
generateStructured<T = unknown>(systemPrompt: string, userPrompt: string, options?: {
temperature?: number;
maxTokens?: number;
}): Promise<T>;
/**
* Generate embeddings (if the model supports it)
*/
generateEmbedding(_text: string): Promise<number[]>;
/**
* Update configuration
*/
configure(config: Partial<OpenRouterConfig>): void;
/**
* Get current configuration
*/
getConfig(): OpenRouterConfig;
}
/**
* Create a new OpenRouter client
*/
export declare function createOpenRouterClient(config?: Partial<OpenRouterConfig>): OpenRouterClient;
//# sourceMappingURL=openrouter-client.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"openrouter-client.d.ts","sourceRoot":"","sources":["openrouter-client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EACL,gBAAgB,EAEhB,iBAAiB,EACjB,kBAAkB,EAElB,iBAAiB,EAClB,MAAM,YAAY,CAAC;AAEpB,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,cAAc,CAA2D;gBAErE,MAAM,GAAE,OAAO,CAAC,gBAAgB,CAAM;IAmBlD;;OAEG;IACG,gBAAgB,CACpB,QAAQ,EAAE,iBAAiB,EAAE,EAC7B,OAAO,GAAE,OAAO,CAAC,IAAI,CAAC,iBAAiB,EAAE,UAAU,GAAG,OAAO,CAAC,CAAM,GACnE,OAAO,CAAC,kBAAkB,CAAC;IAgD9B;;OAEG;IACI,yBAAyB,CAC9B,QAAQ,EAAE,iBAAiB,EAAE,EAC7B,OAAO,GAAE,OAAO,CAAC,IAAI,CAAC,iBAAiB,EAAE,UAAU,GAAG,OAAO,CAAC,CAAM,GACnE,cAAc,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC;IA2ExC;;OAEG;IACG,kBAAkB,CAAC,CAAC,GAAG,OAAO,EAClC,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE;QACR,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,GACA,OAAO,CAAC,CAAC,CAAC;IA+Bb;;OAEG;IACG,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAMzD;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,IAAI;IAIlD;;OAEG;IACH,SAAS,IAAI,gBAAgB;CAG9B;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,gBAAgB,CAE3F"}

View File

@@ -0,0 +1,194 @@
"use strict";
/**
* OpenRouter API client with Kimi K2 support
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.OpenRouterClient = void 0;
exports.createOpenRouterClient = createOpenRouterClient;
const p_retry_1 = __importDefault(require("p-retry"));
const p_throttle_1 = __importDefault(require("p-throttle"));
const types_js_1 = require("./types.js");
class OpenRouterClient {
constructor(config = {}) {
const apiKey = config.apiKey || process.env.OPENROUTER_API_KEY;
if (!apiKey) {
throw new Error('OpenRouter API key is required. Set OPENROUTER_API_KEY environment variable or pass apiKey in config.');
}
this.config = types_js_1.OpenRouterConfigSchema.parse({ ...config, apiKey });
// Setup rate limiting if configured
if (this.config.rateLimit) {
this.throttledFetch = (0, p_throttle_1.default)({
limit: this.config.rateLimit.requests,
interval: this.config.rateLimit.interval
})(fetch.bind(globalThis));
}
else {
this.throttledFetch = fetch.bind(globalThis);
}
}
/**
* Create a chat completion
*/
async createCompletion(messages, options = {}) {
const request = {
model: this.config.model || 'moonshot/kimi-k2-instruct',
messages,
temperature: options.temperature ?? 0.7,
max_tokens: options.max_tokens ?? 4096,
top_p: options.top_p ?? 1,
stream: false,
...options
};
return (0, p_retry_1.default)(async () => {
const response = await this.throttledFetch(`${this.config.baseURL}/chat/completions`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.config.apiKey}`,
'HTTP-Referer': 'https://github.com/ruvnet/ruvector',
'X-Title': 'RuVector Graph Data Generator'
},
body: JSON.stringify(request),
signal: AbortSignal.timeout(this.config.timeout || 60000)
});
if (!response.ok) {
const error = await response.text();
throw new types_js_1.OpenRouterError(`OpenRouter API error: ${response.status} ${response.statusText}`, { status: response.status, error });
}
const data = await response.json();
return data;
}, {
retries: this.config.maxRetries || 3,
onFailedAttempt: (error) => {
console.warn(`Attempt ${error.attemptNumber} failed. ${error.retriesLeft} retries left.`);
}
});
}
/**
* Create a streaming chat completion
*/
async *createStreamingCompletion(messages, options = {}) {
const request = {
model: this.config.model || 'moonshot/kimi-k2-instruct',
messages,
temperature: options.temperature ?? 0.7,
max_tokens: options.max_tokens ?? 4096,
top_p: options.top_p ?? 1,
stream: true,
...options
};
const response = await this.throttledFetch(`${this.config.baseURL}/chat/completions`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.config.apiKey}`,
'HTTP-Referer': 'https://github.com/ruvnet/ruvector',
'X-Title': 'RuVector Graph Data Generator'
},
body: JSON.stringify(request),
signal: AbortSignal.timeout(this.config.timeout || 60000)
});
if (!response.ok) {
const error = await response.text();
throw new types_js_1.OpenRouterError(`OpenRouter API error: ${response.status} ${response.statusText}`, { status: response.status, error });
}
if (!response.body) {
throw new types_js_1.OpenRouterError('No response body received');
}
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
try {
while (true) {
const { done, value } = await reader.read();
if (done)
break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
buffer = lines.pop() || '';
for (const line of lines) {
if (line.startsWith('data: ')) {
const data = line.slice(6).trim();
if (data === '[DONE]') {
return;
}
try {
const parsed = JSON.parse(data);
const content = parsed.choices?.[0]?.delta?.content;
if (content) {
yield content;
}
}
catch (e) {
console.warn('Failed to parse SSE data:', data);
}
}
}
}
}
finally {
reader.releaseLock();
}
}
/**
* Generate structured data using prompt engineering
*/
async generateStructured(systemPrompt, userPrompt, options) {
const messages = [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userPrompt }
];
const response = await this.createCompletion(messages, {
temperature: options?.temperature ?? 0.7,
max_tokens: options?.maxTokens ?? 4096
});
const content = response.choices[0]?.message?.content;
if (!content) {
throw new types_js_1.OpenRouterError('No content in response');
}
// Try to extract JSON from response
try {
// Look for JSON in code blocks
const jsonMatch = content.match(/```(?:json)?\s*(\{[\s\S]*?\}|\[[\s\S]*?\])\s*```/);
if (jsonMatch) {
return JSON.parse(jsonMatch[1]);
}
// Try to parse the entire response as JSON
return JSON.parse(content);
}
catch (e) {
throw new types_js_1.OpenRouterError('Failed to parse JSON from response', { content, error: e });
}
}
/**
* Generate embeddings (if the model supports it)
*/
async generateEmbedding(_text) {
// Note: Kimi K2 may not support embeddings directly
// This is a placeholder for potential future support
throw new Error('Embedding generation not yet implemented for Kimi K2');
}
/**
* Update configuration
*/
configure(config) {
this.config = types_js_1.OpenRouterConfigSchema.parse({ ...this.config, ...config });
}
/**
* Get current configuration
*/
getConfig() {
return { ...this.config };
}
}
exports.OpenRouterClient = OpenRouterClient;
/**
* Create a new OpenRouter client
*/
function createOpenRouterClient(config) {
return new OpenRouterClient(config);
}
//# sourceMappingURL=openrouter-client.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,244 @@
/**
* OpenRouter API client with Kimi K2 support
*/
import pRetry from 'p-retry';
import pThrottle from 'p-throttle';
import {
OpenRouterConfig,
OpenRouterConfigSchema,
OpenRouterRequest,
OpenRouterResponse,
OpenRouterError,
OpenRouterMessage
} from './types.js';
export class OpenRouterClient {
private config: OpenRouterConfig;
private throttledFetch: (url: string, options: RequestInit) => Promise<Response>;
constructor(config: Partial<OpenRouterConfig> = {}) {
const apiKey = config.apiKey || process.env.OPENROUTER_API_KEY;
if (!apiKey) {
throw new Error('OpenRouter API key is required. Set OPENROUTER_API_KEY environment variable or pass apiKey in config.');
}
this.config = OpenRouterConfigSchema.parse({ ...config, apiKey });
// Setup rate limiting if configured
if (this.config.rateLimit) {
this.throttledFetch = pThrottle({
limit: this.config.rateLimit.requests,
interval: this.config.rateLimit.interval
})(fetch.bind(globalThis)) as (url: string, options: RequestInit) => Promise<Response>;
} else {
this.throttledFetch = fetch.bind(globalThis);
}
}
/**
* Create a chat completion
*/
async createCompletion(
messages: OpenRouterMessage[],
options: Partial<Omit<OpenRouterRequest, 'messages' | 'model'>> = {}
): Promise<OpenRouterResponse> {
const request: OpenRouterRequest = {
model: this.config.model || 'moonshot/kimi-k2-instruct',
messages,
temperature: options.temperature ?? 0.7,
max_tokens: options.max_tokens ?? 4096,
top_p: options.top_p ?? 1,
stream: false,
...options
};
return pRetry(
async () => {
const response = await this.throttledFetch(
`${this.config.baseURL}/chat/completions`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.config.apiKey}`,
'HTTP-Referer': 'https://github.com/ruvnet/ruvector',
'X-Title': 'RuVector Graph Data Generator'
},
body: JSON.stringify(request),
signal: AbortSignal.timeout(this.config.timeout || 60000)
}
);
if (!response.ok) {
const error = await response.text();
throw new OpenRouterError(
`OpenRouter API error: ${response.status} ${response.statusText}`,
{ status: response.status, error }
);
}
const data = await response.json() as OpenRouterResponse;
return data;
},
{
retries: this.config.maxRetries || 3,
onFailedAttempt: (error) => {
console.warn(`Attempt ${error.attemptNumber} failed. ${error.retriesLeft} retries left.`);
}
}
);
}
/**
* Create a streaming chat completion
*/
async *createStreamingCompletion(
messages: OpenRouterMessage[],
options: Partial<Omit<OpenRouterRequest, 'messages' | 'model'>> = {}
): AsyncGenerator<string, void, unknown> {
const request: OpenRouterRequest = {
model: this.config.model || 'moonshot/kimi-k2-instruct',
messages,
temperature: options.temperature ?? 0.7,
max_tokens: options.max_tokens ?? 4096,
top_p: options.top_p ?? 1,
stream: true,
...options
};
const response = await this.throttledFetch(
`${this.config.baseURL}/chat/completions`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.config.apiKey}`,
'HTTP-Referer': 'https://github.com/ruvnet/ruvector',
'X-Title': 'RuVector Graph Data Generator'
},
body: JSON.stringify(request),
signal: AbortSignal.timeout(this.config.timeout || 60000)
}
);
if (!response.ok) {
const error = await response.text();
throw new OpenRouterError(
`OpenRouter API error: ${response.status} ${response.statusText}`,
{ status: response.status, error }
);
}
if (!response.body) {
throw new OpenRouterError('No response body received');
}
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
try {
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
buffer = lines.pop() || '';
for (const line of lines) {
if (line.startsWith('data: ')) {
const data = line.slice(6).trim();
if (data === '[DONE]') {
return;
}
try {
const parsed = JSON.parse(data);
const content = parsed.choices?.[0]?.delta?.content;
if (content) {
yield content;
}
} catch (e) {
console.warn('Failed to parse SSE data:', data);
}
}
}
}
} finally {
reader.releaseLock();
}
}
/**
* Generate structured data using prompt engineering
*/
async generateStructured<T = unknown>(
systemPrompt: string,
userPrompt: string,
options?: {
temperature?: number;
maxTokens?: number;
}
): Promise<T> {
const messages: OpenRouterMessage[] = [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userPrompt }
];
const response = await this.createCompletion(messages, {
temperature: options?.temperature ?? 0.7,
max_tokens: options?.maxTokens ?? 4096
});
const content = response.choices[0]?.message?.content;
if (!content) {
throw new OpenRouterError('No content in response');
}
// Try to extract JSON from response
try {
// Look for JSON in code blocks
const jsonMatch = content.match(/```(?:json)?\s*(\{[\s\S]*?\}|\[[\s\S]*?\])\s*```/);
if (jsonMatch) {
return JSON.parse(jsonMatch[1]) as T;
}
// Try to parse the entire response as JSON
return JSON.parse(content) as T;
} catch (e) {
throw new OpenRouterError('Failed to parse JSON from response', { content, error: e });
}
}
/**
* Generate embeddings (if the model supports it)
*/
async generateEmbedding(_text: string): Promise<number[]> {
// Note: Kimi K2 may not support embeddings directly
// This is a placeholder for potential future support
throw new Error('Embedding generation not yet implemented for Kimi K2');
}
/**
* Update configuration
*/
configure(config: Partial<OpenRouterConfig>): void {
this.config = OpenRouterConfigSchema.parse({ ...this.config, ...config });
}
/**
* Get current configuration
*/
getConfig(): OpenRouterConfig {
return { ...this.config };
}
}
/**
* Create a new OpenRouter client
*/
export function createOpenRouterClient(config?: Partial<OpenRouterConfig>): OpenRouterClient {
return new OpenRouterClient(config);
}

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;EAK1B,CAAC;AAGH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;EAO1B,CAAC;AAGH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAU1B,CAAC;AAGH,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;EAQtC,CAAC;AAGH,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;EAOrC,CAAC;AAGH,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;EAOrC,CAAC;AAGH,eAAO,MAAM,+BAA+B;;;;;;;;;;;;;;;;;;;;;EAO1C,CAAC;AAGH,eAAO,MAAM,qBAAqB;;;;;;;;;EAGhC,CAAC;AAGH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAQ5B,CAAC;AAGH,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAatC,CAAC;AAGH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;EAE9C;AAED,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,OAAO;;;;;;;;EAE7D;AAED,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,OAAO;;;;;;;EAE5D;AAED,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,OAAO;;;;;;;EAE5D;AAED,wBAAgB,iCAAiC,CAAC,OAAO,EAAE,OAAO;;;;;;;EAEjE;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO;;;;;;;;;;;EAEjD;AAED,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAE5D"}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,139 @@
/**
* Zod schemas for graph data validation
*/
import { z } from 'zod';
// Graph node schema
export const GraphNodeSchema = z.object({
id: z.string(),
labels: z.array(z.string()),
properties: z.record(z.string(), z.unknown()),
embedding: z.array(z.number()).optional()
});
// Graph edge schema
export const GraphEdgeSchema = z.object({
id: z.string(),
type: z.string(),
source: z.string(),
target: z.string(),
properties: z.record(z.string(), z.unknown()),
embedding: z.array(z.number()).optional()
});
// Graph data schema
export const GraphDataSchema = z.object({
nodes: z.array(GraphNodeSchema),
edges: z.array(GraphEdgeSchema),
metadata: z.object({
domain: z.string().optional(),
generated_at: z.date().optional(),
model: z.string().optional(),
total_nodes: z.number().optional(),
total_edges: z.number().optional()
}).optional()
});
// Knowledge graph options schema
export const KnowledgeGraphOptionsSchema = z.object({
domain: z.string(),
entities: z.number().positive(),
relationships: z.number().positive(),
entityTypes: z.array(z.string()).optional(),
relationshipTypes: z.array(z.string()).optional(),
includeEmbeddings: z.boolean().optional(),
embeddingDimension: z.number().positive().optional()
});
// Social network options schema
export const SocialNetworkOptionsSchema = z.object({
users: z.number().positive(),
avgConnections: z.number().positive(),
networkType: z.enum(['random', 'small-world', 'scale-free', 'clustered']).optional(),
communities: z.number().positive().optional(),
includeMetadata: z.boolean().optional(),
includeEmbeddings: z.boolean().optional()
});
// Temporal event options schema
export const TemporalEventOptionsSchema = z.object({
startDate: z.union([z.date(), z.string()]),
endDate: z.union([z.date(), z.string()]),
eventTypes: z.array(z.string()),
eventsPerDay: z.number().positive().optional(),
entities: z.number().positive().optional(),
includeEmbeddings: z.boolean().optional()
});
// Entity relationship options schema
export const EntityRelationshipOptionsSchema = z.object({
domain: z.string(),
entityCount: z.number().positive(),
relationshipDensity: z.number().min(0).max(1),
entitySchema: z.record(z.string(), z.unknown()).optional(),
relationshipTypes: z.array(z.string()).optional(),
includeEmbeddings: z.boolean().optional()
});
// Cypher statement schema
export const CypherStatementSchema = z.object({
query: z.string(),
parameters: z.record(z.string(), z.unknown()).optional()
});
// Cypher batch schema
export const CypherBatchSchema = z.object({
statements: z.array(CypherStatementSchema),
metadata: z.object({
total_nodes: z.number().optional(),
total_relationships: z.number().optional(),
labels: z.array(z.string()).optional(),
relationship_types: z.array(z.string()).optional()
}).optional()
});
// Graph generation result schema
export const GraphGenerationResultSchema = z.object({
data: GraphDataSchema,
metadata: z.object({
generated_at: z.date(),
model: z.string(),
duration: z.number(),
token_usage: z.object({
prompt_tokens: z.number(),
completion_tokens: z.number(),
total_tokens: z.number()
}).optional()
}),
cypher: CypherBatchSchema.optional()
});
// Validation helpers
export function validateGraphData(data: unknown) {
return GraphDataSchema.parse(data);
}
export function validateKnowledgeGraphOptions(options: unknown) {
return KnowledgeGraphOptionsSchema.parse(options);
}
export function validateSocialNetworkOptions(options: unknown) {
return SocialNetworkOptionsSchema.parse(options);
}
export function validateTemporalEventOptions(options: unknown) {
return TemporalEventOptionsSchema.parse(options);
}
export function validateEntityRelationshipOptions(options: unknown) {
return EntityRelationshipOptionsSchema.parse(options);
}
export function validateCypherBatch(batch: unknown) {
return CypherBatchSchema.parse(batch);
}
export function validateGraphGenerationResult(result: unknown) {
return GraphGenerationResultSchema.parse(result);
}

View File

@@ -0,0 +1,218 @@
/**
* Core types and interfaces for graph-data-generator
*/
import { z } from 'zod';
export interface GraphNode {
id: string;
labels: string[];
properties: Record<string, unknown>;
embedding?: number[];
}
export interface GraphEdge {
id: string;
type: string;
source: string;
target: string;
properties: Record<string, unknown>;
embedding?: number[];
}
export interface GraphData {
nodes: GraphNode[];
edges: GraphEdge[];
metadata?: {
domain?: string;
generated_at?: Date;
model?: string;
total_nodes?: number;
total_edges?: number;
};
}
export interface KnowledgeTriple {
subject: string;
predicate: string;
object: string;
confidence?: number;
source?: string;
}
export interface KnowledgeGraphOptions {
domain: string;
entities: number;
relationships: number;
entityTypes?: string[];
relationshipTypes?: string[];
includeEmbeddings?: boolean;
embeddingDimension?: number;
}
export interface SocialNetworkOptions {
users: number;
avgConnections: number;
networkType?: 'random' | 'small-world' | 'scale-free' | 'clustered';
communities?: number;
includeMetadata?: boolean;
includeEmbeddings?: boolean;
}
export interface SocialNode {
id: string;
username: string;
profile: {
name?: string;
bio?: string;
joined?: Date;
followers?: number;
following?: number;
};
metadata?: Record<string, unknown>;
}
export interface TemporalEventOptions {
startDate: Date | string;
endDate: Date | string;
eventTypes: string[];
eventsPerDay?: number;
entities?: number;
includeEmbeddings?: boolean;
}
export interface TemporalEvent {
id: string;
type: string;
timestamp: Date;
entities: string[];
properties: Record<string, unknown>;
relationships?: Array<{
type: string;
target: string;
}>;
}
export interface EntityRelationshipOptions {
domain: string;
entityCount: number;
relationshipDensity: number;
entitySchema?: Record<string, unknown>;
relationshipTypes?: string[];
includeEmbeddings?: boolean;
}
export interface OpenRouterConfig {
apiKey: string;
model?: string;
baseURL?: string;
timeout?: number;
maxRetries?: number;
rateLimit?: {
requests: number;
interval: number;
};
}
export declare const OpenRouterConfigSchema: z.ZodObject<{
apiKey: z.ZodString;
model: z.ZodDefault<z.ZodOptional<z.ZodString>>;
baseURL: z.ZodDefault<z.ZodOptional<z.ZodString>>;
timeout: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
maxRetries: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
rateLimit: z.ZodOptional<z.ZodObject<{
requests: z.ZodNumber;
interval: z.ZodNumber;
}, "strip", z.ZodTypeAny, {
interval: number;
requests: number;
}, {
interval: number;
requests: number;
}>>;
}, "strip", z.ZodTypeAny, {
maxRetries: number;
apiKey: string;
model: string;
timeout: number;
baseURL: string;
rateLimit?: {
interval: number;
requests: number;
} | undefined;
}, {
apiKey: string;
maxRetries?: number | undefined;
model?: string | undefined;
timeout?: number | undefined;
baseURL?: string | undefined;
rateLimit?: {
interval: number;
requests: number;
} | undefined;
}>;
export interface OpenRouterMessage {
role: 'system' | 'user' | 'assistant';
content: string;
}
export interface OpenRouterRequest {
model: string;
messages: OpenRouterMessage[];
temperature?: number;
max_tokens?: number;
top_p?: number;
stream?: boolean;
}
export interface OpenRouterResponse {
id: string;
model: string;
choices: Array<{
message: {
role: string;
content: string;
};
finish_reason: string;
}>;
usage: {
prompt_tokens: number;
completion_tokens: number;
total_tokens: number;
};
}
export interface CypherStatement {
query: string;
parameters?: Record<string, unknown>;
}
export interface CypherBatch {
statements: CypherStatement[];
metadata?: {
total_nodes?: number;
total_relationships?: number;
labels?: string[];
relationship_types?: string[];
};
}
export interface EmbeddingConfig {
provider: 'openrouter' | 'local';
model?: string;
dimensions?: number;
batchSize?: number;
}
export interface EmbeddingResult {
embedding: number[];
model: string;
dimensions: number;
}
export interface GraphGenerationResult<T = GraphData> {
data: T;
metadata: {
generated_at: Date;
model: string;
duration: number;
token_usage?: {
prompt_tokens: number;
completion_tokens: number;
total_tokens: number;
};
};
cypher?: CypherBatch;
}
export declare class GraphGenerationError extends Error {
code: string;
details?: unknown | undefined;
constructor(message: string, code: string, details?: unknown | undefined);
}
export declare class OpenRouterError extends GraphGenerationError {
constructor(message: string, details?: unknown);
}
export declare class ValidationError extends GraphGenerationError {
constructor(message: string, details?: unknown);
}
//# sourceMappingURL=types.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,43 @@
"use strict";
/**
* Core types and interfaces for graph-data-generator
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ValidationError = exports.OpenRouterError = exports.GraphGenerationError = exports.OpenRouterConfigSchema = void 0;
const zod_1 = require("zod");
exports.OpenRouterConfigSchema = zod_1.z.object({
apiKey: zod_1.z.string(),
model: zod_1.z.string().optional().default('moonshot/kimi-k2-instruct'),
baseURL: zod_1.z.string().optional().default('https://openrouter.ai/api/v1'),
timeout: zod_1.z.number().optional().default(60000),
maxRetries: zod_1.z.number().optional().default(3),
rateLimit: zod_1.z.object({
requests: zod_1.z.number(),
interval: zod_1.z.number()
}).optional()
});
// Error types
class GraphGenerationError extends Error {
constructor(message, code, details) {
super(message);
this.code = code;
this.details = details;
this.name = 'GraphGenerationError';
}
}
exports.GraphGenerationError = GraphGenerationError;
class OpenRouterError extends GraphGenerationError {
constructor(message, details) {
super(message, 'OPENROUTER_ERROR', details);
this.name = 'OpenRouterError';
}
}
exports.OpenRouterError = OpenRouterError;
class ValidationError extends GraphGenerationError {
constructor(message, details) {
super(message, 'VALIDATION_ERROR', details);
this.name = 'ValidationError';
}
}
exports.ValidationError = ValidationError;
//# sourceMappingURL=types.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"types.js","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH,6BAAwB;AAsHX,QAAA,sBAAsB,GAAG,OAAC,CAAC,MAAM,CAAC;IAC7C,MAAM,EAAE,OAAC,CAAC,MAAM,EAAE;IAClB,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,2BAA2B,CAAC;IACjE,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,8BAA8B,CAAC;IACtE,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;IAC7C,UAAU,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAC5C,SAAS,EAAE,OAAC,CAAC,MAAM,CAAC;QAClB,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE;QACpB,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE;KACrB,CAAC,CAAC,QAAQ,EAAE;CACd,CAAC,CAAC;AA+EH,cAAc;AACd,MAAa,oBAAqB,SAAQ,KAAK;IAC7C,YACE,OAAe,EACR,IAAY,EACZ,OAAiB;QAExB,KAAK,CAAC,OAAO,CAAC,CAAC;QAHR,SAAI,GAAJ,IAAI,CAAQ;QACZ,YAAO,GAAP,OAAO,CAAU;QAGxB,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AATD,oDASC;AAED,MAAa,eAAgB,SAAQ,oBAAoB;IACvD,YAAY,OAAe,EAAE,OAAiB;QAC5C,KAAK,CAAC,OAAO,EAAE,kBAAkB,EAAE,OAAO,CAAC,CAAC;QAC5C,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CACF;AALD,0CAKC;AAED,MAAa,eAAgB,SAAQ,oBAAoB;IACvD,YAAY,OAAe,EAAE,OAAiB;QAC5C,KAAK,CAAC,OAAO,EAAE,kBAAkB,EAAE,OAAO,CAAC,CAAC;QAC5C,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CACF;AALD,0CAKC"}

View File

@@ -0,0 +1,236 @@
/**
* Core types and interfaces for graph-data-generator
*/
import { z } from 'zod';
// Graph data types
export interface GraphNode {
id: string;
labels: string[];
properties: Record<string, unknown>;
embedding?: number[];
}
export interface GraphEdge {
id: string;
type: string;
source: string;
target: string;
properties: Record<string, unknown>;
embedding?: number[];
}
export interface GraphData {
nodes: GraphNode[];
edges: GraphEdge[];
metadata?: {
domain?: string;
generated_at?: Date;
model?: string;
total_nodes?: number;
total_edges?: number;
};
}
// Knowledge graph types
export interface KnowledgeTriple {
subject: string;
predicate: string;
object: string;
confidence?: number;
source?: string;
}
export interface KnowledgeGraphOptions {
domain: string;
entities: number;
relationships: number;
entityTypes?: string[];
relationshipTypes?: string[];
includeEmbeddings?: boolean;
embeddingDimension?: number;
}
// Social network types
export interface SocialNetworkOptions {
users: number;
avgConnections: number;
networkType?: 'random' | 'small-world' | 'scale-free' | 'clustered';
communities?: number;
includeMetadata?: boolean;
includeEmbeddings?: boolean;
}
export interface SocialNode {
id: string;
username: string;
profile: {
name?: string;
bio?: string;
joined?: Date;
followers?: number;
following?: number;
};
metadata?: Record<string, unknown>;
}
// Temporal event types
export interface TemporalEventOptions {
startDate: Date | string;
endDate: Date | string;
eventTypes: string[];
eventsPerDay?: number;
entities?: number;
includeEmbeddings?: boolean;
}
export interface TemporalEvent {
id: string;
type: string;
timestamp: Date;
entities: string[];
properties: Record<string, unknown>;
relationships?: Array<{
type: string;
target: string;
}>;
}
// Entity relationship types
export interface EntityRelationshipOptions {
domain: string;
entityCount: number;
relationshipDensity: number; // 0-1
entitySchema?: Record<string, unknown>;
relationshipTypes?: string[];
includeEmbeddings?: boolean;
}
// OpenRouter client types
export interface OpenRouterConfig {
apiKey: string;
model?: string;
baseURL?: string;
timeout?: number;
maxRetries?: number;
rateLimit?: {
requests: number;
interval: number; // milliseconds
};
}
export const OpenRouterConfigSchema = z.object({
apiKey: z.string(),
model: z.string().optional().default('moonshot/kimi-k2-instruct'),
baseURL: z.string().optional().default('https://openrouter.ai/api/v1'),
timeout: z.number().optional().default(60000),
maxRetries: z.number().optional().default(3),
rateLimit: z.object({
requests: z.number(),
interval: z.number()
}).optional()
});
export interface OpenRouterMessage {
role: 'system' | 'user' | 'assistant';
content: string;
}
export interface OpenRouterRequest {
model: string;
messages: OpenRouterMessage[];
temperature?: number;
max_tokens?: number;
top_p?: number;
stream?: boolean;
}
export interface OpenRouterResponse {
id: string;
model: string;
choices: Array<{
message: {
role: string;
content: string;
};
finish_reason: string;
}>;
usage: {
prompt_tokens: number;
completion_tokens: number;
total_tokens: number;
};
}
// Cypher types
export interface CypherStatement {
query: string;
parameters?: Record<string, unknown>;
}
export interface CypherBatch {
statements: CypherStatement[];
metadata?: {
total_nodes?: number;
total_relationships?: number;
labels?: string[];
relationship_types?: string[];
};
}
// Embedding types
export interface EmbeddingConfig {
provider: 'openrouter' | 'local';
model?: string;
dimensions?: number;
batchSize?: number;
}
export interface EmbeddingResult {
embedding: number[];
model: string;
dimensions: number;
}
// Generation result types
export interface GraphGenerationResult<T = GraphData> {
data: T;
metadata: {
generated_at: Date;
model: string;
duration: number;
token_usage?: {
prompt_tokens: number;
completion_tokens: number;
total_tokens: number;
};
};
cypher?: CypherBatch;
}
// Error types
export class GraphGenerationError extends Error {
constructor(
message: string,
public code: string,
public details?: unknown
) {
super(message);
this.name = 'GraphGenerationError';
}
}
export class OpenRouterError extends GraphGenerationError {
constructor(message: string, details?: unknown) {
super(message, 'OPENROUTER_ERROR', details);
this.name = 'OpenRouterError';
}
}
export class ValidationError extends GraphGenerationError {
constructor(message: string, details?: unknown) {
super(message, 'VALIDATION_ERROR', details);
this.name = 'ValidationError';
}
}

View File

@@ -0,0 +1,26 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ES2022",
"lib": ["ES2022"],
"moduleResolution": "bundler",
"resolveJsonModule": true,
"allowJs": true,
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"outDir": "./dist",
"rootDir": "./src",
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"allowSyntheticDefaultImports": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "tests"]
}