@ai.ntellect/core 0.5.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.mocharc.json +1 -1
- package/README.md +311 -272
- package/create-llm-to-select-multiple-graph copy.ts +243 -0
- package/create-llm-to-select-multiple-graph.ts +148 -0
- package/dist/graph/controller.js +63 -0
- package/dist/graph/engine.js +563 -0
- package/dist/index.js +6 -6
- package/dist/memory/adapters/meilisearch/index.js +249 -0
- package/dist/memory/adapters/redis/index.js +96 -0
- package/dist/memory/index.js +9 -0
- package/dist/services/agenda.js +115 -0
- package/dist/services/embedding.js +40 -0
- package/dist/services/queue.js +99 -103
- package/dist/test/graph/controller.test.js +170 -0
- package/dist/test/graph/engine.test.js +465 -0
- package/dist/test/memory/adapters/meilisearch.test.js +250 -0
- package/dist/test/memory/adapters/redis.test.js +143 -0
- package/dist/test/memory/base.test.js +209 -0
- package/dist/test/services/agenda.test.js +230 -0
- package/dist/test/services/queue.test.js +258 -0
- package/dist/types/index.js +2 -0
- package/dist/utils/generate-object.js +32 -11
- package/dist/utils/inject-actions.js +2 -2
- package/dist/utils/queue-item-transformer.js +2 -2
- package/dist/utils/state-manager.js +20 -0
- package/graph/controller.ts +64 -0
- package/graph/engine.ts +790 -0
- package/index copy.ts +81 -0
- package/index.ts +7 -7
- package/interfaces/index.ts +119 -0
- package/memory/adapters/meilisearch/index.ts +286 -0
- package/memory/adapters/redis/index.ts +103 -0
- package/memory/index.ts +22 -0
- package/package.json +7 -2
- package/services/agenda.ts +48 -43
- package/services/embedding.ts +26 -0
- package/services/queue.ts +2 -29
- package/test/.env.test +4 -0
- package/test/graph/controller.test.ts +186 -0
- package/test/graph/engine.test.ts +546 -0
- package/test/memory/adapters/meilisearch.test.ts +297 -0
- package/test/memory/adapters/redis.test.ts +160 -0
- package/test/memory/base.test.ts +229 -0
- package/test/services/agenda.test.ts +280 -0
- package/test/services/queue.test.ts +286 -44
- package/tsconfig.json +10 -10
- package/types/index.ts +278 -0
- package/utils/queue-item-transformer.ts +8 -11
- package/utils/setup-graphs.ts +45 -0
- package/utils/stringifiy-zod-schema.ts +45 -0
- package/.nvmrc +0 -1
- package/README.FR.md +0 -916
- package/agent/index.ts +0 -151
- package/agent/workflow/conditions.ts +0 -16
- package/agent/workflow/handlers/interpreter.handler.ts +0 -48
- package/agent/workflow/handlers/memory.handler.ts +0 -106
- package/agent/workflow/handlers/orchestrator.handler.ts +0 -23
- package/agent/workflow/handlers/queue.handler.ts +0 -34
- package/agent/workflow/handlers/scheduler.handler.ts +0 -61
- package/agent/workflow/index.ts +0 -62
- package/dist/agent/index.d.ts +0 -38
- package/dist/agent/index.js +0 -143
- package/dist/agent/tools/get-rss.d.ts +0 -16
- package/dist/agent/tools/get-rss.js +0 -62
- package/dist/bull.d.ts +0 -1
- package/dist/bull.js +0 -9
- package/dist/examples/index.d.ts +0 -2
- package/dist/examples/index.js +0 -89
- package/dist/index.d.ts +0 -7
- package/dist/llm/interpreter/context.d.ts +0 -15
- package/dist/llm/interpreter/context.js +0 -89
- package/dist/llm/interpreter/index.d.ts +0 -21
- package/dist/llm/interpreter/index.js +0 -87
- package/dist/llm/memory-manager/context.d.ts +0 -2
- package/dist/llm/memory-manager/context.js +0 -22
- package/dist/llm/memory-manager/index.d.ts +0 -17
- package/dist/llm/memory-manager/index.js +0 -107
- package/dist/llm/orchestrator/context.d.ts +0 -2
- package/dist/llm/orchestrator/context.js +0 -23
- package/dist/llm/orchestrator/index.d.ts +0 -44
- package/dist/llm/orchestrator/index.js +0 -139
- package/dist/llm/orchestrator/types.d.ts +0 -12
- package/dist/memory/cache.d.ts +0 -22
- package/dist/memory/cache.js +0 -165
- package/dist/memory/persistent.d.ts +0 -57
- package/dist/memory/persistent.js +0 -189
- package/dist/services/queue.d.ts +0 -13
- package/dist/services/redis-cache.d.ts +0 -37
- package/dist/services/redis-cache.js +0 -93
- package/dist/services/scheduler.d.ts +0 -40
- package/dist/services/scheduler.js +0 -99
- package/dist/services/telegram-monitor.d.ts +0 -0
- package/dist/services/telegram-monitor.js +0 -118
- package/dist/t.d.ts +0 -46
- package/dist/t.js +0 -102
- package/dist/test.d.ts +0 -0
- package/dist/test.js +0 -438
- package/dist/types.d.ts +0 -258
- package/dist/types.js +0 -22
- package/dist/utils/generate-object.d.ts +0 -12
- package/dist/utils/header-builder.d.ts +0 -11
- package/dist/utils/inject-actions.d.ts +0 -2
- package/dist/utils/queue-item-transformer.d.ts +0 -7
- package/dist/utils/sanitize-results.d.ts +0 -17
- package/dist/utils/schema-generator.d.ts +0 -16
- package/examples/actions/get-rss.ts +0 -71
- package/examples/index.ts +0 -98
- package/index.html +0 -42
- package/llm/dynamic-condition/example.ts +0 -36
- package/llm/dynamic-condition/index.ts +0 -108
- package/llm/interpreter/context.ts +0 -94
- package/llm/interpreter/index.ts +0 -140
- package/llm/memory-manager/context.ts +0 -19
- package/llm/memory-manager/index.ts +0 -115
- package/llm/orchestrator/context.ts +0 -19
- package/llm/orchestrator/index.ts +0 -192
- package/llm/orchestrator/types.ts +0 -14
- package/memory/cache.ts +0 -221
- package/memory/persistent.ts +0 -265
- package/script.js +0 -167
- package/services/cache.ts +0 -298
- package/services/telegram-monitor.ts +0 -138
- package/services/workflow.ts +0 -491
- package/t.py +0 -79
- package/t.ts +0 -25
- package/test/llm/orchestrator.test.ts +0 -47
- package/test/llm/synthesizer.test.ts +0 -31
- package/types.ts +0 -367
- package/utils/schema-generator.ts +0 -73
- package/utils/state-manager.ts +0 -25
- /package/dist/{llm/orchestrator/types.js → interfaces/index.js} +0 -0
package/memory/persistent.ts
DELETED
@@ -1,265 +0,0 @@
|
|
1
|
-
import { cosineSimilarity, embed, EmbeddingModel, embedMany } from "ai";
|
2
|
-
import { RecursiveCharacterTextSplitter } from "langchain/text_splitter";
|
3
|
-
import { LongTermMemory, MemoryScope } from "../types";
|
4
|
-
|
5
|
-
interface SearchOptions {
|
6
|
-
scope?: MemoryScope;
|
7
|
-
userId?: string;
|
8
|
-
maxResults?: number;
|
9
|
-
similarityThreshold?: number;
|
10
|
-
}
|
11
|
-
|
12
|
-
interface MeilisearchSettings {
|
13
|
-
searchableAttributes?: string[];
|
14
|
-
sortableAttributes?: string[];
|
15
|
-
}
|
16
|
-
|
17
|
-
interface MeilisearchResponse {
|
18
|
-
hits: Array<{
|
19
|
-
createdAt: string;
|
20
|
-
query: string;
|
21
|
-
purpose: string;
|
22
|
-
data?: any;
|
23
|
-
chunks: Array<{
|
24
|
-
content: string;
|
25
|
-
embedding: number[];
|
26
|
-
}>;
|
27
|
-
}>;
|
28
|
-
}
|
29
|
-
|
30
|
-
interface ProcessedChunk {
|
31
|
-
content: string;
|
32
|
-
embedding: number[];
|
33
|
-
}
|
34
|
-
|
35
|
-
/**
|
36
|
-
* Handles persistent memory storage using Meilisearch API
|
37
|
-
*/
|
38
|
-
export class PersistentMemory {
|
39
|
-
private readonly host: string;
|
40
|
-
private readonly apiKey: string;
|
41
|
-
private readonly INDEX_PREFIX: string;
|
42
|
-
private readonly embeddingModel: EmbeddingModel<string>;
|
43
|
-
constructor(options: {
|
44
|
-
host: string;
|
45
|
-
apiKey: string;
|
46
|
-
indexPrefix?: string;
|
47
|
-
embeddingModel: EmbeddingModel<string>;
|
48
|
-
}) {
|
49
|
-
this.host = options.host;
|
50
|
-
this.apiKey = options.apiKey;
|
51
|
-
this.INDEX_PREFIX = options.indexPrefix || "memory";
|
52
|
-
this.embeddingModel = options.embeddingModel;
|
53
|
-
}
|
54
|
-
|
55
|
-
/**
|
56
|
-
* Initialize indexes
|
57
|
-
*/
|
58
|
-
async init() {
|
59
|
-
try {
|
60
|
-
// Create or get main index
|
61
|
-
await this._getOrCreateIndex(this.INDEX_PREFIX);
|
62
|
-
console.log(`✅ Index '${this.INDEX_PREFIX}' initialized successfully`);
|
63
|
-
} catch (error) {
|
64
|
-
console.error(`❌ Failed to initialize index: ${error}`);
|
65
|
-
throw error;
|
66
|
-
}
|
67
|
-
}
|
68
|
-
|
69
|
-
/**
|
70
|
-
* Make API request to Meilisearch
|
71
|
-
*/
|
72
|
-
private async _makeRequest<T = unknown>(
|
73
|
-
path: string,
|
74
|
-
options: RequestInit = {}
|
75
|
-
): Promise<T> {
|
76
|
-
const url = `${this.host}${path}`;
|
77
|
-
console.log("🔍 Making request to Meilisearch:", url);
|
78
|
-
const response = await fetch(url, {
|
79
|
-
...options,
|
80
|
-
headers: {
|
81
|
-
"Content-Type": "application/json",
|
82
|
-
Authorization: `Bearer ${this.apiKey}`,
|
83
|
-
...options.headers,
|
84
|
-
},
|
85
|
-
});
|
86
|
-
|
87
|
-
if (!response.ok) {
|
88
|
-
console.log({ response });
|
89
|
-
throw new Error(`Meilisearch API error: ${response.statusText}`);
|
90
|
-
}
|
91
|
-
|
92
|
-
return response.json() as Promise<T>;
|
93
|
-
}
|
94
|
-
|
95
|
-
/**
|
96
|
-
* Get or create an index with proper settings
|
97
|
-
*/
|
98
|
-
private async _getOrCreateIndex(indexName: string) {
|
99
|
-
try {
|
100
|
-
// Check if index exists first
|
101
|
-
const indexExists = await this._makeRequest(`/indexes/${indexName}`, {
|
102
|
-
method: "GET",
|
103
|
-
}).catch(() => false);
|
104
|
-
|
105
|
-
if (!indexExists) {
|
106
|
-
console.log(`Creating new index: ${indexName}`);
|
107
|
-
await this._makeRequest("/indexes", {
|
108
|
-
method: "POST",
|
109
|
-
body: JSON.stringify({
|
110
|
-
uid: indexName,
|
111
|
-
primaryKey: "id",
|
112
|
-
}),
|
113
|
-
});
|
114
|
-
}
|
115
|
-
|
116
|
-
// Update index settings
|
117
|
-
const settings: MeilisearchSettings = {
|
118
|
-
searchableAttributes: ["query", "purpose", "chunks.content"],
|
119
|
-
sortableAttributes: ["createdAt"],
|
120
|
-
};
|
121
|
-
|
122
|
-
await this._makeRequest(`/indexes/${indexName}/settings`, {
|
123
|
-
method: "PATCH",
|
124
|
-
body: JSON.stringify(settings),
|
125
|
-
});
|
126
|
-
|
127
|
-
console.log(`Index ${indexName} configured successfully`);
|
128
|
-
} catch (error: any) {
|
129
|
-
console.error(`Failed to configure index ${indexName}:`, error);
|
130
|
-
throw error;
|
131
|
-
}
|
132
|
-
}
|
133
|
-
|
134
|
-
async processContent(content: string): Promise<ProcessedChunk[]> {
|
135
|
-
// Split content into chunks
|
136
|
-
const textSplitter = new RecursiveCharacterTextSplitter({
|
137
|
-
chunkSize: 1000,
|
138
|
-
});
|
139
|
-
const chunks = await textSplitter.createDocuments([content]);
|
140
|
-
|
141
|
-
// Generate embeddings for all chunks
|
142
|
-
const { embeddings } = await embedMany({
|
143
|
-
model: this.embeddingModel,
|
144
|
-
values: chunks.map((chunk) => chunk.pageContent),
|
145
|
-
});
|
146
|
-
|
147
|
-
// Create processed chunks with embeddings
|
148
|
-
return chunks.map((chunk, i) => ({
|
149
|
-
content: chunk.pageContent,
|
150
|
-
embedding: embeddings[i],
|
151
|
-
}));
|
152
|
-
}
|
153
|
-
|
154
|
-
/**
|
155
|
-
* Store a memory in the database
|
156
|
-
*/
|
157
|
-
async createMemory(memory: LongTermMemory) {
|
158
|
-
try {
|
159
|
-
console.log(`📝 Creating memory in index: ${this.INDEX_PREFIX}`);
|
160
|
-
|
161
|
-
// Process content into chunks with embeddings
|
162
|
-
const chunks = await this.processContent(memory.data);
|
163
|
-
|
164
|
-
// Generate unique ID if not provided
|
165
|
-
const id = memory.id || crypto.randomUUID();
|
166
|
-
|
167
|
-
const document = {
|
168
|
-
...memory,
|
169
|
-
chunks,
|
170
|
-
createdAt: memory.createdAt.toISOString(),
|
171
|
-
};
|
172
|
-
|
173
|
-
const response = await this._makeRequest(
|
174
|
-
`/indexes/${this.INDEX_PREFIX}/documents`,
|
175
|
-
{
|
176
|
-
method: "POST",
|
177
|
-
body: JSON.stringify([document]),
|
178
|
-
}
|
179
|
-
);
|
180
|
-
|
181
|
-
console.log("✅ Memory created successfully", { id });
|
182
|
-
return response;
|
183
|
-
} catch (error) {
|
184
|
-
console.error("❌ Failed to create memory:", error);
|
185
|
-
throw error;
|
186
|
-
}
|
187
|
-
}
|
188
|
-
|
189
|
-
/**
|
190
|
-
* Find best matching memories
|
191
|
-
*/
|
192
|
-
async findRelevantDocuments(query: string, options: SearchOptions = {}) {
|
193
|
-
console.log(`\n🔍 Searching in index: ${this.INDEX_PREFIX}`);
|
194
|
-
console.log("Query:", query);
|
195
|
-
|
196
|
-
try {
|
197
|
-
// Generate embedding for the query
|
198
|
-
const { embedding: queryEmbedding } = await embed({
|
199
|
-
model: this.embeddingModel,
|
200
|
-
value: query,
|
201
|
-
});
|
202
|
-
|
203
|
-
// Search in the index
|
204
|
-
const searchResults = await this._makeRequest<MeilisearchResponse>(
|
205
|
-
`/indexes/${this.INDEX_PREFIX}/search`,
|
206
|
-
{
|
207
|
-
method: "POST",
|
208
|
-
body: JSON.stringify({
|
209
|
-
q: query,
|
210
|
-
limit: options.maxResults || 10,
|
211
|
-
}),
|
212
|
-
}
|
213
|
-
);
|
214
|
-
|
215
|
-
if (!searchResults?.hits?.length) {
|
216
|
-
console.log("❌ No matches found");
|
217
|
-
return [];
|
218
|
-
}
|
219
|
-
|
220
|
-
// Process and filter results using cosine similarity
|
221
|
-
const results = searchResults.hits
|
222
|
-
.flatMap((hit) => {
|
223
|
-
const chunkSimilarities = hit.chunks.map((chunk) => ({
|
224
|
-
query: hit.query,
|
225
|
-
data: hit.data,
|
226
|
-
similarityPercentage:
|
227
|
-
(cosineSimilarity(queryEmbedding, chunk.embedding) + 1) * 50,
|
228
|
-
createdAt: hit.createdAt,
|
229
|
-
}));
|
230
|
-
|
231
|
-
return chunkSimilarities.reduce(
|
232
|
-
(best, current) =>
|
233
|
-
current.similarityPercentage > best.similarityPercentage
|
234
|
-
? current
|
235
|
-
: best,
|
236
|
-
chunkSimilarities[0]
|
237
|
-
);
|
238
|
-
})
|
239
|
-
.filter(
|
240
|
-
(match) =>
|
241
|
-
match.similarityPercentage >= (options.similarityThreshold || 70)
|
242
|
-
)
|
243
|
-
.sort((a, b) => b.similarityPercentage - a.similarityPercentage);
|
244
|
-
|
245
|
-
console.log(`✨ Found ${results.length} relevant matches`);
|
246
|
-
return results.map((result) => ({
|
247
|
-
query: result.query,
|
248
|
-
data: result.data,
|
249
|
-
createdAt: result.createdAt,
|
250
|
-
}));
|
251
|
-
} catch (error) {
|
252
|
-
console.error("❌ Search failed:", error);
|
253
|
-
return [];
|
254
|
-
}
|
255
|
-
}
|
256
|
-
|
257
|
-
/**
|
258
|
-
* Delete memories for a given scope and user
|
259
|
-
*/
|
260
|
-
async deleteMemories() {
|
261
|
-
return this._makeRequest(`/indexes/${this.INDEX_PREFIX}`, {
|
262
|
-
method: "DELETE",
|
263
|
-
});
|
264
|
-
}
|
265
|
-
}
|
package/script.js
DELETED
@@ -1,167 +0,0 @@
|
|
1
|
-
// Dimensions de l'espace SVG
|
2
|
-
const width = 800;
|
3
|
-
const height = 600;
|
4
|
-
|
5
|
-
// Exemple de données pour les nœuds et les arêtes
|
6
|
-
const nodes = [
|
7
|
-
{ id: "fetchData", name: "Fetch Data", group: 1, selected: false },
|
8
|
-
{ id: "analyzeData", name: "Analyze Data", group: 1, selected: false },
|
9
|
-
{ id: "sendAlert", name: "Send Alert", group: 1, selected: false },
|
10
|
-
];
|
11
|
-
|
12
|
-
const links = [
|
13
|
-
{ source: "fetchData", target: "analyzeData" },
|
14
|
-
{ source: "analyzeData", target: "sendAlert" },
|
15
|
-
];
|
16
|
-
|
17
|
-
// Simulation de force
|
18
|
-
const simulation = d3
|
19
|
-
.forceSimulation(nodes)
|
20
|
-
.force(
|
21
|
-
"link",
|
22
|
-
d3.forceLink(links).id((d) => d.id)
|
23
|
-
)
|
24
|
-
.force("charge", d3.forceManyBody().strength(-300))
|
25
|
-
.force("center", d3.forceCenter(width / 2, height / 2));
|
26
|
-
|
27
|
-
// Créer le conteneur SVG
|
28
|
-
const svg = d3.select("#graph").attr("width", width).attr("height", height);
|
29
|
-
|
30
|
-
// Groupes pour liens et nœuds
|
31
|
-
const linkGroup = svg
|
32
|
-
.append("g")
|
33
|
-
.attr("class", "links")
|
34
|
-
.attr("stroke", "#999")
|
35
|
-
.attr("stroke-opacity", 0.6);
|
36
|
-
|
37
|
-
const nodeGroup = svg.append("g").attr("class", "nodes");
|
38
|
-
|
39
|
-
// Fonction pour mettre à jour le graphe
|
40
|
-
function updateGraph() {
|
41
|
-
// Mettre à jour les liens
|
42
|
-
const link = linkGroup.selectAll("line").data(links);
|
43
|
-
|
44
|
-
link
|
45
|
-
.enter()
|
46
|
-
.append("line")
|
47
|
-
.attr("stroke-width", 2)
|
48
|
-
.merge(link)
|
49
|
-
.attr("x1", (d) => d.source.x)
|
50
|
-
.attr("y1", (d) => d.source.y)
|
51
|
-
.attr("x2", (d) => d.target.x)
|
52
|
-
.attr("y2", (d) => d.target.y);
|
53
|
-
|
54
|
-
link.exit().remove();
|
55
|
-
|
56
|
-
// Mettre à jour les nœuds
|
57
|
-
const node = nodeGroup.selectAll("circle").data(nodes, (d) => d.id);
|
58
|
-
|
59
|
-
node.exit().remove();
|
60
|
-
|
61
|
-
const nodeEnter = node
|
62
|
-
.enter()
|
63
|
-
.append("circle")
|
64
|
-
.attr("r", 20)
|
65
|
-
.attr("fill", (d) => (d.selected ? "orange" : "#69b3a2"))
|
66
|
-
.attr("stroke", "#fff")
|
67
|
-
.attr("stroke-width", 1.5)
|
68
|
-
.call(
|
69
|
-
d3
|
70
|
-
.drag()
|
71
|
-
.on("start", dragstarted)
|
72
|
-
.on("drag", dragged)
|
73
|
-
.on("end", dragended)
|
74
|
-
)
|
75
|
-
.on("click", nodeClicked);
|
76
|
-
|
77
|
-
nodeEnter
|
78
|
-
.merge(node)
|
79
|
-
.attr("cx", (d) => d.x)
|
80
|
-
.attr("cy", (d) => d.y)
|
81
|
-
.attr("fill", (d) => (d.selected ? "orange" : "#69b3a2"));
|
82
|
-
|
83
|
-
// Ajouter des labels
|
84
|
-
const label = nodeGroup.selectAll("text").data(nodes);
|
85
|
-
|
86
|
-
label.exit().remove();
|
87
|
-
|
88
|
-
label
|
89
|
-
.enter()
|
90
|
-
.append("text")
|
91
|
-
.attr("dy", 4)
|
92
|
-
.attr("dx", 25)
|
93
|
-
.merge(label)
|
94
|
-
.attr("x", (d) => d.x)
|
95
|
-
.attr("y", (d) => d.y)
|
96
|
-
.text((d) => d.name);
|
97
|
-
|
98
|
-
simulation.on("tick", () => {
|
99
|
-
link
|
100
|
-
.attr("x1", (d) => d.source.x)
|
101
|
-
.attr("y1", (d) => d.source.y)
|
102
|
-
.attr("x2", (d) => d.target.x)
|
103
|
-
.attr("y2", (d) => d.target.y);
|
104
|
-
|
105
|
-
node.attr("cx", (d) => d.x).attr("cy", (d) => d.y);
|
106
|
-
|
107
|
-
label.attr("x", (d) => d.x + 25).attr("y", (d) => d.y);
|
108
|
-
});
|
109
|
-
|
110
|
-
updateWorkflowOrder();
|
111
|
-
}
|
112
|
-
|
113
|
-
// Fonction pour mettre à jour l'ordre du workflow
|
114
|
-
function updateWorkflowOrder() {
|
115
|
-
const selectedNodes = nodes.filter((node) => node.selected);
|
116
|
-
if (selectedNodes.length > 0) {
|
117
|
-
workflowOrder = selectedNodes.map((node) => node.name);
|
118
|
-
} else {
|
119
|
-
const startNode = nodes.find(
|
120
|
-
(node) => !links.some((link) => link.target === node.id)
|
121
|
-
);
|
122
|
-
|
123
|
-
if (!startNode) {
|
124
|
-
workflowOrder = [];
|
125
|
-
console.log("Workflow Order: []");
|
126
|
-
return;
|
127
|
-
}
|
128
|
-
|
129
|
-
workflowOrder = [];
|
130
|
-
let currentNode = startNode;
|
131
|
-
while (currentNode) {
|
132
|
-
workflowOrder.push(currentNode.name);
|
133
|
-
const nextLink = links.find((link) => link.source === currentNode.id);
|
134
|
-
currentNode = nextLink
|
135
|
-
? nodes.find((node) => node.id === nextLink.target)
|
136
|
-
: null;
|
137
|
-
}
|
138
|
-
}
|
139
|
-
console.log("Workflow Order:", workflowOrder);
|
140
|
-
}
|
141
|
-
|
142
|
-
// Gestion de la sélection multiple
|
143
|
-
function nodeClicked(event, node) {
|
144
|
-
node.selected = !node.selected;
|
145
|
-
updateGraph();
|
146
|
-
}
|
147
|
-
|
148
|
-
// Gestion du drag & drop
|
149
|
-
function dragstarted(event, d) {
|
150
|
-
if (!event.active) simulation.alphaTarget(0.3).restart();
|
151
|
-
d.fx = d.x;
|
152
|
-
d.fy = d.y;
|
153
|
-
}
|
154
|
-
|
155
|
-
function dragged(event, d) {
|
156
|
-
d.fx = event.x;
|
157
|
-
d.fy = event.y;
|
158
|
-
}
|
159
|
-
|
160
|
-
function dragended(event, d) {
|
161
|
-
if (!event.active) simulation.alphaTarget(0);
|
162
|
-
d.fx = null;
|
163
|
-
d.fy = null;
|
164
|
-
}
|
165
|
-
|
166
|
-
// Initialisation
|
167
|
-
updateGraph();
|