@graphext/cuery 0.2.1 → 0.3.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.
@@ -1,3 +1,4 @@
1
+ import { type AIParams } from '../openai.js';
1
2
  /**
2
3
  * Classifies a single data record into one of the provided categories using an LLM call.
3
4
  */
@@ -14,4 +15,20 @@ export declare function label(record: Record<string, unknown> | null, labels: Re
14
15
  * Assigns labels to multiple data records concurrently while preserving order.
15
16
  */
16
17
  export declare function labelBatch(records: Array<Record<string, unknown> | null>, labels: Record<string, string>, instructions?: string, model?: string, maxConcurrency?: number): Promise<Array<Array<string> | null>>;
18
+ export interface LabelExtractionOptions {
19
+ records: Array<Record<string, unknown>>;
20
+ nLabels?: number;
21
+ instructions?: string;
22
+ maxSamples?: number;
23
+ model?: string;
24
+ modelParams?: AIParams;
25
+ maxRetries?: number;
26
+ language?: string;
27
+ }
28
+ /**
29
+ * Extracts a set of classification labels from an array of records using an LLM.
30
+ * Returns a Record<string, string> mapping label names to descriptions,
31
+ * which can be used directly with classify() and classifyBatch().
32
+ */
33
+ export declare function extractLabels({ records, nLabels, instructions, maxSamples, model, modelParams, maxRetries, language }: LabelExtractionOptions): Promise<Record<string, string>>;
17
34
  //# sourceMappingURL=classifier.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"classifier.d.ts","sourceRoot":"","sources":["../../../src/src/tools/classifier.ts"],"names":[],"mappings":"AAsGA;;GAEG;AACH,wBAAsB,QAAQ,CAC7B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,YAAY,GAAE,MAAW,EACzB,KAAK,GAAE,MAAuB,GAC5B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiBxB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC5B,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,EAC9C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,YAAY,GAAE,MAAW,EACzB,KAAK,GAAE,MAAuB,EAC9B,cAAc,GAAE,MAAY,GAC1B,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAM/B;AAED;;GAEG;AACH,wBAAsB,KAAK,CAC1B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,YAAY,GAAE,MAAW,EACzB,KAAK,GAAE,MAAuB,GAC5B,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAiB/B;AAED;;GAEG;AACH,wBAAgB,UAAU,CACzB,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,EAC9C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,YAAY,GAAE,MAAW,EACzB,KAAK,GAAE,MAAuB,EAC9B,cAAc,GAAE,MAAY,GAC1B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAMtC"}
1
+ {"version":3,"file":"classifier.d.ts","sourceRoot":"","sources":["../../../src/src/tools/classifier.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAoG5D;;GAEG;AACH,wBAAsB,QAAQ,CAC7B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,YAAY,GAAE,MAAW,EACzB,KAAK,GAAE,MAAuB,GAC5B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiBxB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC5B,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,EAC9C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,YAAY,GAAE,MAAW,EACzB,KAAK,GAAE,MAAuB,EAC9B,cAAc,GAAE,MAAY,GAC1B,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAM/B;AAED;;GAEG;AACH,wBAAsB,KAAK,CAC1B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,YAAY,GAAE,MAAW,EACzB,KAAK,GAAE,MAAuB,GAC5B,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAiB/B;AAED;;GAEG;AACH,wBAAgB,UAAU,CACzB,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,EAC9C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,YAAY,GAAE,MAAW,EACzB,KAAK,GAAE,MAAuB,EAC9B,cAAc,GAAE,MAAY,GAC1B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAMtC;AA4CD,MAAM,WAAW,sBAAsB;IACtC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,EACnC,OAAO,EACP,OAAY,EACZ,YAAiB,EACjB,UAAgB,EAChB,KAAiB,EACjB,WAAgB,EAChB,UAAc,EACd,QAA6C,EAC7C,EAAE,sBAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAsC1D"}
@@ -1,7 +1,7 @@
1
1
  import { z } from '../../deps/jsr.io/@zod/zod/4.1.12/src/index.js';
2
2
  import { mapParallel } from '../async.js';
3
3
  import { askOpenAISafe } from '../openai.js';
4
- import { dedent } from '../utils.js';
4
+ import { dedent, formatRecordsAttrWise } from '../utils.js';
5
5
  const PROMPT_TEMPLATE = dedent(`
6
6
  # Instructions
7
7
 
@@ -133,3 +133,79 @@ export async function label(record, labels, instructions = '', model = 'gpt-4.1-
133
133
  export function labelBatch(records, labels, instructions = '', model = 'gpt-4.1-mini', maxConcurrency = 100) {
134
134
  return mapParallel(records, maxConcurrency, record => label(record, labels, instructions, model));
135
135
  }
136
+ // =============================================================================
137
+ // Label Extraction
138
+ // =============================================================================
139
+ const EXTRACT_LABELS_PROMPT = dedent(`
140
+ # Instructions
141
+
142
+ From the data records below, extract a flat list of classification labels.
143
+ The output should be a JSON object with a "labels" array, where each item has a "name" and "description".
144
+ The list should not contain more than {n_labels} labels.
145
+
146
+ Make sure labels are generalizable and capture broad themes.
147
+ Each label should have a clear, concise description explaining what it represents.
148
+ Labels and descriptions must be written in {language}.
149
+
150
+ The labels should follow the MECE framework (Mutually Exclusive, Collectively Exhaustive):
151
+ - Mutually Exclusive: Labels should not overlap; each record should fit clearly into one category.
152
+ - Collectively Exhaustive: Labels should cover all the data; every record should have a fitting category.
153
+ - If needed, include an "Other" category for records that don't fit well into the main labels.
154
+
155
+ If the records contain mainly textual content (e.g., articles, posts, comments, descriptions),
156
+ the labels should represent the main topics or subject areas covered by the text,
157
+ unless the user provides different instructions below.
158
+
159
+ {instructions}
160
+
161
+ # Data Records
162
+
163
+ {records}
164
+ `);
165
+ /**
166
+ * Schema for extracted labels - an array of label objects.
167
+ * Uses array format instead of record because OpenAI doesn't support propertyNames in JSON schema.
168
+ */
169
+ const ExtractedLabelsSchema = z.object({
170
+ labels: z.array(z.object({
171
+ name: z.string(),
172
+ description: z.string()
173
+ }))
174
+ });
175
+ /**
176
+ * Extracts a set of classification labels from an array of records using an LLM.
177
+ * Returns a Record<string, string> mapping label names to descriptions,
178
+ * which can be used directly with classify() and classifyBatch().
179
+ */
180
+ export async function extractLabels({ records, nLabels = 10, instructions = '', maxSamples = 500, model = 'gpt-4.1', modelParams = {}, maxRetries = 8, language = 'The same language as the records' }) {
181
+ if (!records || records.length === 0) {
182
+ return {};
183
+ }
184
+ const sampledRecords = records.length > maxSamples
185
+ ? records.slice(0, maxSamples)
186
+ : records;
187
+ const formattedRecords = formatRecordsAttrWise(sampledRecords);
188
+ const prompt = EXTRACT_LABELS_PROMPT
189
+ .replace('{n_labels}', String(nLabels))
190
+ .replace('{instructions}', instructions)
191
+ .replace('{records}', formattedRecords)
192
+ .replace('{language}', language);
193
+ const { parsed, output_text, error } = await askOpenAISafe(prompt, model, ExtractedLabelsSchema, modelParams, maxRetries, 'return');
194
+ if (error != null) {
195
+ if (output_text == null) {
196
+ throw new Error('Failed to get response from OpenAI');
197
+ }
198
+ try {
199
+ const extracted = JSON.parse(output_text);
200
+ const { labels } = ExtractedLabelsSchema.parse(extracted);
201
+ return Object.fromEntries(labels.map(l => [l.name, l.description]));
202
+ }
203
+ catch (parseError) {
204
+ throw new Error(`Failed to parse response: ${parseError instanceof Error ? parseError.message : String(parseError)}`);
205
+ }
206
+ }
207
+ if (parsed == null) {
208
+ throw new Error('Failed to parse response from OpenAI');
209
+ }
210
+ return Object.fromEntries(parsed.labels.map(l => [l.name, l.description]));
211
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"topics.d.ts","sourceRoot":"","sources":["../../../src/src/tools/topics.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,gDAAgD,CAAC;AAEnE,OAAO,EAAsC,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAEjF,OAAO,EAEN,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,MAAM,6BAA6B,CAAC;AAIrC,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC;AAuEpD;;;GAGG;AACH,eAAO,MAAM,KAAK;;;iBAShB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,YAAY;;;;;iBAEvB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,QAAQ;;;;;iBAEnB,CAAC;AAEH;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;CAAE,CAAC,CAKpH;AACD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,YAAY;;;;;;;kBAmBvD;AAyCD;;GAEG;AACH,wBAAsB,WAAW,CAChC,IAAI,EAAE,MAAM,GAAG,IAAI,EACnB,QAAQ,EAAE,YAAY,GAAG,KAAK,CAAC,SAAS,CAAC,GAAG,MAAM,EAClD,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,EAClC,KAAK,GAAE,MAAkB,EACzB,WAAW,GAAE,QAA4C,GACvD,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CA2B5B;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC3B,KAAK,EAAE,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,EAC3B,QAAQ,EAAE,YAAY,GAAG,KAAK,CAAC,SAAS,CAAC,EACzC,KAAK,GAAE,MAAkB,EACzB,WAAW,GAAE,QAA4C,EACzD,cAAc,GAAE,MAAY,GAC1B,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,CAgBnC;AAED,MAAM,WAAW,sBAAsB;IACtC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,EACnC,OAAO,EACP,OAAY,EACZ,UAAc,EACd,YAAiB,EACjB,UAAgB,EAChB,KAAiB,EACjB,WAAgB,EAChB,UAAc,EACd,QAA6C,EAC7C,EAAE,sBAAsB,GAAG,OAAO,CAAC,YAAY,CAAC,CAsChD"}
1
+ {"version":3,"file":"topics.d.ts","sourceRoot":"","sources":["../../../src/src/tools/topics.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,gDAAgD,CAAC;AAEnE,OAAO,EAAsC,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAEjF,OAAO,EAEN,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,MAAM,6BAA6B,CAAC;AAIrC,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC;AAuEpD;;;GAGG;AACH,eAAO,MAAM,KAAK;;;iBAShB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,YAAY;;;;;iBAEvB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,QAAQ;;;;;iBAEnB,CAAC;AAEH;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;CAAE,CAAC,CAKpH;AACD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,YAAY;;;;;;;kBAmBvD;AA+CD;;GAEG;AACH,wBAAsB,WAAW,CAChC,IAAI,EAAE,MAAM,GAAG,IAAI,EACnB,QAAQ,EAAE,YAAY,GAAG,KAAK,CAAC,SAAS,CAAC,GAAG,MAAM,EAClD,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,EAClC,KAAK,GAAE,MAAkB,EACzB,WAAW,GAAE,QAA4C,GACvD,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CA2B5B;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC3B,KAAK,EAAE,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,EAC3B,QAAQ,EAAE,YAAY,GAAG,KAAK,CAAC,SAAS,CAAC,EACzC,KAAK,GAAE,MAAkB,EACzB,WAAW,GAAE,QAA4C,EACzD,cAAc,GAAE,MAAY,GAC1B,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,CAgBnC;AAED,MAAM,WAAW,sBAAsB;IACtC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,EACnC,OAAO,EACP,OAAY,EACZ,UAAc,EACd,YAAiB,EACjB,UAAgB,EAChB,KAAiB,EACjB,WAAgB,EAChB,UAAc,EACd,QAA6C,EAC7C,EAAE,sBAAsB,GAAG,OAAO,CAAC,YAAY,CAAC,CAsChD"}
@@ -126,12 +126,18 @@ const TOPICS_PROMPT = dedent(`
126
126
  From the data records below, extract a two-level nested list of topics.
127
127
  The output should be a JSON object with top-level topics as keys and lists of subtopics as values.
128
128
  The top-level should not contain more than {n_topics} topics, and each top-level
129
- should not contain more than {n_subtopics} subtopics.
129
+ should not contain more than {n_subtopics} subtopics. Fewer topics are acceptable, and appropriate if
130
+ the data does not support that many or if there are too few records.
130
131
 
131
132
  Make sure top-level topics are generalizable and capture broad themes.
132
133
  Subtopics should represent more specific categories within each theme.
133
134
  Both topics and subtopics must be written in {language}.
134
135
 
136
+ The taxonomy should follow the MECE framework (Mutually Exclusive, Collectively Exhaustive):
137
+ - Mutually Exclusive: Topics and subtopics should not overlap; each record should fit clearly into one category.
138
+ - Collectively Exhaustive: The taxonomy should cover all the data; every record should have a fitting topic and subtopic.
139
+ - If needed, include an "Other" topic or subtopic for records that don't fit well into the main categories.
140
+
135
141
  {instructions}
136
142
 
137
143
  # Data Records
@@ -1 +1 @@
1
- {"version":3,"file":"translate.d.ts","sourceRoot":"","sources":["../../../src/src/tools/translate.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AA+C/D,MAAM,WAAW,eAAe;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,YAAY,CAAC;CAC3B;AAED;;GAEG;AACH,wBAAsB,SAAS,CAC9B,EAAE,OAAO,EAAE,QAAe,EAAE,KAAoB,EAAE,YAAY,EAAE,YAAiB,EAAE,EAAE,eAAe,GAClG,OAAO,CAAC,MAAM,CAAC,CAcjB;AAED;;GAEG;AAEH,MAAM,WAAW,oBAAoB;IACpC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,YAAY,CAAC;CAC3B;AAED,wBAAsB,cAAc,CACnC,MAAM,EAAE,oBAAoB,GAC1B,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAQxB;AA4BD,MAAM,WAAW,sBAAsB;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACrC,EAAE,MAAM,EAAE,QAAe,EAAE,KAAsB,EAAE,EAAE,sBAAsB,GACzE,OAAO,CAAC,MAAM,CAAC,CAWjB;AAED,MAAM,WAAW,2BAA2B;IAC3C,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CAC1C,MAAM,EAAE,2BAA2B,GACjC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAQxB"}
1
+ {"version":3,"file":"translate.d.ts","sourceRoot":"","sources":["../../../src/src/tools/translate.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AA+C/D,MAAM,WAAW,eAAe;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,YAAY,CAAC;CAC3B;AAED;;GAEG;AACH,wBAAsB,SAAS,CAC9B,EAAE,OAAO,EAAE,QAAe,EAAE,KAAoB,EAAE,YAAY,EAAE,YAAiB,EAAE,EAAE,eAAe,GAClG,OAAO,CAAC,MAAM,CAAC,CAcjB;AAED;;GAEG;AAEH,MAAM,WAAW,oBAAoB;IACpC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,YAAY,CAAC;CAC3B;AAED,wBAAsB,cAAc,CACnC,MAAM,EAAE,oBAAoB,GAC1B,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAQxB;AA+BD,MAAM,WAAW,sBAAsB;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACrC,EAAE,MAAM,EAAE,QAAe,EAAE,KAAsB,EAAE,EAAE,sBAAsB,GACzE,OAAO,CAAC,MAAM,CAAC,CAWjB;AAED,MAAM,WAAW,2BAA2B;IAC3C,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CAC1C,MAAM,EAAE,2BAA2B,GACjC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAQxB"}
@@ -71,7 +71,7 @@ You are an expert in understanding search intent.
71
71
  Convert the following natural language prompt into an equivalent Google search keyword.
72
72
  The keyword should:
73
73
 
74
- - Be concise (typically 2-5 words)
74
+ - Be concise
75
75
  - Capture the core search intent
76
76
  - Remove conversational filler and politeness
77
77
  - Use common search terms
@@ -84,6 +84,9 @@ For example:
84
84
 
85
85
  Make sure the keyword is in the language "{language}".
86
86
 
87
+ It's mandatory that the keyword contains no more than 4 words, ideally 2-3 words.
88
+ Otherwise, Google keyword planner will not accept it.
89
+
87
90
  # Prompt
88
91
 
89
92
  {prompt}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphext/cuery",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Cuery tools for AI-powered keyword research and brand analysis",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,3 +1,4 @@
1
+ import { type AIParams } from '../openai.js';
1
2
  /**
2
3
  * Classifies a single data record into one of the provided categories using an LLM call.
3
4
  */
@@ -14,4 +15,20 @@ export declare function label(record: Record<string, unknown> | null, labels: Re
14
15
  * Assigns labels to multiple data records concurrently while preserving order.
15
16
  */
16
17
  export declare function labelBatch(records: Array<Record<string, unknown> | null>, labels: Record<string, string>, instructions?: string, model?: string, maxConcurrency?: number): Promise<Array<Array<string> | null>>;
18
+ export interface LabelExtractionOptions {
19
+ records: Array<Record<string, unknown>>;
20
+ nLabels?: number;
21
+ instructions?: string;
22
+ maxSamples?: number;
23
+ model?: string;
24
+ modelParams?: AIParams;
25
+ maxRetries?: number;
26
+ language?: string;
27
+ }
28
+ /**
29
+ * Extracts a set of classification labels from an array of records using an LLM.
30
+ * Returns a Record<string, string> mapping label names to descriptions,
31
+ * which can be used directly with classify() and classifyBatch().
32
+ */
33
+ export declare function extractLabels({ records, nLabels, instructions, maxSamples, model, modelParams, maxRetries, language }: LabelExtractionOptions): Promise<Record<string, string>>;
17
34
  //# sourceMappingURL=classifier.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"classifier.d.ts","sourceRoot":"","sources":["../../../src/src/tools/classifier.ts"],"names":[],"mappings":"AAsGA;;GAEG;AACH,wBAAsB,QAAQ,CAC7B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,YAAY,GAAE,MAAW,EACzB,KAAK,GAAE,MAAuB,GAC5B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiBxB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC5B,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,EAC9C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,YAAY,GAAE,MAAW,EACzB,KAAK,GAAE,MAAuB,EAC9B,cAAc,GAAE,MAAY,GAC1B,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAM/B;AAED;;GAEG;AACH,wBAAsB,KAAK,CAC1B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,YAAY,GAAE,MAAW,EACzB,KAAK,GAAE,MAAuB,GAC5B,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAiB/B;AAED;;GAEG;AACH,wBAAgB,UAAU,CACzB,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,EAC9C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,YAAY,GAAE,MAAW,EACzB,KAAK,GAAE,MAAuB,EAC9B,cAAc,GAAE,MAAY,GAC1B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAMtC"}
1
+ {"version":3,"file":"classifier.d.ts","sourceRoot":"","sources":["../../../src/src/tools/classifier.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAoG5D;;GAEG;AACH,wBAAsB,QAAQ,CAC7B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,YAAY,GAAE,MAAW,EACzB,KAAK,GAAE,MAAuB,GAC5B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiBxB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC5B,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,EAC9C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,YAAY,GAAE,MAAW,EACzB,KAAK,GAAE,MAAuB,EAC9B,cAAc,GAAE,MAAY,GAC1B,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAM/B;AAED;;GAEG;AACH,wBAAsB,KAAK,CAC1B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,YAAY,GAAE,MAAW,EACzB,KAAK,GAAE,MAAuB,GAC5B,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAiB/B;AAED;;GAEG;AACH,wBAAgB,UAAU,CACzB,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,EAC9C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,YAAY,GAAE,MAAW,EACzB,KAAK,GAAE,MAAuB,EAC9B,cAAc,GAAE,MAAY,GAC1B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAMtC;AA4CD,MAAM,WAAW,sBAAsB;IACtC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,EACnC,OAAO,EACP,OAAY,EACZ,YAAiB,EACjB,UAAgB,EAChB,KAAiB,EACjB,WAAgB,EAChB,UAAc,EACd,QAA6C,EAC7C,EAAE,sBAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAsC1D"}
@@ -4,6 +4,7 @@ exports.classify = classify;
4
4
  exports.classifyBatch = classifyBatch;
5
5
  exports.label = label;
6
6
  exports.labelBatch = labelBatch;
7
+ exports.extractLabels = extractLabels;
7
8
  const index_js_1 = require("../../deps/jsr.io/@zod/zod/4.1.12/src/index.js");
8
9
  const async_js_1 = require("../async.js");
9
10
  const openai_js_1 = require("../openai.js");
@@ -139,3 +140,79 @@ async function label(record, labels, instructions = '', model = 'gpt-4.1-mini')
139
140
  function labelBatch(records, labels, instructions = '', model = 'gpt-4.1-mini', maxConcurrency = 100) {
140
141
  return (0, async_js_1.mapParallel)(records, maxConcurrency, record => label(record, labels, instructions, model));
141
142
  }
143
+ // =============================================================================
144
+ // Label Extraction
145
+ // =============================================================================
146
+ const EXTRACT_LABELS_PROMPT = (0, utils_js_1.dedent)(`
147
+ # Instructions
148
+
149
+ From the data records below, extract a flat list of classification labels.
150
+ The output should be a JSON object with a "labels" array, where each item has a "name" and "description".
151
+ The list should not contain more than {n_labels} labels.
152
+
153
+ Make sure labels are generalizable and capture broad themes.
154
+ Each label should have a clear, concise description explaining what it represents.
155
+ Labels and descriptions must be written in {language}.
156
+
157
+ The labels should follow the MECE framework (Mutually Exclusive, Collectively Exhaustive):
158
+ - Mutually Exclusive: Labels should not overlap; each record should fit clearly into one category.
159
+ - Collectively Exhaustive: Labels should cover all the data; every record should have a fitting category.
160
+ - If needed, include an "Other" category for records that don't fit well into the main labels.
161
+
162
+ If the records contain mainly textual content (e.g., articles, posts, comments, descriptions),
163
+ the labels should represent the main topics or subject areas covered by the text,
164
+ unless the user provides different instructions below.
165
+
166
+ {instructions}
167
+
168
+ # Data Records
169
+
170
+ {records}
171
+ `);
172
+ /**
173
+ * Schema for extracted labels - an array of label objects.
174
+ * Uses array format instead of record because OpenAI doesn't support propertyNames in JSON schema.
175
+ */
176
+ const ExtractedLabelsSchema = index_js_1.z.object({
177
+ labels: index_js_1.z.array(index_js_1.z.object({
178
+ name: index_js_1.z.string(),
179
+ description: index_js_1.z.string()
180
+ }))
181
+ });
182
+ /**
183
+ * Extracts a set of classification labels from an array of records using an LLM.
184
+ * Returns a Record<string, string> mapping label names to descriptions,
185
+ * which can be used directly with classify() and classifyBatch().
186
+ */
187
+ async function extractLabels({ records, nLabels = 10, instructions = '', maxSamples = 500, model = 'gpt-4.1', modelParams = {}, maxRetries = 8, language = 'The same language as the records' }) {
188
+ if (!records || records.length === 0) {
189
+ return {};
190
+ }
191
+ const sampledRecords = records.length > maxSamples
192
+ ? records.slice(0, maxSamples)
193
+ : records;
194
+ const formattedRecords = (0, utils_js_1.formatRecordsAttrWise)(sampledRecords);
195
+ const prompt = EXTRACT_LABELS_PROMPT
196
+ .replace('{n_labels}', String(nLabels))
197
+ .replace('{instructions}', instructions)
198
+ .replace('{records}', formattedRecords)
199
+ .replace('{language}', language);
200
+ const { parsed, output_text, error } = await (0, openai_js_1.askOpenAISafe)(prompt, model, ExtractedLabelsSchema, modelParams, maxRetries, 'return');
201
+ if (error != null) {
202
+ if (output_text == null) {
203
+ throw new Error('Failed to get response from OpenAI');
204
+ }
205
+ try {
206
+ const extracted = JSON.parse(output_text);
207
+ const { labels } = ExtractedLabelsSchema.parse(extracted);
208
+ return Object.fromEntries(labels.map(l => [l.name, l.description]));
209
+ }
210
+ catch (parseError) {
211
+ throw new Error(`Failed to parse response: ${parseError instanceof Error ? parseError.message : String(parseError)}`);
212
+ }
213
+ }
214
+ if (parsed == null) {
215
+ throw new Error('Failed to parse response from OpenAI');
216
+ }
217
+ return Object.fromEntries(parsed.labels.map(l => [l.name, l.description]));
218
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"topics.d.ts","sourceRoot":"","sources":["../../../src/src/tools/topics.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,gDAAgD,CAAC;AAEnE,OAAO,EAAsC,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAEjF,OAAO,EAEN,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,MAAM,6BAA6B,CAAC;AAIrC,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC;AAuEpD;;;GAGG;AACH,eAAO,MAAM,KAAK;;;iBAShB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,YAAY;;;;;iBAEvB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,QAAQ;;;;;iBAEnB,CAAC;AAEH;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;CAAE,CAAC,CAKpH;AACD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,YAAY;;;;;;;kBAmBvD;AAyCD;;GAEG;AACH,wBAAsB,WAAW,CAChC,IAAI,EAAE,MAAM,GAAG,IAAI,EACnB,QAAQ,EAAE,YAAY,GAAG,KAAK,CAAC,SAAS,CAAC,GAAG,MAAM,EAClD,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,EAClC,KAAK,GAAE,MAAkB,EACzB,WAAW,GAAE,QAA4C,GACvD,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CA2B5B;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC3B,KAAK,EAAE,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,EAC3B,QAAQ,EAAE,YAAY,GAAG,KAAK,CAAC,SAAS,CAAC,EACzC,KAAK,GAAE,MAAkB,EACzB,WAAW,GAAE,QAA4C,EACzD,cAAc,GAAE,MAAY,GAC1B,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,CAgBnC;AAED,MAAM,WAAW,sBAAsB;IACtC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,EACnC,OAAO,EACP,OAAY,EACZ,UAAc,EACd,YAAiB,EACjB,UAAgB,EAChB,KAAiB,EACjB,WAAgB,EAChB,UAAc,EACd,QAA6C,EAC7C,EAAE,sBAAsB,GAAG,OAAO,CAAC,YAAY,CAAC,CAsChD"}
1
+ {"version":3,"file":"topics.d.ts","sourceRoot":"","sources":["../../../src/src/tools/topics.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,gDAAgD,CAAC;AAEnE,OAAO,EAAsC,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAEjF,OAAO,EAEN,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,MAAM,6BAA6B,CAAC;AAIrC,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC;AAuEpD;;;GAGG;AACH,eAAO,MAAM,KAAK;;;iBAShB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,YAAY;;;;;iBAEvB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,QAAQ;;;;;iBAEnB,CAAC;AAEH;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;CAAE,CAAC,CAKpH;AACD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,YAAY;;;;;;;kBAmBvD;AA+CD;;GAEG;AACH,wBAAsB,WAAW,CAChC,IAAI,EAAE,MAAM,GAAG,IAAI,EACnB,QAAQ,EAAE,YAAY,GAAG,KAAK,CAAC,SAAS,CAAC,GAAG,MAAM,EAClD,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,EAClC,KAAK,GAAE,MAAkB,EACzB,WAAW,GAAE,QAA4C,GACvD,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CA2B5B;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC3B,KAAK,EAAE,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,EAC3B,QAAQ,EAAE,YAAY,GAAG,KAAK,CAAC,SAAS,CAAC,EACzC,KAAK,GAAE,MAAkB,EACzB,WAAW,GAAE,QAA4C,EACzD,cAAc,GAAE,MAAY,GAC1B,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,CAgBnC;AAED,MAAM,WAAW,sBAAsB;IACtC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,EACnC,OAAO,EACP,OAAY,EACZ,UAAc,EACd,YAAiB,EACjB,UAAgB,EAChB,KAAiB,EACjB,WAAgB,EAChB,UAAc,EACd,QAA6C,EAC7C,EAAE,sBAAsB,GAAG,OAAO,CAAC,YAAY,CAAC,CAsChD"}
@@ -134,12 +134,18 @@ const TOPICS_PROMPT = (0, utils_js_1.dedent)(`
134
134
  From the data records below, extract a two-level nested list of topics.
135
135
  The output should be a JSON object with top-level topics as keys and lists of subtopics as values.
136
136
  The top-level should not contain more than {n_topics} topics, and each top-level
137
- should not contain more than {n_subtopics} subtopics.
137
+ should not contain more than {n_subtopics} subtopics. Fewer topics are acceptable, and appropriate if
138
+ the data does not support that many or if there are too few records.
138
139
 
139
140
  Make sure top-level topics are generalizable and capture broad themes.
140
141
  Subtopics should represent more specific categories within each theme.
141
142
  Both topics and subtopics must be written in {language}.
142
143
 
144
+ The taxonomy should follow the MECE framework (Mutually Exclusive, Collectively Exhaustive):
145
+ - Mutually Exclusive: Topics and subtopics should not overlap; each record should fit clearly into one category.
146
+ - Collectively Exhaustive: The taxonomy should cover all the data; every record should have a fitting topic and subtopic.
147
+ - If needed, include an "Other" topic or subtopic for records that don't fit well into the main categories.
148
+
143
149
  {instructions}
144
150
 
145
151
  # Data Records
@@ -1 +1 @@
1
- {"version":3,"file":"translate.d.ts","sourceRoot":"","sources":["../../../src/src/tools/translate.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AA+C/D,MAAM,WAAW,eAAe;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,YAAY,CAAC;CAC3B;AAED;;GAEG;AACH,wBAAsB,SAAS,CAC9B,EAAE,OAAO,EAAE,QAAe,EAAE,KAAoB,EAAE,YAAY,EAAE,YAAiB,EAAE,EAAE,eAAe,GAClG,OAAO,CAAC,MAAM,CAAC,CAcjB;AAED;;GAEG;AAEH,MAAM,WAAW,oBAAoB;IACpC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,YAAY,CAAC;CAC3B;AAED,wBAAsB,cAAc,CACnC,MAAM,EAAE,oBAAoB,GAC1B,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAQxB;AA4BD,MAAM,WAAW,sBAAsB;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACrC,EAAE,MAAM,EAAE,QAAe,EAAE,KAAsB,EAAE,EAAE,sBAAsB,GACzE,OAAO,CAAC,MAAM,CAAC,CAWjB;AAED,MAAM,WAAW,2BAA2B;IAC3C,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CAC1C,MAAM,EAAE,2BAA2B,GACjC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAQxB"}
1
+ {"version":3,"file":"translate.d.ts","sourceRoot":"","sources":["../../../src/src/tools/translate.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AA+C/D,MAAM,WAAW,eAAe;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,YAAY,CAAC;CAC3B;AAED;;GAEG;AACH,wBAAsB,SAAS,CAC9B,EAAE,OAAO,EAAE,QAAe,EAAE,KAAoB,EAAE,YAAY,EAAE,YAAiB,EAAE,EAAE,eAAe,GAClG,OAAO,CAAC,MAAM,CAAC,CAcjB;AAED;;GAEG;AAEH,MAAM,WAAW,oBAAoB;IACpC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,YAAY,CAAC;CAC3B;AAED,wBAAsB,cAAc,CACnC,MAAM,EAAE,oBAAoB,GAC1B,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAQxB;AA+BD,MAAM,WAAW,sBAAsB;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACrC,EAAE,MAAM,EAAE,QAAe,EAAE,KAAsB,EAAE,EAAE,sBAAsB,GACzE,OAAO,CAAC,MAAM,CAAC,CAWjB;AAED,MAAM,WAAW,2BAA2B;IAC3C,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CAC1C,MAAM,EAAE,2BAA2B,GACjC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAQxB"}
@@ -77,7 +77,7 @@ You are an expert in understanding search intent.
77
77
  Convert the following natural language prompt into an equivalent Google search keyword.
78
78
  The keyword should:
79
79
 
80
- - Be concise (typically 2-5 words)
80
+ - Be concise
81
81
  - Capture the core search intent
82
82
  - Remove conversational filler and politeness
83
83
  - Use common search terms
@@ -90,6 +90,9 @@ For example:
90
90
 
91
91
  Make sure the keyword is in the language "{language}".
92
92
 
93
+ It's mandatory that the keyword contains no more than 4 words, ideally 2-3 words.
94
+ Otherwise, Google keyword planner will not accept it.
95
+
93
96
  # Prompt
94
97
 
95
98
  {prompt}