agent99 0.0.3 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/A2A_SPEC-dev.md +1829 -0
  3. data/CHANGELOG.md +38 -0
  4. data/COMMITS.md +196 -0
  5. data/DOCS.md +96 -0
  6. data/README.md +212 -84
  7. data/Rakefile +62 -0
  8. data/docs/AI/htm.md +215 -0
  9. data/docs/AI/htm.rb +141 -0
  10. data/docs/AI/htm_demo.db +0 -0
  11. data/docs/AI/notes_on_htm_implementation.md +1319 -0
  12. data/docs/AI/some_code.rb +692 -0
  13. data/docs/advanced-topics/a2a-protocol.md +13 -0
  14. data/docs/{advanced_features.md → advanced-topics/advanced-features.md} +9 -4
  15. data/docs/{control_actions.md → advanced-topics/control-actions.md} +2 -0
  16. data/docs/advanced-topics/model-context-protocol.md +4 -0
  17. data/docs/advanced-topics/multi-agent-processing.md +674 -0
  18. data/docs/agent-development/request-response-handling.md +512 -0
  19. data/docs/agent99_framework/central_registry.md +94 -0
  20. data/docs/agent99_framework/message_client.md +120 -0
  21. data/docs/agent99_framework/registry_client.md +119 -0
  22. data/docs/api-reference/agent99-base.md +463 -0
  23. data/docs/api-reference/message-clients.md +495 -0
  24. data/docs/{api_reference.md → api-reference/overview.md} +14 -4
  25. data/docs/api-reference/registry-client.md +470 -0
  26. data/docs/api-reference/schemas.md +518 -0
  27. data/docs/assets/css/custom.css +27 -0
  28. data/docs/assets/images/agent-lifecycle.svg +73 -0
  29. data/docs/assets/images/agent-registry-process.svg +86 -0
  30. data/docs/assets/images/agent-registry-processes.svg +114 -0
  31. data/docs/assets/images/agent-types-overview.svg +51 -0
  32. data/docs/assets/images/agent99-architecture.svg +85 -0
  33. data/docs/assets/images/agent99_logo.png +0 -0
  34. data/docs/assets/images/control-actions-state.svg +83 -0
  35. data/docs/assets/images/knowledge-graph.svg +77 -0
  36. data/docs/assets/images/message-processing-flow.svg +148 -0
  37. data/docs/assets/images/multi-agent-system.svg +66 -0
  38. data/docs/assets/images/proxy-pattern-sequence.svg +48 -0
  39. data/docs/assets/images/request-flow.svg +97 -0
  40. data/docs/assets/images/request-processing-lifecycle.svg +50 -0
  41. data/docs/assets/images/request-response-sequence.svg +39 -0
  42. data/docs/{agent_lifecycle.md → core-concepts/agent-lifecycle.md} +2 -0
  43. data/docs/core-concepts/agent-types.md +255 -0
  44. data/docs/{architecture.md → core-concepts/architecture.md} +5 -5
  45. data/docs/core-concepts/what-is-an-agent.md +293 -0
  46. data/docs/diagrams/message-flow-sequence.svg +198 -0
  47. data/docs/diagrams/p2p-network-topology.svg +181 -0
  48. data/docs/diagrams/smart-transport-routing.svg +165 -0
  49. data/docs/diagrams/three-layer-architecture.svg +77 -0
  50. data/docs/diagrams/transport-extension-api.svg +309 -0
  51. data/docs/diagrams/transport-extension-architecture.svg +234 -0
  52. data/docs/diagrams/transport-selection-flowchart.svg +264 -0
  53. data/docs/examples/advanced-examples.md +951 -0
  54. data/docs/examples/basic-examples.md +268 -0
  55. data/docs/{agent_discovery.md → framework-components/agent-discovery.md} +9 -5
  56. data/docs/{agent_registry_processes.md → framework-components/agent-registry.md} +9 -3
  57. data/docs/{message_processing.md → framework-components/message-processing.md} +3 -1
  58. data/docs/getting-started/basic-example.md +306 -0
  59. data/docs/getting-started/installation.md +160 -0
  60. data/docs/getting-started/overview.md +64 -0
  61. data/docs/getting-started/quick-start.md +179 -0
  62. data/docs/index.md +97 -0
  63. data/docs/operations/breaking-changes.md +26 -0
  64. data/examples/DEMO.md +148 -0
  65. data/examples/README.md +50 -0
  66. data/examples/agent_watcher.rb +5 -1
  67. data/examples/bad_agent.rb +32 -0
  68. data/examples/chief_agent.rb +17 -6
  69. data/examples/control.rb +16 -7
  70. data/examples/example_agent.rb +16 -3
  71. data/examples/maxwell_agent86.rb +15 -26
  72. data/examples/registry.rb +10 -9
  73. data/examples/run_demo.rb +433 -0
  74. data/lib/agent99/agent_discovery.rb +4 -0
  75. data/lib/agent99/agent_lifecycle.rb +34 -10
  76. data/lib/agent99/amqp_message_client.rb +2 -2
  77. data/lib/agent99/base.rb +6 -2
  78. data/lib/agent99/message_processing.rb +6 -10
  79. data/lib/agent99/registry_client.rb +15 -11
  80. data/lib/agent99/tcp_message_client.rb +183 -0
  81. data/lib/agent99/version.rb +1 -1
  82. data/lib/agent99.rb +1 -1
  83. data/mkdocs.yml +195 -0
  84. data/p2p_plan.md +533 -0
  85. data/p2p_roadmap.md +299 -0
  86. data/registry_plan.md +1818 -0
  87. metadata +93 -30
  88. data/docs/README.md +0 -57
  89. data/docs/diagrams/agent_registry_processes.dot +0 -42
  90. data/docs/diagrams/agent_registry_processes.png +0 -0
  91. data/docs/diagrams/high_level_architecture.dot +0 -26
  92. data/docs/diagrams/high_level_architecture.png +0 -0
  93. data/docs/diagrams/request_flow.dot +0 -42
  94. data/docs/diagrams/request_flow.png +0 -0
  95. /data/docs/{extending_the_framework.md → advanced-topics/extending-the-framework.md} +0 -0
  96. /data/docs/{custom_agent_implementation.md → agent-development/custom-agent-implementation.md} +0 -0
  97. /data/docs/{error_handling_and_logging.md → agent-development/error-handling-and-logging.md} +0 -0
  98. /data/docs/{schema_definition.md → agent-development/schema-definition.md} +0 -0
  99. /data/docs/{messaging_system.md → framework-components/messaging-system.md} +0 -0
  100. /data/docs/{configuration.md → operations/configuration.md} +0 -0
  101. /data/docs/{preformance_considerations.md → operations/performance-considerations.md} +0 -0
  102. /data/docs/{security.md → operations/security.md} +0 -0
  103. /data/docs/{troubleshooting.md → operations/troubleshooting.md} +0 -0
@@ -0,0 +1,1319 @@
1
+
2
+ ruby-12-15 18:49:23] INFO: #<AIA::Config arguments=#<Hashie::Array ["ruby_expert"]> backend="mods" chat?=true completion=nil config_file=nil debug?=false directives=#<Hashie::Array []> dump_file=nil edit?=false erb?=false extra="" fuzzy?=false help?=false image_quality="" image_size="" log_file=#<Pathname:/Users/dewayne/.prompts/_prompts.log> markdown?=true model="gpt-4o-mini" next="" out_file=#<IO:<STDOUT>> pipeline=#<Hashie::Array []> prompts_dir=#<Pathname:/Users/dewayne/.prompts> render?=false role="" roles_dir=#<Pathname:/Users/dewayne/.prompts/roles> shell?=false speak?=false speech_model="tts-1" terse?=false transcription_model="wisper-1" verbose?=true version?=false voice="alloy">
3
+
4
+
5
+ [2024-12-15 18:51:14] INFO: PROMPT ID ruby_expert
6
+ PATH: /Users/dewayne/.prompts/ruby_expert.txt
7
+ KEYWORDS: [DO_WHAT]
8
+
9
+ As an experienced Ruby software engineer when giving tasks involving the Ruby programming language, use modern Ruby 3.3 syntax, especially for hashes and method signatures with named parameters when generating Ruby source code. Whe you do generate Ruby source code I want the following formatting to be used. Consecutive assignment statements will have theirh "=" character in the same column. This also applies for the the insert operator "<<" as well. When formatting a Hash statement all values will start in the same column.
10
+
11
+ I would like to talk through an idean that I have for implemenmtion something like heirarchical temporal memory at the database level. do you know what HTM is
12
+
13
+ RESULT:
14
+ Yes, I'm familiar with Hierarchical Temporal Memory (HTM). HTM is a machine learning
15
+ technology that aims to capture the structural and algorithmic properties of the neocortex in
16
+ the human brain. It's designed to model temporal sequences of patterns and make predictions
17
+ based on learned sequences.
18
+
19
+ The key features of HTM include:
20
+
21
+ 1. Sparse Distributed Representations
22
+ 2. Temporal learning
23
+ 3. Hierarchical structure
24
+ 4. Online learning
25
+ 5. Anomaly detection
26
+
27
+ Implementing HTM at the database level is an interesting concept. It could potentially allow
28
+ for more intelligent data storage, retrieval, and analysis directly within the database
29
+ system. This could lead to more efficient processing of time-series data, better pattern
30
+ recognition, and improved predictive capabilities built into the database itself.
31
+
32
+ Would you like to discuss specific aspects of how you're thinking of implementing HTM at the
33
+ database level? For example:
34
+
35
+ 1. How would you represent the hierarchical structure in the database schema?
36
+ 2. Are you considering implementing the learning algorithms within the database, or just the
37
+ data structure?
38
+ 3. What kind of queries or operations do you envision for interacting with the HTM-like
39
+ structure?
40
+ 4. Are there specific use cases or types of data you're targeting with this implementation?
41
+
42
+ Let me know which aspects you'd like to explore further, and I'd be happy to discuss them in
43
+ more detail.
44
+
45
+
46
+
47
+
48
+
49
+ [2024-12-15 18:56:41] INFO: Follow Up:
50
+ I was thinking about using knowledge graphs to represent a topic of discourse based upon the idea that I can construct a KG that spans the range of detail about the topic from most general to most detailed. what do you thing about that?
51
+
52
+
53
+
54
+ [2024-12-15 18:56:41] INFO: Response:
55
+ That's an intriguing approach! Using knowledge graphs to represent a topic of discourse with
56
+ varying levels of detail is a powerful idea. It aligns well with the hierarchical nature of
57
+ HTM and could provide a flexible, scalable way to represent and navigate complex information.
58
+ Let's explore this concept further:
59
+
60
+ Advantages of this approach:
61
+
62
+ 1. Hierarchical Representation: Knowledge graphs naturally support hierarchical structures,
63
+ which aligns well with the HTM concept.
64
+
65
+ 2. Flexibility: You can easily add new nodes and relationships at any level of detail.
66
+
67
+ 3. Contextual Understanding: The relationships between concepts at different levels can
68
+ provide rich context.
69
+
70
+ 4. Scalability: Knowledge graphs can handle large amounts of interconnected data efficiently.
71
+
72
+ 5. Query Flexibility: Graph databases allow for complex queries that can traverse the
73
+ hierarchy efficiently.
74
+
75
+ Implementation considerations:
76
+
77
+ 1. Graph Database: You might want to use a graph database like Neo4j or Amazon Neptune to
78
+ store and query your knowledge graph efficiently.
79
+
80
+ 2. Node Types: You could have different node types representing different levels of
81
+ abstraction or detail.
82
+
83
+ 3. Edge Types: Define relationships that connect nodes both horizontally (related concepts)
84
+ and vertically (more general/more specific).
85
+
86
+ 4. Metadata: Include metadata on nodes to indicate their level of detail or abstraction.
87
+
88
+ Here's a simple Ruby example of how you might start to model this:
89
+
90
+ ```ruby
91
+ class KnowledgeNode
92
+ attr_reader :id, :content, :detail_level
93
+
94
+ def initialize(id:, content:, detail_level:)
95
+ @id = id
96
+ @content = content
97
+ @detail_level = detail_level
98
+ @connections = {
99
+ more_general: [],
100
+ more_specific: [],
101
+ related: []
102
+ }
103
+ end
104
+
105
+ def add_connection(node:, relationship:)
106
+ @connections[relationship] << node
107
+ end
108
+ end
109
+
110
+ class KnowledgeGraph
111
+ def initialize
112
+ @nodes = {}
113
+ end
114
+
115
+ def add_node(node:)
116
+ @nodes[node.id] = node
117
+ end
118
+
119
+ def connect_nodes(from_id:, to_id:, relationship:)
120
+ from_node = @nodes[from_id]
121
+ to_node = @nodes[to_id]
122
+ from_node.add_connection(node: to_node, relationship: relationship)
123
+ end
124
+
125
+ def get_more_specific(node_id:)
126
+ @nodes[node_id].connections[:more_specific]
127
+ end
128
+
129
+ def get_more_general(node_id:)
130
+ @nodes[node_id].connections[:more_general]
131
+ end
132
+ end
133
+ ```
134
+
135
+ This basic structure allows you to create nodes with different levels of detail and connect
136
+ them in a hierarchical manner. You could expand on this to include methods for traversing the
137
+ graph, finding paths between concepts, or identifying clusters of related ideas.
138
+
139
+ Some challenges to consider:
140
+
141
+ 1. Maintaining Consistency: Ensuring that relationships between nodes at different levels
142
+ remain consistent as the graph grows.
143
+
144
+ 2. Scalability: As the graph grows, efficient querying and traversal become crucial.
145
+
146
+ 3. Ontology Design: Defining a clear ontology for your knowledge domain to guide the creation
147
+ and connection of nodes.
148
+
149
+ 4. Integration with HTM: Considering how to integrate this knowledge graph structure with
150
+ HTM's learning and prediction capabilities.
151
+
152
+ What are your thoughts on this approach? Do you see any specific challenges or opportunities
153
+ in implementing this for your use case?
154
+
155
+
156
+ [2024-12-15 19:03:35] INFO: Follow Up:
157
+ Are there any ruby gems that implement knowledge graphs
158
+
159
+
160
+ [2024-12-15 19:03:35] INFO: Response:
161
+ Yes, there are several Ruby gems that can help you work with knowledge graphs or implement
162
+ graph-like structures. While there isn't a gem specifically named "knowledge graph," there are
163
+ gems that provide graph database interfaces or graph data structures that could be used to
164
+ implement a knowledge graph. Here are a few options:
165
+
166
+ 1. Neo4j.rb
167
+ This is a Ruby wrapper for the Neo4j graph database. It's one of the most popular options for
168
+ working with graph structures in Ruby.
169
+
170
+ ```ruby
171
+ gem 'neo4j'
172
+ ```
173
+
174
+ Example usage:
175
+
176
+ ```ruby
177
+ require 'neo4j'
178
+
179
+ class Concept
180
+ include Neo4j::ActiveNode
181
+ property :name, type: String
182
+ property :detail_level, type: Integer
183
+
184
+ has_many :out, :more_specific, type: :SPECIALIZES, model_class: 'Concept'
185
+ has_many :in, :more_general, type: :SPECIALIZES, model_class: 'Concept'
186
+ end
187
+
188
+ # Create nodes
189
+ general = Concept.create(name: "Science", detail_level: 1)
190
+ specific = Concept.create(name: "Physics", detail_level: 2)
191
+
192
+ # Create relationship
193
+ general.more_specific << specific
194
+ ```
195
+
196
+ 2. Ruby-GraphViz
197
+ While primarily for visualization, it can be used to create and manipulate graph structures.
198
+
199
+ ```ruby
200
+ gem 'ruby-graphviz'
201
+ ```
202
+
203
+ Example usage:
204
+
205
+ ```ruby
206
+ require 'graphviz'
207
+
208
+ graph = GraphViz.new(:G, type: :digraph)
209
+
210
+ node1 = graph.add_nodes("Science")
211
+ node2 = graph.add_nodes("Physics")
212
+
213
+ graph.add_edges(node1, node2)
214
+
215
+ # See knowledge graph visualization at:
216
+ # docs/assets/images/knowledge-graph.svg
217
+ # graph.output(png: "knowledge_graph.png")
218
+ ```
219
+
220
+ ![Knowledge Graph Example](../assets/images/knowledge-graph.svg)
221
+
222
+ 3. RGL (Ruby Graph Library)
223
+ A pure Ruby graph library that provides a set of graph data structures and algorithms.
224
+
225
+ ```ruby
226
+ gem 'rgl'
227
+ ```
228
+
229
+ Example usage:
230
+
231
+ ```ruby
232
+ require 'rgl/adjacency'
233
+ require 'rgl/dot'
234
+
235
+ graph = RGL::DirectedAdjacencyGraph.new
236
+
237
+ graph.add_edge('Science', 'Physics')
238
+ graph.add_edge('Physics', 'Quantum Mechanics')
239
+
240
+ graph.write_to_graphic_file('jpg')
241
+ ```
242
+
243
+ 4. OrientDB-JRuby
244
+ If you're using JRuby, this gem provides access to OrientDB, a multi-model database that
245
+ supports graph structures.
246
+
247
+ ```ruby
248
+ gem 'orientdb'
249
+ ```
250
+
251
+ Example usage:
252
+
253
+ ```ruby
254
+ require 'orientdb'
255
+
256
+ database = OrientDB::Database.new(url: "remote:localhost/knowledge_graph")
257
+
258
+ database.create_vertex_type('Concept')
259
+
260
+ science = database.create_vertex('Concept', name: 'Science', detail_level: 1)
261
+ physics = database.create_vertex('Concept', name: 'Physics', detail_level: 2)
262
+
263
+ database.create_edge('Specializes', science, physics)
264
+ ```
265
+
266
+ While these gems don't implement knowledge graphs directly, they provide the building blocks
267
+ you'd need to create one. You'd likely need to build additional abstraction layers on top of
268
+ these to implement the specific semantics and operations of a knowledge graph for your use
269
+ case.
270
+
271
+ Remember to choose the gem that best fits your specific requirements, considering factors like
272
+ performance, ease of use, and whether you need a full database solution or just an in-memory
273
+ graph structure.
274
+
275
+
276
+ [2024-12-15 19:06:02] INFO: Follow Up:
277
+ is it fair to posit that within the temporal component the most detailed knowledge nodes are forgotten first before the more general nodes.
278
+
279
+
280
+ [2024-12-15 19:06:02] INFO: Response:
281
+ That's an insightful observation, and it aligns well with both cognitive science research and
282
+ practical considerations in knowledge management. Let's explore this idea:
283
+
284
+ 1. Cognitive Science Perspective:
285
+ Research in human memory and learning suggests that general concepts tend to be more resilient
286
+ than specific details. This phenomenon is often referred to as the "gist" or "fuzzy-trace"
287
+ theory of memory.
288
+
289
+ 2. Information Theory:
290
+ More general nodes typically contain less specific information, making them more compressible
291
+ and potentially easier to retain.
292
+
293
+ 3. Practical Knowledge Management:
294
+ In many systems, retaining high-level concepts while allowing low-level details to expire can
295
+ be an efficient strategy for managing information over time.
296
+
297
+ Implementing this concept in a Ruby-based knowledge graph system could look something like
298
+ this:
299
+
300
+ ```ruby
301
+ class KnowledgeNode
302
+ attr_reader :id, :content, :detail_level, :last_accessed
303
+ def initialize(id:, content:, detail_level:)
304
+ @id = id
305
+ @content = content
306
+ @detail_level = detail_level
307
+ @last_accessed = Time.now
308
+ @connections = {
309
+ more_general: [],
310
+ more_specific: [],
311
+ related: []
312
+ }
313
+ end
314
+
315
+ def access
316
+ @last_accessed = Time.now
317
+ end
318
+
319
+ def forgettable?(threshold)
320
+ Time.now - @last_accessed > threshold * (1.0 / @detail_level)
321
+ end
322
+ end
323
+
324
+ class TemporalKnowledgeGraph
325
+ def initialize(forget_threshold: 30 * 24 * 60 * 60) # 30 days in seconds
326
+ @nodes = {}
327
+ @forget_threshold = forget_threshold
328
+ end
329
+
330
+ def add_node(node:)
331
+ @nodes[node.id] = node
332
+ end
333
+
334
+ def access_node(id:)
335
+ node = @nodes[id]
336
+ node.access if node
337
+ node
338
+ end
339
+
340
+ def forget_old_nodes
341
+ @nodes.delete_if do |id, node|
342
+ node.forgettable?(@forget_threshold)
343
+ end
344
+ end
345
+
346
+ def connect_nodes(from_id:, to_id:, relationship:)
347
+ from_node = @nodes[from_id]
348
+ to_node = @nodes[to_id]
349
+ from_node.connections[relationship] << to_node if from_node && to_node
350
+ end
351
+ end
352
+
353
+ # Usage
354
+ graph = TemporalKnowledgeGraph.new(forget_threshold: 60 * 60 * 24) # 1 day
355
+
356
+ node1 = KnowledgeNode.new(id: 1, content: "Science", detail_level: 1)
357
+ node2 = KnowledgeNode.new(id: 2, content: "Physics", detail_level: 2)
358
+ node3 = KnowledgeNode.new(id: 3, content: "Quantum Entanglement", detail_level: 3)
359
+
360
+ graph.add_node(node: node1)
361
+ graph.add_node(node: node2)
362
+ graph.add_node(node: node3)
363
+
364
+ graph.connect_nodes(from_id: 1, to_id: 2, relationship: :more_specific)
365
+ graph.connect_nodes(from_id: 2, to_id: 3, relationship: :more_specific)
366
+
367
+ # Simulate passage of time and node access
368
+ sleep(2)
369
+ graph.access_node(id: 1)
370
+ graph.access_node(id: 2)
371
+
372
+ sleep(2)
373
+ graph.forget_old_nodes
374
+ # At this point, node3 might be forgotten, while node1 and node2 are retained
375
+ ```
376
+
377
+ This implementation introduces a `forgettable?` method that takes into account both the time
378
+ since last access and the detail level of the node. More detailed nodes (higher
379
+ `detail_level`) will be considered forgettable sooner than more general nodes.
380
+
381
+ Some considerations for this approach:
382
+
383
+ 1. Balancing Act: You'll need to fine-tune the forgetting threshold and the relationship
384
+ between detail level and forgetting speed.
385
+
386
+ 2. Contextual Importance: Some detailed nodes might be more important than others, regardless
387
+ of their detail level. You might want to introduce an "importance" factor.
388
+
389
+ 3. Cascading Forgetfulness: When a node is forgotten, you might want to update or remove
390
+ references to it in connected nodes.
391
+
392
+ 4. Relearning: Consider implementing a mechanism to "relearn" forgotten nodes if they become
393
+ relevant again.
394
+
395
+ 5. Persistence: If you're storing this graph in a database, you'll need to implement periodic
396
+ cleanup operations to remove forgotten nodes.
397
+
398
+ This approach provides a starting point for implementing a temporal aspect to your knowledge
399
+ graph, where more detailed information is more susceptible to being forgotten over time. It's
400
+ a complex topic with many nuances, and the exact implementation would depend on your specific
401
+ use case and requirements.
402
+
403
+
404
+ [2024-12-15 19:11:27] INFO: Follow Up:
405
+ The reason that I am looking at HTM is for application in retrieval augmented generation RAG in which information consistent with an LLM prompt is retrieved semantically from a presistant data store for inclusion as context to the prompt. The size of the context windows is often limited with regard to the amount of information by token count that can be added. I am thinking that HTM with its ability to forget information over time might lead to better results better in this case may mean quick responses
406
+
407
+
408
+ [2024-12-15 19:11:27] INFO: Response:
409
+ Your insight about using HTM principles for Retrieval Augmented Generation (RAG) is quite
410
+ innovative and could indeed lead to more efficient and effective context retrieval. Let's
411
+ explore how this could work and how it might be implemented in Ruby.
412
+
413
+ The key advantages of this approach for RAG would be:
414
+
415
+ 1. Temporal Relevance: More recent or frequently accessed information is prioritized.
416
+ 2. Hierarchical Context: Ability to provide a mix of general and specific information within
417
+ token limits.
418
+ 3. Adaptive Memory: The system can "forget" less relevant details, making room for new
419
+ information.
420
+
421
+ Here's a conceptual implementation in Ruby that combines HTM principles with RAG:
422
+
423
+ ```ruby
424
+ require 'set'
425
+
426
+ class HTMNode
427
+ attr_reader :id, :content, :detail_level, :last_accessed, :access_count
428
+
429
+ def initialize(id:, content:, detail_level:)
430
+ @id = id
431
+ @content = content
432
+ @detail_level = detail_level
433
+ @last_accessed = Time.now
434
+ @access_count = 0
435
+ @connections = Set.new
436
+ end
437
+
438
+ def access
439
+ @last_accessed = Time.now
440
+ @access_count += 1
441
+ end
442
+
443
+ def add_connection(node)
444
+ @connections.add(node)
445
+ end
446
+
447
+ def relevance_score(current_time)
448
+ time_factor = 1.0 / (current_time - @last_accessed)
449
+ detail_factor = 1.0 / @detail_level
450
+ access_factor = Math.log(@access_count + 1)
451
+ time_factor * detail_factor * access_factor
452
+ end
453
+ end
454
+
455
+ class HTMRAG
456
+ def initialize(forget_threshold: 30 * 24 * 60 * 60) # 30 days in seconds
457
+ @nodes = {}
458
+ @forget_threshold = forget_threshold
459
+ end
460
+
461
+ def add_node(node)
462
+ @nodes[node.id] = node
463
+ end
464
+
465
+ def connect_nodes(from_id, to_id)
466
+ @nodes[from_id].add_connection(@nodes[to_id])
467
+ end
468
+
469
+ def forget_old_nodes
470
+ current_time = Time.now
471
+ @nodes.delete_if do |_, node|
472
+ current_time - node.last_accessed > @forget_threshold
473
+ end
474
+ end
475
+
476
+ def retrieve_context(query, max_tokens: 1000)
477
+ relevant_nodes = find_relevant_nodes(query)
478
+ construct_context(relevant_nodes, max_tokens)
479
+ end
480
+
481
+ private
482
+
483
+ def find_relevant_nodes(query)
484
+ # This is a placeholder for semantic search
485
+ # In a real implementation, you'd use embeddings or other NLP techniques
486
+ @nodes.values.sort_by { |node| -node.relevance_score(Time.now) }
487
+ end
488
+
489
+ def construct_context(nodes, max_tokens)
490
+ context = ""
491
+ token_count = 0
492
+
493
+ nodes.each do |node|
494
+ break if token_count >= max_tokens
495
+
496
+ node_content = node.content
497
+ node_tokens = node_content.split.size # Simple tokenization
498
+
499
+ if token_count + node_tokens <= max_tokens
500
+ context += node_content + " "
501
+ token_count += node_tokens
502
+ node.access
503
+ else
504
+ remaining_tokens = max_tokens - token_count
505
+ truncated_content = node_content.split[0...remaining_tokens].join(' ')
506
+ context += truncated_content + " "
507
+ break
508
+ end
509
+ end
510
+
511
+ context.strip
512
+ end
513
+ end
514
+
515
+ # Usage example
516
+ rag = HTMRAG.new
517
+
518
+ node1 = HTMNode.new(id: 1, content: "AI is a broad field of computer science.", detail_level:
519
+ 1)
520
+ node2 = HTMNode.new(id: 2, content: "Machine Learning is a subset of AI focused on data-driven
521
+ algorithms.", detail_level: 2)
522
+ node3 = HTMNode.new(id: 3, content: "Neural networks are a type of machine learning model
523
+ inspired by biological neurons.", detail_level: 3)
524
+
525
+ rag.add_node(node1)
526
+ rag.add_node(node2)
527
+ rag.add_node(node3)
528
+
529
+ rag.connect_nodes(1, 2)
530
+ rag.connect_nodes(2, 3)
531
+
532
+ context = rag.retrieve_context("What is AI?", max_tokens: 50)
533
+ puts context
534
+ ```
535
+
536
+ This implementation incorporates several key HTM and RAG concepts:
537
+
538
+ 1. Hierarchical Structure: Nodes have a `detail_level` attribute.
539
+ 2. Temporal Aspect: Nodes track `last_accessed` time and `access_count`.
540
+ 3. Relevance Scoring: Combines recency, detail level, and access frequency.
541
+ 4. Forgetting Mechanism: Old nodes are removed based on a time threshold.
542
+ 5. Context Construction: Retrieves and combines relevant nodes within token limits.
543
+
544
+ To make this more effective for RAG:
545
+
546
+ 1. Semantic Search: Implement a proper semantic search for `find_relevant_nodes`, possibly
547
+ using embeddings.
548
+ 2. Smarter Tokenization: Use a proper tokenizer that aligns with your LLM.
549
+ 3. Adaptive Forgetting: Adjust the forgetting threshold based on system performance and data
550
+ volume.
551
+ 4. Contextual Connections: Enhance the connection mechanism to capture semantic relationships
552
+ between nodes.
553
+
554
+ This approach could indeed lead to quicker responses in RAG systems by:
555
+
556
+ 1. Prioritizing recent and frequently accessed information.
557
+ 2. Maintaining a balance between general and specific information.
558
+ 3. Automatically curating the knowledge base over time.
559
+ 4. Allowing for faster retrieval by maintaining a more focused set of nodes.
560
+
561
+ Remember, the effectiveness of this system would heavily depend on the quality of your
562
+ semantic search and the relevance scoring mechanism. You might need to experiment with
563
+ different scoring formulas and parameters to optimize for your specific use case.
564
+
565
+
566
+ [2024-12-15 19:17:29] INFO: Follow Up:
567
+ Instead of the common vectorization of the prompt and a semantic search of the database for the nearest neighbor based upon the vectorization, I was thinking along the lines of breaking the prompt up into a knowledge graph of propositions. I could then chose from the database those existing graphcs in which their sequences mose closely resembles the sequences in the prompts graph. does that make sense?
568
+
569
+
570
+ [2024-12-15 19:17:29] INFO: Response:
571
+ That's a fascinating and innovative approach! It makes a lot of sense and could potentially
572
+ offer some significant advantages over traditional vector-based semantic search. Let's break
573
+ down this concept and explore how it might be implemented in Ruby.
574
+
575
+ The key ideas in your approach are:
576
+
577
+ 1. Representing the prompt as a knowledge graph of propositions.
578
+ 2. Comparing the structure and sequence of this graph to existing graphs in the database.
579
+ 3. Selecting the most similar graphs for context retrieval.
580
+
581
+ This approach could indeed provide more nuanced and contextually relevant results, as it takes
582
+ into account the relationships and sequence of ideas, not just the overall semantic
583
+ similarity.
584
+
585
+ Here's a conceptual implementation in Ruby:
586
+
587
+ ```ruby
588
+ class Proposition
589
+ attr_reader :id, :content
590
+ attr_accessor :next, :related
591
+
592
+ def initialize(id:, content:)
593
+ @id = id
594
+ @content = content
595
+ @next = nil
596
+ @related = []
597
+ end
598
+ end
599
+
600
+ class PropositionGraph
601
+ attr_reader :propositions
602
+
603
+ def initialize
604
+ @propositions = {}
605
+ end
606
+
607
+ def add_proposition(prop)
608
+ @propositions[prop.id] = prop
609
+ end
610
+
611
+ def connect(from_id:, to_id:, relationship: :next)
612
+ from_prop = @propositions[from_id]
613
+ to_prop = @propositions[to_id]
614
+ if relationship == :next
615
+ from_prop.next = to_prop
616
+ else
617
+ from_prop.related << to_prop
618
+ end
619
+ end
620
+
621
+ def similarity_score(other_graph)
622
+ sequence_similarity = calculate_sequence_similarity(other_graph)
623
+ structure_similarity = calculate_structure_similarity(other_graph)
624
+ (sequence_similarity + structure_similarity) / 2.0
625
+ end
626
+
627
+ private
628
+
629
+ def calculate_sequence_similarity(other_graph)
630
+ # Implement sequence comparison logic here
631
+ # This could involve comparing the 'next' chains of both graphs
632
+ # Return a score between 0 and 1
633
+ end
634
+
635
+ def calculate_structure_similarity(other_graph)
636
+ # Implement structure comparison logic here
637
+ # This could involve comparing the 'related' connections of both graphs
638
+ # Return a score between 0 and 1
639
+ end
640
+ end
641
+
642
+ class GraphBasedRAG
643
+ def initialize
644
+ @stored_graphs = []
645
+ end
646
+
647
+ def add_graph(graph)
648
+ @stored_graphs << graph
649
+ end
650
+
651
+ def retrieve_context(prompt_graph, top_n: 3)
652
+ scored_graphs = @stored_graphs.map do |graph|
653
+ {
654
+ graph: graph,
655
+ score: graph.similarity_score(prompt_graph)
656
+ }
657
+ end
658
+
659
+ top_graphs = scored_graphs.sort_by { |g| -g[:score] }.take(top_n)
660
+ construct_context(top_graphs)
661
+ end
662
+
663
+ private
664
+
665
+ def construct_context(top_graphs)
666
+ # Implement logic to construct context from top graphs
667
+ # This could involve extracting key propositions or summarizing the graphs
668
+ end
669
+ end
670
+
671
+ # Usage example
672
+ rag = GraphBasedRAG.new
673
+
674
+ # Create and add some stored graphs
675
+ graph1 = PropositionGraph.new
676
+ prop1 = Proposition.new(id: 1, content: "AI is a field of computer science")
677
+ prop2 = Proposition.new(id: 2, content: "Machine Learning is a subset of AI")
678
+ graph1.add_proposition(prop1)
679
+ graph1.add_proposition(prop2)
680
+ graph1.connect(from_id: 1, to_id: 2)
681
+ rag.add_graph(graph1)
682
+
683
+ # ... Add more graphs ...
684
+
685
+ # Create a graph from the prompt
686
+ prompt_graph = PropositionGraph.new
687
+ prompt_prop1 = Proposition.new(id: 1, content: "What is AI")
688
+ prompt_prop2 = Proposition.new(id: 2, content: "How does it relate to Machine Learning")
689
+ prompt_graph.add_proposition(prompt_prop1)
690
+ prompt_graph.add_proposition(prompt_prop2)
691
+ prompt_graph.connect(from_id: 1, to_id: 2)
692
+
693
+ # Retrieve context
694
+ context = rag.retrieve_context(prompt_graph)
695
+ puts context
696
+ ```
697
+
698
+ This implementation provides a framework for your approach. Some key points:
699
+
700
+ 1. `Proposition` represents individual ideas or statements.
701
+ 2. `PropositionGraph` represents a network of related propositions.
702
+ 3. The `similarity_score` method in `PropositionGraph` compares both sequence and structure.
703
+ 4. `GraphBasedRAG` stores graphs and retrieves the most similar ones for a given prompt graph.
704
+
705
+ To make this system more effective:
706
+
707
+ 1. Implement sophisticated graph comparison algorithms in `calculate_sequence_similarity` and
708
+ `calculate_structure_similarity`.
709
+ 2. Develop a method to automatically convert natural language prompts into proposition graphs.
710
+ 3. Optimize the storage and retrieval of graphs for large-scale applications.
711
+ 4. Implement a method to extract or summarize relevant information from the retrieved graphs.
712
+
713
+ Advantages of this approach:
714
+
715
+ 1. Captures relationships between ideas, not just individual concepts.
716
+ 2. Can potentially handle complex queries more effectively.
717
+ 3. Might be better at maintaining context and coherence in retrieved information.
718
+
719
+ Challenges to consider:
720
+
721
+ 1. Complexity in converting natural language to proposition graphs.
722
+ 2. Potentially higher computational cost for graph comparisons.
723
+ 3. Need for sophisticated algorithms to handle graph similarity at scale.
724
+
725
+ This approach is innovative and has the potential to provide more contextually relevant
726
+ results for RAG systems, especially for complex queries where the relationship between
727
+ concepts is crucial. It would be particularly effective in domains where the sequence and
728
+ structure of information are as important as the content itself.
729
+
730
+
731
+ [2024-12-15 19:19:56] INFO: Follow Up:
732
+ are their graph-based extensions to PostgreSQL that we could use for this project?
733
+
734
+
735
+ [2024-12-15 19:19:56] INFO: Response:
736
+ Yes, there are indeed graph-based extensions for PostgreSQL that could be very useful for this
737
+ project. The most notable one is pgvector, which while not strictly graph-based, provides
738
+ vector operations that can be helpful in graph-like queries. However, for true graph
739
+ operations, we can look at a few options:
740
+
741
+ 1. AGE (Apache AGE)
742
+ AGE (A Graph Extension) is an extension that adds graph database functionality to PostgreSQL.
743
+ It's based on the Cypher query language and supports property graphs.
744
+
745
+ To use AGE with Ruby, you'd typically use the pg gem and write Cypher queries as strings.
746
+ Here's a basic example:
747
+
748
+ ```ruby
749
+ require 'pg'
750
+
751
+ class GraphDatabase
752
+ def initialize(dbname:, user:, password:)
753
+ @conn = PG.connect(dbname: dbname, user: user, password: password)
754
+ @conn.exec("CREATE EXTENSION IF NOT EXISTS age")
755
+ @conn.exec("LOAD 'age'")
756
+ @conn.exec("SET search_path = ag_catalog, \"$user\", public")
757
+ end
758
+
759
+ def create_graph(name)
760
+ @conn.exec("SELECT create_graph('#{name}')")
761
+ end
762
+
763
+ def add_vertex(graph, properties)
764
+ props = properties.map { |k, v| "#{k}: '#{v}'" }.join(", ")
765
+ @conn.exec("SELECT * FROM cypher('#{graph}', $$ CREATE (:Proposition {#{props}}) $$) as (v
766
+ agtype)")
767
+ end
768
+
769
+ def add_edge(graph, from_id, to_id, relationship)
770
+ @conn.exec("SELECT * FROM cypher('#{graph}', $$ MATCH (a), (b) WHERE id(a) = #{from_id} AND
771
+ id(b) = #{to_id} CREATE (a)-[:#{relationship}]->(b) $$) as (e agtype)")
772
+ end
773
+
774
+ def query(graph, cypher)
775
+ result = @conn.exec("SELECT * FROM cypher('#{graph}', $$ #{cypher} $$) as (result agtype)")
776
+ result.map { |row| row['result'] }
777
+ end
778
+ end
779
+
780
+ # Usage
781
+ db = GraphDatabase.new(dbname: 'your_db', user: 'your_user', password: 'your_password')
782
+ db.create_graph('knowledge_graph')
783
+ db.add_vertex('knowledge_graph', {content: "AI is a field of computer science", detail_level:
784
+ 1})
785
+ db.add_vertex('knowledge_graph', {content: "Machine Learning is a subset of AI", detail_level:
786
+ 2})
787
+ db.add_edge('knowledge_graph', 0, 1, 'SPECIALIZES')
788
+
789
+ result = db.query('knowledge_graph', "MATCH (p:Proposition) RETURN p")
790
+ puts result
791
+ ```
792
+
793
+ 2. pggraph
794
+ pggraph is another extension that adds graph functionality to PostgreSQL. It's less
795
+ feature-rich than AGE but might be simpler for some use cases.
796
+
797
+ 3. pgRouting
798
+ If your graph operations involve pathfinding or network analysis, pgRouting could be useful.
799
+ It's primarily designed for geospatial routing but can be adapted for other types of graphs.
800
+
801
+ For our specific use case of proposition graphs and RAG, AGE would likely be the most suitable
802
+ option. It allows for complex graph structures and queries, which aligns well with the idea of
803
+ representing and querying proposition graphs.
804
+
805
+ Here's how you might implement some of the core functionality using AGE:
806
+
807
+ ```ruby
808
+ class PropositionGraphDatabase
809
+ def initialize(dbname:, user:, password:)
810
+ @db = GraphDatabase.new(dbname: dbname, user: user, password: password)
811
+ @db.create_graph('proposition_graph')
812
+ end
813
+
814
+ def add_proposition(content:, detail_level:)
815
+ @db.add_vertex('proposition_graph', {content: content, detail_level: detail_level})
816
+ end
817
+
818
+ def connect_propositions(from_id:, to_id:, relationship: 'NEXT')
819
+ @db.add_edge('proposition_graph', from_id, to_id, relationship)
820
+ end
821
+
822
+ def find_similar_graphs(prompt_graph)
823
+ # This is a simplified example. In practice, you'd need a more sophisticated
824
+ # algorithm to compare graph structures.
825
+ cypher = """
826
+ MATCH path = (start:Proposition)-[:NEXT*]->(end:Proposition)
827
+ WHERE NOT (end)-[:NEXT]->()
828
+ WITH path, nodes(path) AS props
829
+ RETURN path,
830
+ reduce(similarity = 0, p IN props |
831
+ similarity + CASE WHEN p.content CONTAINS '#{prompt_graph.first.content}' THEN 1 ELSE 0 END
832
+ ) AS similarity_score
833
+ ORDER BY similarity_score DESC
834
+ LIMIT 5
835
+ """
836
+ @db.query('proposition_graph', cypher)
837
+ end
838
+ end
839
+
840
+ # Usage
841
+ graph_db = PropositionGraphDatabase.new(dbname: 'your_db', user: 'your_user', password:
842
+ 'your_password')
843
+ graph_db.add_proposition(content: "AI is a field of computer science", detail_level: 1)
844
+ graph_db.add_proposition(content: "Machine Learning is a subset of AI", detail_level: 2)
845
+ graph_db.connect_propositions(from_id: 0, to_id: 1)
846
+
847
+ prompt_graph = [OpenStruct.new(content: "What is AI")]
848
+ similar_graphs = graph_db.find_similar_graphs(prompt_graph)
849
+ puts similar_graphs
850
+ ```
851
+
852
+ This approach allows you to leverage PostgreSQL's robustness and scalability while gaining
853
+ graph database capabilities. It's particularly well-suited for your proposition graph idea, as
854
+ it can represent complex relationships between propositions and allow for sophisticated
855
+ querying based on graph structure.
856
+
857
+ Remember that you'll need to install and configure the AGE extension on your PostgreSQL server
858
+ before using it. Also, for production use, you'd want to implement more sophisticated graph
859
+ comparison algorithms and possibly combine this with vector embeddings for even more accurate
860
+ similarity matching.
861
+
862
+
863
+ [2024-12-15 19:27:00] INFO: Follow Up:
864
+ do you know of a goo LLM that would take a block of text for example a paragraph and great a knowledge graph from that text.
865
+
866
+
867
+ [2024-12-15 19:27:00] INFO: Response:
868
+ Yes, there are several large language models (LLMs) that can be used to generate knowledge
869
+ graphs from text. One of the most capable and widely used models for this task is GPT-4 from
870
+ OpenAI. While it doesn't directly output a structured knowledge graph, it can be prompted to
871
+ generate the components of a knowledge graph, which you can then parse and structure.
872
+
873
+ Here's an example of how you might use GPT-4 (or a similar model) to generate a knowledge
874
+ graph from a paragraph of text, and then process the output in Ruby:
875
+
876
+ ```ruby
877
+ require 'openai'
878
+ require 'json'
879
+
880
+ class KnowledgeGraphGenerator
881
+ def initialize(api_key)
882
+ @client = OpenAI::Client.new(access_token: api_key)
883
+ end
884
+
885
+ def generate_graph(text)
886
+ prompt = <<~PROMPT
887
+ Given the following paragraph, create a knowledge graph.
888
+ Output the result as a JSON object with the following structure:
889
+ {
890
+ "nodes": [
891
+ {"id": "unique_id", "label": "concept or entity", "type": "entity_type"}
892
+ ],
893
+ "edges": [
894
+ {"source": "source_id", "target": "target_id", "label": "relationship"}
895
+ ]
896
+ }
897
+
898
+ Paragraph:
899
+ #{text}
900
+
901
+ JSON Knowledge Graph:
902
+ PROMPT
903
+
904
+ response = @client.chat(
905
+ parameters: {
906
+ model: "gpt-4", # or "gpt-3.5-turbo" if you don't have GPT-4 access
907
+ messages: [{ role: "user", content: prompt }],
908
+ temperature: 0.7,
909
+ }
910
+ )
911
+
912
+ JSON.parse(response.dig("choices", 0, "message", "content"))
913
+ end
914
+ end
915
+
916
+ class KnowledgeGraph
917
+ attr_reader :nodes, :edges
918
+
919
+ def initialize(data)
920
+ @nodes = data["nodes"]
921
+ @edges = data["edges"]
922
+ end
923
+
924
+ def to_s
925
+ "Nodes:\n" + @nodes.map { |n| " #{n['id']}: #{n['label']} (#{n['type']})" }.join("\n") +
926
+ "\nEdges:\n" + @edges.map { |e| " #{e['source']} -> #{e['target']}: #{e['label']}"
927
+ }.join("\n")
928
+ end
929
+ end
930
+
931
+ # Usage
932
+ generator = KnowledgeGraphGenerator.new('your-openai-api-key')
933
+
934
+ text = "Artificial Intelligence (AI) is a broad field of computer science focused on creating
935
+ intelligent machines that can perform tasks that typically require human intelligence. Machine
936
+ Learning, a subset of AI, uses statistical techniques to give computer systems the ability to
937
+ 'learn' from data, without being explicitly programmed. Deep Learning, a further
938
+ specialization of Machine Learning, uses neural networks with many layers (hence 'deep') to
939
+ analyze various factors of data."
940
+
941
+ graph_data = generator.generate_graph(text)
942
+ graph = KnowledgeGraph.new(graph_data)
943
+
944
+ puts graph
945
+ ```
946
+
947
+ This script does the following:
948
+
949
+ 1. It uses the OpenAI API to send a prompt to GPT-4, asking it to generate a knowledge graph
950
+ from the given text.
951
+ 2. The prompt specifies the desired output format (a JSON object with nodes and edges).
952
+ 3. The response from GPT-4 is parsed as JSON.
953
+ 4. A `KnowledgeGraph` class is used to represent the graph structure and provide a simple
954
+ string representation.
955
+
956
+ When you run this script, it will output something like:
957
+
958
+ ```
959
+ Nodes:
960
+ 1: Artificial Intelligence (AI) (field)
961
+ 2: Computer Science (field)
962
+ 3: Intelligent Machines (concept)
963
+ 4: Human Intelligence (concept)
964
+ 5: Machine Learning (subfield)
965
+ 6: Statistical Techniques (method)
966
+ 7: Computer Systems (technology)
967
+ 8: Data (concept)
968
+ 9: Deep Learning (subfield)
969
+ 10: Neural Networks (technology)
970
+ Edges:
971
+ 1 -> 2: is part of
972
+ 1 -> 3: focuses on creating
973
+ 3 -> 4: perform tasks requiring
974
+ 5 -> 1: is subset of
975
+ 5 -> 6: uses
976
+ 6 -> 7: give ability to
977
+ 7 -> 8: learn from
978
+ 9 -> 5: is specialization of
979
+ 9 -> 10: uses
980
+ 10 -> 8: analyze
981
+ ```
982
+
983
+ This approach allows you to generate knowledge graphs from text in a flexible way. However,
984
+ keep in mind:
985
+
986
+ 1. The quality and structure of the generated graph will depend on the capabilities of the LLM
987
+ and how well you craft the prompt.
988
+ 2. You may need to post-process the LLM output to ensure consistency or to adapt it to your
989
+ specific needs.
990
+ 3. This method may not be suitable for processing large volumes of text due to API rate limits
991
+ and costs.
992
+ 4. For production use, you'd want to add error handling and possibly implement retries for API
993
+ calls.
994
+
995
+ For more specialized or consistent results, you might consider fine-tuning a model on
996
+ knowledge graph generation tasks, or using a dedicated NLP pipeline with named entity
997
+ recognition and relationship extraction components.
998
+
999
+
1000
+ [2024-12-15 19:31:08] INFO: Follow Up:
1001
+ Lets do an exercise. I'm going to give you some text and I would like you to give back to me a represention of that text as a knowledge graph. The text is "As a resident of Bossier City, LA I am not allowed to drive my 2021 Tahoe LS because of my poor eyesight."
1002
+
1003
+
1004
+ [2024-12-15 19:31:08] INFO: Response:
1005
+ Certainly! I'll represent this text as a knowledge graph for you. I'll provide the graph
1006
+ structure in a JSON format, which can be easily parsed and used in Ruby or other programming
1007
+ languages.
1008
+
1009
+ ```json
1010
+ {
1011
+ "nodes": [
1012
+ {
1013
+ "id": "1",
1014
+ "label": "Resident",
1015
+ "type": "Person"
1016
+ },
1017
+ {
1018
+ "id": "2",
1019
+ "label": "Bossier City",
1020
+ "type": "Location"
1021
+ },
1022
+ {
1023
+ "id": "3",
1024
+ "label": "Louisiana",
1025
+ "type": "Location"
1026
+ },
1027
+ {
1028
+ "id": "4",
1029
+ "label": "2021 Tahoe LS",
1030
+ "type": "Vehicle"
1031
+ },
1032
+ {
1033
+ "id": "5",
1034
+ "label": "Poor eyesight",
1035
+ "type": "Condition"
1036
+ },
1037
+ {
1038
+ "id": "6",
1039
+ "label": "Driving restriction",
1040
+ "type": "Regulation"
1041
+ }
1042
+ ],
1043
+ "edges": [
1044
+ {
1045
+ "source": "1",
1046
+ "target": "2",
1047
+ "label": "resides in"
1048
+ },
1049
+ {
1050
+ "source": "2",
1051
+ "target": "3",
1052
+ "label": "located in"
1053
+ },
1054
+ {
1055
+ "source": "1",
1056
+ "target": "4",
1057
+ "label": "owns"
1058
+ },
1059
+ {
1060
+ "source": "1",
1061
+ "target": "5",
1062
+ "label": "has condition"
1063
+ },
1064
+ {
1065
+ "source": "1",
1066
+ "target": "6",
1067
+ "label": "subject to"
1068
+ },
1069
+ {
1070
+ "source": "6",
1071
+ "target": "4",
1072
+ "label": "applies to"
1073
+ },
1074
+ {
1075
+ "source": "5",
1076
+ "target": "6",
1077
+ "label": "causes"
1078
+ }
1079
+ ]
1080
+ }
1081
+ ```
1082
+
1083
+ This knowledge graph representation captures the key entities and relationships in the given
1084
+ text. Here's a breakdown of the graph:
1085
+
1086
+ 1. Nodes represent the main entities and concepts:
1087
+ - The resident (Person)
1088
+ - Bossier City and Louisiana (Locations)
1089
+ - 2021 Tahoe LS (Vehicle)
1090
+ - Poor eyesight (Condition)
1091
+ - Driving restriction (Regulation)
1092
+
1093
+ 2. Edges represent the relationships between these entities:
1094
+ - The resident resides in Bossier City, which is located in Louisiana
1095
+ - The resident owns the 2021 Tahoe LS
1096
+ - The resident has the condition of poor eyesight
1097
+ - The resident is subject to a driving restriction
1098
+ - The driving restriction applies to the 2021 Tahoe LS
1099
+ - The poor eyesight causes the driving restriction
1100
+
1101
+ This structure allows for querying and reasoning about the relationships between the entities.
1102
+ For example, you can easily trace why the resident can't drive their vehicle (poor eyesight
1103
+ leading to a driving restriction).
1104
+
1105
+ To use this in Ruby, you could parse the JSON and create a graph structure similar to the one
1106
+ we discussed earlier:
1107
+
1108
+ ```ruby
1109
+ require 'json'
1110
+
1111
+ class KnowledgeGraph
1112
+ attr_reader :nodes, :edges
1113
+
1114
+ def initialize(data)
1115
+ @nodes = data["nodes"]
1116
+ @edges = data["edges"]
1117
+ end
1118
+
1119
+ def to_s
1120
+ "Nodes:\n" + @nodes.map { |n| " #{n['id']}: #{n['label']} (#{n['type']})" }.join("\n") +
1121
+ "\nEdges:\n" + @edges.map { |e| " #{e['source']} -> #{e['target']}: #{e['label']}"
1122
+ }.join("\n")
1123
+ end
1124
+ end
1125
+
1126
+ # Assuming the JSON is stored in a variable called 'json_data'
1127
+ graph_data = JSON.parse(json_data)
1128
+ graph = KnowledgeGraph.new(graph_data)
1129
+
1130
+ puts graph
1131
+ ```
1132
+
1133
+ This would give you a readable representation of the knowledge graph derived from the text.
1134
+
1135
+
1136
+ [2024-12-15 19:47:47] INFO: Follow Up:
1137
+ Is there a way that I can display the knowledge graph graphically within a rails application
1138
+
1139
+
1140
+ [2024-12-15 19:47:47] INFO: Response:
1141
+ Absolutely! There are several ways to display a knowledge graph graphically within a Rails
1142
+ application. One popular and effective approach is to use a JavaScript library for graph
1143
+ visualization. D3.js is a powerful option, but for simplicity and ease of use, we'll go with
1144
+ vis.js, which is particularly well-suited for network graphs.
1145
+
1146
+ Here's a step-by-step guide to implement this in your Rails application:
1147
+
1148
+ 1. Add the vis-network library to your Rails application:
1149
+
1150
+ Add this line to your `app/javascript/application.js` file:
1151
+
1152
+ ```javascript
1153
+ import "vis-network/styles/vis-network.css";
1154
+ import { Network } from "vis-network/standalone";
1155
+ ```
1156
+
1157
+ And add this to your `config/importmap.rb`:
1158
+
1159
+ ```ruby
1160
+ pin "vis-network", to:
1161
+ "https://ga.jspm.io/npm:vis-network@9.1.6/standalone/esm/vis-network.js"
1162
+ ```
1163
+
1164
+ 2. Create a controller action to serve the graph data:
1165
+
1166
+ ```ruby
1167
+ # app/controllers/knowledge_graphs_controller.rb
1168
+ class KnowledgeGraphsController < ApplicationController
1169
+ def show
1170
+ @graph_data = {
1171
+ nodes: [
1172
+ { id: 1, label: "Resident", group: "Person" },
1173
+ { id: 2, label: "Bossier City", group: "Location" },
1174
+ { id: 3, label: "Louisiana", group: "Location" },
1175
+ { id: 4, label: "2021 Tahoe LS", group: "Vehicle" },
1176
+ { id: 5, label: "Poor eyesight", group: "Condition" },
1177
+ { id: 6, label: "Driving restriction", group: "Regulation" }
1178
+ ],
1179
+ edges: [
1180
+ { from: 1, to: 2, label: "resides in" },
1181
+ { from: 2, to: 3, label: "located in" },
1182
+ { from: 1, to: 4, label: "owns" },
1183
+ { from: 1, to: 5, label: "has condition" },
1184
+ { from: 1, to: 6, label: "subject to" },
1185
+ { from: 6, to: 4, label: "applies to" },
1186
+ { from: 5, to: 6, label: "causes" }
1187
+ ]
1188
+ }
1189
+ end
1190
+ end
1191
+ ```
1192
+
1193
+ 3. Create a view to display the graph:
1194
+
1195
+ ```erb
1196
+ <!-- app/views/knowledge_graphs/show.html.erb -->
1197
+ <div id="knowledge-graph" style="width: 100%; height: 600px;"></div>
1198
+
1199
+ <%= javascript_tag do %>
1200
+ document.addEventListener('DOMContentLoaded', function() {
1201
+ var container = document.getElementById('knowledge-graph');
1202
+ var data = {
1203
+ nodes: new vis.DataSet(<%= raw @graph_data[:nodes].to_json %>),
1204
+ edges: new vis.DataSet(<%= raw @graph_data[:edges].to_json %>)
1205
+ };
1206
+ var options = {
1207
+ nodes: {
1208
+ shape: 'dot',
1209
+ size: 16
1210
+ },
1211
+ physics: {
1212
+ forceAtlas2Based: {
1213
+ gravitationalConstant: -26,
1214
+ centralGravity: 0.005,
1215
+ springLength: 230,
1216
+ springConstant: 0.18
1217
+ },
1218
+ maxVelocity: 146,
1219
+ solver: 'forceAtlas2Based',
1220
+ timestep: 0.35,
1221
+ stabilization: { iterations: 150 }
1222
+ }
1223
+ };
1224
+ var network = new vis.Network(container, data, options);
1225
+ });
1226
+ <% end %>
1227
+ ```
1228
+
1229
+ 4. Add a route for the knowledge graph:
1230
+
1231
+ ```ruby
1232
+ # config/routes.rb
1233
+ Rails.application.routes.draw do
1234
+ get 'knowledge_graph', to: 'knowledge_graphs#show'
1235
+ # ... other routes ...
1236
+ end
1237
+ ```
1238
+
1239
+ 5. Style the graph (optional):
1240
+
1241
+ You can add custom styles to make the graph more visually appealing. Add this to your CSS
1242
+ (e.g., in `app/assets/stylesheets/application.css`):
1243
+
1244
+ ```css
1245
+ #knowledge-graph {
1246
+ border: 1px solid #ddd;
1247
+ border-radius: 4px;
1248
+ box-shadow: 0 0 10px rgba(0,0,0,0.1);
1249
+ }
1250
+ ```
1251
+
1252
+ Now, when you visit `/knowledge_graph` in your Rails application, you should see a graphical
1253
+ representation of the knowledge graph.
1254
+
1255
+ To make this more dynamic:
1256
+
1257
+ 1. You could store your graph data in the database and retrieve it in the controller.
1258
+ 2. You could create a form that allows users to input text, which is then processed (possibly
1259
+ using an LLM as discussed earlier) to generate the graph data.
1260
+
1261
+ Here's a quick example of how you might do that:
1262
+
1263
+ ```ruby
1264
+ # app/controllers/knowledge_graphs_controller.rb
1265
+ class KnowledgeGraphsController < ApplicationController
1266
+ def new
1267
+ @knowledge_graph = KnowledgeGraph.new
1268
+ end
1269
+
1270
+ def create
1271
+ @knowledge_graph = KnowledgeGraph.new(knowledge_graph_params)
1272
+ if @knowledge_graph.save
1273
+ redirect_to @knowledge_graph
1274
+ else
1275
+ render :new
1276
+ end
1277
+ end
1278
+
1279
+ def show
1280
+ @knowledge_graph = KnowledgeGraph.find(params[:id])
1281
+ @graph_data = JSON.parse(@knowledge_graph.graph_data)
1282
+ end
1283
+
1284
+ private
1285
+
1286
+ def knowledge_graph_params
1287
+ params.require(:knowledge_graph).permit(:input_text)
1288
+ end
1289
+ end
1290
+ ```
1291
+
1292
+ You would need to create a `KnowledgeGraph` model that stores the input text and the generated
1293
+ graph data. The model could include a method to generate the graph data from the input text
1294
+ (possibly using an LLM API).
1295
+
1296
+ This setup allows for a more interactive and dynamic knowledge graph visualization in your
1297
+ Rails application.
1298
+
1299
+
1300
+ [2024-12-15 19:49:12] INFO: Follow Up:
1301
+ thank you I believe we have covered the wubject well enough.
1302
+
1303
+
1304
+ [2024-12-15 19:49:12] INFO: Response:
1305
+ You're welcome! I'm glad we were able to cover the subject of knowledge graphs, their
1306
+ implementation in Ruby and Rails, and their visualization to your satisfaction. This
1307
+ exploration touched on several important aspects:
1308
+
1309
+ 1. The concept of knowledge graphs and their representation
1310
+ 2. Using LLMs to generate knowledge graphs from text
1311
+ 3. Implementing knowledge graph structures in Ruby
1312
+ 4. Visualizing knowledge graphs in a Rails application using JavaScript libraries
1313
+
1314
+ These concepts provide a solid foundation for working with knowledge graphs in a Ruby on Rails
1315
+ environment. If you decide to implement this in a project, you'll have a good starting point
1316
+ for representing, manipulating, and visualizing complex information structures.
1317
+
1318
+ If you have any more questions in the future about this topic or any related areas, feel free
1319
+ to ask. Good luck with your work involving knowledge graphs!