@falkordb/text-to-cypher 0.1.0

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/CHANGELOG.md ADDED
@@ -0,0 +1,48 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.1.0] - 2025-12-23
9
+
10
+ ### Added
11
+ - Initial release of text-to-cypher-node
12
+ - NAPI-RS bindings for the text-to-cypher Rust library
13
+ - `TextToCypher` class with the following methods:
14
+ - `textToCypher(graphName, question)` - Convert natural language to Cypher and execute
15
+ - `textToCypherWithMessages(graphName, messages)` - Support for conversation history
16
+ - `cypherOnly(graphName, question)` - Generate Cypher without execution
17
+ - `discoverSchema(graphName)` - Discover and return graph schema
18
+ - TypeScript definitions for all public APIs
19
+ - Comprehensive documentation:
20
+ - README.md with usage examples
21
+ - INTEGRATION.md for FalkorDB Browser integration
22
+ - CONTRIBUTING.md for developers
23
+ - Examples:
24
+ - basic-usage.js - JavaScript example
25
+ - typescript-usage.ts - TypeScript example
26
+ - Test suite using Vitest
27
+ - GitHub Actions CI/CD:
28
+ - Build workflow for multiple platforms (Linux, macOS, Windows)
29
+ - Test workflow
30
+ - Release workflow with automatic npm publishing
31
+ - Support for multiple AI models:
32
+ - OpenAI (GPT-4, GPT-4 Turbo, GPT-4o Mini, etc.)
33
+ - Anthropic (Claude 3)
34
+ - Google (Gemini)
35
+ - Pre-built binaries for:
36
+ - Linux x64 (glibc and musl)
37
+ - Linux ARM64 (glibc and musl)
38
+ - macOS x64 (Intel)
39
+ - macOS ARM64 (Apple Silicon)
40
+ - Windows x64
41
+
42
+ ### Technical Details
43
+ - Built with NAPI-RS for high-performance native Node.js bindings
44
+ - Async/await support throughout the API
45
+ - Proper error handling and propagation from Rust to JavaScript
46
+ - Zero runtime dependencies
47
+
48
+ [0.1.0]: https://github.com/FalkorDB/text-to-cypher-node/releases/tag/v0.1.0
package/INTEGRATION.md ADDED
@@ -0,0 +1,373 @@
1
+ # Integration Guide for FalkorDB Browser
2
+
3
+ This guide explains how to integrate `@falkordb/text-to-cypher-node` into the [FalkorDB Browser](https://github.com/FalkorDB/falkordb-browser).
4
+
5
+ ## Overview
6
+
7
+ The FalkorDB Browser can use text-to-cypher-node to provide a natural language interface for querying graphs. Users can ask questions in plain English instead of writing Cypher queries.
8
+
9
+ ## Installation
10
+
11
+ In your FalkorDB Browser project:
12
+
13
+ ```bash
14
+ npm install @falkordb/text-to-cypher-node
15
+ ```
16
+
17
+ ## Backend Integration (Node.js/Express)
18
+
19
+ ### 1. Create a Text-to-Cypher Service
20
+
21
+ ```typescript
22
+ // services/textToCypherService.ts
23
+ import { TextToCypher, TextToCypherResponse } from '@falkordb/text-to-cypher-node';
24
+
25
+ export class TextToCypherService {
26
+ private client: TextToCypher;
27
+
28
+ constructor(
29
+ model: string = process.env.AI_MODEL || 'gpt-4o-mini',
30
+ apiKey: string = process.env.OPENAI_API_KEY || '',
31
+ falkordbConnection: string = process.env.FALKORDB_CONNECTION || 'falkor://localhost:6379'
32
+ ) {
33
+ this.client = new TextToCypher({
34
+ model,
35
+ apiKey,
36
+ falkordbConnection
37
+ });
38
+ }
39
+
40
+ async convertQuery(graphName: string, question: string): Promise<TextToCypherResponse> {
41
+ return await this.client.textToCypher(graphName, question);
42
+ }
43
+
44
+ async generateCypherOnly(graphName: string, question: string): Promise<TextToCypherResponse> {
45
+ return await this.client.cypherOnly(graphName, question);
46
+ }
47
+
48
+ async getSchema(graphName: string): Promise<string> {
49
+ return await this.client.discoverSchema(graphName);
50
+ }
51
+ }
52
+ ```
53
+
54
+ ### 2. Create API Endpoints
55
+
56
+ ```typescript
57
+ // routes/textToCypher.ts
58
+ import { Router, Request, Response } from 'express';
59
+ import { TextToCypherService } from '../services/textToCypherService';
60
+
61
+ const router = Router();
62
+ const textToCypherService = new TextToCypherService();
63
+
64
+ // Convert natural language to Cypher and execute
65
+ router.post('/api/text-to-cypher', async (req: Request, res: Response) => {
66
+ try {
67
+ const { graphName, question } = req.body;
68
+
69
+ if (!graphName || !question) {
70
+ return res.status(400).json({
71
+ error: 'Missing required fields: graphName and question'
72
+ });
73
+ }
74
+
75
+ const response = await textToCypherService.convertQuery(graphName, question);
76
+
77
+ if (response.status === 'error') {
78
+ return res.status(500).json(response);
79
+ }
80
+
81
+ res.json(response);
82
+ } catch (error) {
83
+ res.status(500).json({
84
+ error: 'Internal server error',
85
+ message: error instanceof Error ? error.message : 'Unknown error'
86
+ });
87
+ }
88
+ });
89
+
90
+ // Generate Cypher only (for preview)
91
+ router.post('/api/generate-cypher', async (req: Request, res: Response) => {
92
+ try {
93
+ const { graphName, question } = req.body;
94
+
95
+ if (!graphName || !question) {
96
+ return res.status(400).json({
97
+ error: 'Missing required fields: graphName and question'
98
+ });
99
+ }
100
+
101
+ const response = await textToCypherService.generateCypherOnly(graphName, question);
102
+
103
+ if (response.status === 'error') {
104
+ return res.status(500).json(response);
105
+ }
106
+
107
+ res.json(response);
108
+ } catch (error) {
109
+ res.status(500).json({
110
+ error: 'Internal server error',
111
+ message: error instanceof Error ? error.message : 'Unknown error'
112
+ });
113
+ }
114
+ });
115
+
116
+ // Get graph schema
117
+ router.get('/api/schema/:graphName', async (req: Request, res: Response) => {
118
+ try {
119
+ const { graphName } = req.params;
120
+ const schema = await textToCypherService.getSchema(graphName);
121
+ res.json({ schema: JSON.parse(schema) });
122
+ } catch (error) {
123
+ res.status(500).json({
124
+ error: 'Internal server error',
125
+ message: error instanceof Error ? error.message : 'Unknown error'
126
+ });
127
+ }
128
+ });
129
+
130
+ export default router;
131
+ ```
132
+
133
+ ### 3. Register Routes in Your App
134
+
135
+ ```typescript
136
+ // app.ts
137
+ import express from 'express';
138
+ import textToCypherRoutes from './routes/textToCypher';
139
+
140
+ const app = express();
141
+
142
+ app.use(express.json());
143
+ app.use(textToCypherRoutes);
144
+
145
+ // ... other routes and middleware
146
+
147
+ export default app;
148
+ ```
149
+
150
+ ## Frontend Integration (React)
151
+
152
+ ### 1. Create a Text-to-Cypher Hook
153
+
154
+ ```typescript
155
+ // hooks/useTextToCypher.ts
156
+ import { useState } from 'react';
157
+
158
+ interface TextToCypherResponse {
159
+ status: string;
160
+ schema?: string;
161
+ cypherQuery?: string;
162
+ cypherResult?: string;
163
+ answer?: string;
164
+ error?: string;
165
+ }
166
+
167
+ export const useTextToCypher = () => {
168
+ const [loading, setLoading] = useState(false);
169
+ const [error, setError] = useState<string | null>(null);
170
+
171
+ const convertQuery = async (
172
+ graphName: string,
173
+ question: string
174
+ ): Promise<TextToCypherResponse | null> => {
175
+ setLoading(true);
176
+ setError(null);
177
+
178
+ try {
179
+ const response = await fetch('/api/text-to-cypher', {
180
+ method: 'POST',
181
+ headers: {
182
+ 'Content-Type': 'application/json',
183
+ },
184
+ body: JSON.stringify({ graphName, question }),
185
+ });
186
+
187
+ const data = await response.json();
188
+
189
+ if (!response.ok) {
190
+ throw new Error(data.error || 'Failed to convert query');
191
+ }
192
+
193
+ return data;
194
+ } catch (err) {
195
+ const errorMessage = err instanceof Error ? err.message : 'Unknown error';
196
+ setError(errorMessage);
197
+ return null;
198
+ } finally {
199
+ setLoading(false);
200
+ }
201
+ };
202
+
203
+ const generateCypher = async (
204
+ graphName: string,
205
+ question: string
206
+ ): Promise<TextToCypherResponse | null> => {
207
+ setLoading(true);
208
+ setError(null);
209
+
210
+ try {
211
+ const response = await fetch('/api/generate-cypher', {
212
+ method: 'POST',
213
+ headers: {
214
+ 'Content-Type': 'application/json',
215
+ },
216
+ body: JSON.stringify({ graphName, question }),
217
+ });
218
+
219
+ const data = await response.json();
220
+
221
+ if (!response.ok) {
222
+ throw new Error(data.error || 'Failed to generate query');
223
+ }
224
+
225
+ return data;
226
+ } catch (err) {
227
+ const errorMessage = err instanceof Error ? err.message : 'Unknown error';
228
+ setError(errorMessage);
229
+ return null;
230
+ } finally {
231
+ setLoading(false);
232
+ }
233
+ };
234
+
235
+ return { convertQuery, generateCypher, loading, error };
236
+ };
237
+ ```
238
+
239
+ ### 2. Create a Natural Language Query Component
240
+
241
+ ```typescript
242
+ // components/NaturalLanguageQuery.tsx
243
+ import React, { useState } from 'react';
244
+ import { useTextToCypher } from '../hooks/useTextToCypher';
245
+
246
+ interface Props {
247
+ graphName: string;
248
+ onQueryGenerated?: (query: string) => void;
249
+ onResultReceived?: (result: string, answer: string) => void;
250
+ }
251
+
252
+ export const NaturalLanguageQuery: React.FC<Props> = ({
253
+ graphName,
254
+ onQueryGenerated,
255
+ onResultReceived,
256
+ }) => {
257
+ const [question, setQuestion] = useState('');
258
+ const { convertQuery, generateCypher, loading, error } = useTextToCypher();
259
+
260
+ const handleConvert = async () => {
261
+ const response = await convertQuery(graphName, question);
262
+ if (response && response.status === 'success') {
263
+ if (response.cypherQuery) {
264
+ onQueryGenerated?.(response.cypherQuery);
265
+ }
266
+ if (response.cypherResult && response.answer) {
267
+ onResultReceived?.(response.cypherResult, response.answer);
268
+ }
269
+ }
270
+ };
271
+
272
+ const handleGenerateOnly = async () => {
273
+ const response = await generateCypher(graphName, question);
274
+ if (response && response.cypherQuery) {
275
+ onQueryGenerated?.(response.cypherQuery);
276
+ }
277
+ };
278
+
279
+ return (
280
+ <div className="natural-language-query">
281
+ <h3>Ask a Question</h3>
282
+ <textarea
283
+ value={question}
284
+ onChange={(e) => setQuestion(e.target.value)}
285
+ placeholder="e.g., Find all actors who appeared in movies after 2020"
286
+ disabled={loading}
287
+ />
288
+ <div className="buttons">
289
+ <button onClick={handleConvert} disabled={loading || !question}>
290
+ {loading ? 'Processing...' : 'Execute Query'}
291
+ </button>
292
+ <button onClick={handleGenerateOnly} disabled={loading || !question}>
293
+ Generate Query Only
294
+ </button>
295
+ </div>
296
+ {error && <div className="error">{error}</div>}
297
+ </div>
298
+ );
299
+ };
300
+ ```
301
+
302
+ ## Environment Variables
303
+
304
+ Create a `.env` file in your project:
305
+
306
+ ```env
307
+ # AI Model Configuration
308
+ AI_MODEL=gpt-4o-mini
309
+ OPENAI_API_KEY=your-openai-api-key-here
310
+
311
+ # FalkorDB Connection
312
+ FALKORDB_CONNECTION=falkor://localhost:6379
313
+
314
+ # Optional: for other AI providers
315
+ # ANTHROPIC_API_KEY=your-anthropic-key
316
+ # GOOGLE_API_KEY=your-google-key
317
+ ```
318
+
319
+ ## Usage Examples
320
+
321
+ ### Example 1: Simple Query
322
+
323
+ User asks: "Show me all actors"
324
+
325
+ Response:
326
+ - Generated Query: `MATCH (a:Actor) RETURN a.name`
327
+ - Result: List of actor names
328
+ - Answer: "Here are all the actors in the database: Tom Hanks, Meryl Streep, ..."
329
+
330
+ ### Example 2: Complex Query
331
+
332
+ User asks: "Find actors who worked with Tom Hanks in movies released after 2000"
333
+
334
+ Response:
335
+ - Generated Query: `MATCH (a:Actor)-[:ACTED_IN]->(m:Movie)<-[:ACTED_IN]-(coactor:Actor {name: 'Tom Hanks'}) WHERE m.year > 2000 RETURN DISTINCT a.name`
336
+ - Result: List of co-actors
337
+ - Answer: "Tom Hanks worked with the following actors in movies after 2000: ..."
338
+
339
+ ## Best Practices
340
+
341
+ 1. **Rate Limiting**: Implement rate limiting on the API endpoints to prevent abuse
342
+ 2. **Caching**: Cache schema discovery results to reduce database queries
343
+ 3. **Error Handling**: Provide helpful error messages to users
344
+ 4. **User Feedback**: Show the generated Cypher query to users for transparency
345
+ 5. **Query Validation**: Always validate and sanitize queries before execution
346
+
347
+ ## Security Considerations
348
+
349
+ 1. Never expose your AI API keys in frontend code
350
+ 2. Implement proper authentication for the API endpoints
351
+ 3. Use read-only connections when possible
352
+ 4. Consider implementing a query whitelist for production environments
353
+ 5. Monitor usage to detect potential abuse
354
+
355
+ ## Troubleshooting
356
+
357
+ ### Issue: "Cannot connect to FalkorDB"
358
+
359
+ Solution: Ensure FalkorDB is running and the connection string is correct.
360
+
361
+ ### Issue: "Invalid API key"
362
+
363
+ Solution: Check that your AI provider API key is set correctly in environment variables.
364
+
365
+ ### Issue: "Query generation failed"
366
+
367
+ Solution: The AI model might need more context. Try rephrasing the question or providing more specific details.
368
+
369
+ ## Support
370
+
371
+ For issues or questions:
372
+ - [text-to-cypher-node GitHub Issues](https://github.com/FalkorDB/text-to-cypher-node/issues)
373
+ - [FalkorDB Discord](https://discord.gg/falkordb)
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 FalkorDB
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.