[WIP] making a working demo for all possible seekers questions

This commit is contained in:
Eliyan
2025-10-14 17:44:27 +02:00
parent 28b0360ddb
commit e863a0a5ea
3 changed files with 142 additions and 21 deletions

View File

@@ -8,11 +8,13 @@ This is a **Proof of Concept (PoC)** that demonstrates the conversion of natural
## Features
- Converts natural language requests into ODMDB DSL queries
- Handles temporal queries ("new seekers since last week")
- Maps human-readable field names to schema fields
- Validates output using Zod schema validation
- Uses OpenAI's structured output for reliable JSON generation
- **Natural Language Processing**: Converts human questions into structured ODMDB queries
- **Real ODMDB Integration**: Works with actual ODMDB data from `../smatchitObjectOdmdb/`
- **Schema-Based Mapping**: Uses actual seekers.json schema for accurate field mapping (62 properties)
- **Local Data Execution**: Processes queries against local seeker files in `objects/seekers/itm/`
- **OpenAI Structured Output**: Ensures reliable JSON query generation
- **Query Validation**: Validates generated queries against real ODMDB schema rules
- **jq Integration**: Powerful result processing, filtering, and CSV export capabilities
## Prerequisites
@@ -21,13 +23,24 @@ This is a **Proof of Concept (PoC)** that demonstrates the conversion of natural
## Installation
1. Install dependencies:
1. Make sure you have the ODMDB data structure available:
```
../smatchitObjectOdmdb/
├── schema/
│ └── seekers.json # Seeker schema (62 properties)
└── objects/
└── seekers/
└── itm/ # Individual seeker JSON files
```
2. Install dependencies:
```bash
npm install
```
2. Set your OpenAI API key:
3. Set your OpenAI API key:
```bash
export OPENAI_API_KEY=sk-your-api-key-here
```
@@ -48,10 +61,6 @@ npm start
EXECUTE_QUERY=true npm start
```
**With Custom ODMDB Server:**
```bash
EXECUTE_QUERY=true ODMDB_BASE_URL=http://localhost:8080 npm start
```
This will process the hardcoded natural language query and output the generated ODMDB query in JSON format. When `EXECUTE_QUERY=true`, it will also execute the query against the ODMDB server.
@@ -67,17 +76,28 @@ const NL_QUERY = "your natural language query here";
### Example Queries
**Status-based queries:**
- `"show me seekers with status startasap and their email and experience"`
- `"find seekers looking for jobs urgently with their skills"`
**Date-based queries:**
- `"give me new seekers since last week with email and experience"`
- `"find recent seekers with job titles and salary expectations"`
- `"show me seekers from yesterday with their skills"`
### Testing jq Processing
**Field-specific queries:**
- `"find seekers with job titles and salary expectations"`
- `"show me seeker locations and availability"`
**Supported filter types:**
- **Status filtering**: `seekstatus` (startasap, norush, notlooking)
- **Date filtering**: `dt_create` with date ranges
- **Index optimization**: Uses ODMDB indexes for efficient queries
To test the jq processing capabilities with mock data:
```bash
node test-jq.js
```
This demonstrates various jq operations including:

101
demo.js Normal file
View File

@@ -0,0 +1,101 @@
#!/usr/bin/env node
// Demo script showing different ODMDB query types with real data
import fs from "node:fs";
console.log("🚀 ODMDB NL to Query Demo");
console.log("=".repeat(50));
// Sample queries to demonstrate
const queries = [
{
nl: "show me seekers with status startasap and their email and experience",
description: "Status-based filtering with field selection",
expectedCondition: "idx.seekstatus_alias(startasap)",
expectedFields: ["email", "seekworkingyear"],
},
{
nl: "find seekers looking for jobs urgently with salary expectations",
description: "Status synonym mapping + salary field",
expectedCondition: "idx.seekstatus_alias(startasap)",
expectedFields: ["salaryexpectation", "salaryunit"],
},
{
nl: "give me seekers from last month with their locations",
description: "Date-based filtering + location fields",
expectedCondition: "prop.dt_create(>=:2025-09-14)",
expectedFields: ["seeklocation"],
},
];
console.log("📋 Demo Queries:");
queries.forEach((query, i) => {
console.log(`\n${i + 1}. "${query.nl}"`);
console.log(` Purpose: ${query.description}`);
console.log(` Expected DSL: ${query.expectedCondition}`);
console.log(` Expected Fields: ${query.expectedFields.join(", ")}`);
});
console.log("\n💡 To test these queries:");
console.log("1. Edit the NL_QUERY constant in poc.js");
console.log("2. Run: EXECUTE_QUERY=true npm start");
console.log("\n📊 Current ODMDB Status:");
// Check if ODMDB data is accessible
const seekersPath = "../smatchitObjectOdmdb/objects/seekers/itm";
try {
if (fs.existsSync(seekersPath)) {
const files = fs
.readdirSync(seekersPath)
.filter((f) => f.endsWith(".json") && f !== "backup");
console.log(`✅ Found ${files.length} seeker files in ${seekersPath}`);
// Sample a few files to show data types
const sampleFile = files[0];
const sampleData = JSON.parse(
fs.readFileSync(`${seekersPath}/${sampleFile}`, "utf-8")
);
console.log(`📄 Sample seeker data (${sampleFile}):`);
console.log(` - alias: ${sampleData.alias}`);
console.log(` - email: ${sampleData.email}`);
console.log(` - seekstatus: ${sampleData.seekstatus}`);
console.log(` - seekworkingyear: ${sampleData.seekworkingyear}`);
console.log(` - dt_create: ${sampleData.dt_create}`);
} else {
console.log(`❌ ODMDB data not found at ${seekersPath}`);
}
} catch (error) {
console.log(`❌ Error accessing ODMDB data: ${error.message}`);
}
const schemaPath = "../smatchitObjectOdmdb/schema/seekers.json";
try {
if (fs.existsSync(schemaPath)) {
const schema = JSON.parse(fs.readFileSync(schemaPath, "utf-8"));
const fieldCount = Object.keys(schema.properties || {}).length;
console.log(`✅ Loaded seekers schema with ${fieldCount} properties`);
// Show access rights info
if (schema.apxaccessrights?.recruiters?.R) {
console.log(
`📋 Recruiter-readable fields: ${schema.apxaccessrights.recruiters.R.slice(
0,
5
).join(", ")}... (${schema.apxaccessrights.recruiters.R.length} total)`
);
}
// Show available indexes
if (schema.apxidx) {
const indexes = schema.apxidx.map((idx) => idx.name);
console.log(`🔍 Available indexes: ${indexes.join(", ")}`);
}
} else {
console.log(`❌ Schema not found at ${schemaPath}`);
}
} catch (error) {
console.log(`❌ Error loading schema: ${error.message}`);
}
console.log("\n✅ Demo complete!");

8
poc.js
View File

@@ -23,7 +23,7 @@ const EXECUTE_QUERY = process.env.EXECUTE_QUERY === "true"; // Set to "true" to
// Hardcoded NL query for the PoC (no multi-turn)
const NL_QUERY =
"give me new seekers since last week with email and experience";
"show me seekers with status startasap and their email and experience";
// ---- Load schemas (safe) ----
function loadJsonSafe(path) {
@@ -603,7 +603,7 @@ async function processResults(results, jqFilter = ".") {
console.log("\n📋 Results Summary:");
const summary = await processResults(
results,
`.[0:3] | map({alias, email, seekstatus})`
`.[0:3] | map({email, seekworkingyear})`
);
console.log(JSON.stringify(summary, null, 2));
@@ -617,8 +617,8 @@ async function processResults(results, jqFilter = ".") {
const csvData = await processResults(
results,
`
map([.alias // "N/A", .email // "N/A", .seekstatus // "N/A"]) |
["alias","email","status"] as $header |
map([.email // "N/A", .seekworkingyear // "N/A"]) |
["email","experience"] as $header |
[$header] + .[0:5] |
.[] | @csv
`