Skip to content

Commit afddb7e

Browse files
feat: Implement premium AI natural language search endpoint and middleware for tier-based access control
1 parent 4dc9d63 commit afddb7e

16 files changed

+699
-36
lines changed

README.md

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -329,10 +329,11 @@ The `/v1/search` endpoint returns detailed nutritional information. The `primary
329329

330330
Performs a search using a natural language query to identify a food and its quantity.
331331

332-
- **Endpoint**: `GET /v1/natural-language-search`
333-
- **Authentication**: Required (API Key)
334-
- **Query Parameters**:
335-
- `query` (required): A natural language query (e.g., "100g of cheddar cheese").
332+
- **Endpoint**: `POST /v1/natural-language-search`
333+
- **Authentication**: Required (API Key – Free or Pro)
334+
- **Body**:
335+
- `text` (string, required): A natural language query (e.g., "100g of cheddar cheese").
336+
- `maxResults`, `confidence`, `filterForSuggestions` (optional): Advanced controls for USDA lookups.
336337
- **Success Response (`200 OK`)**:
337338
```json
338339
{
@@ -364,6 +365,21 @@ Performs a search using a natural language query to identify a food and its quan
364365
}
365366
```
366367

368+
### Premium AI Natural Language Search (Pro Tier)
369+
370+
Unlock the Workers AI-powered parser for more nuanced, multi-item meal descriptions.
371+
372+
- **Endpoint**: `POST /v2/ai-natural-language-search`
373+
- **Authentication**: Requires a **Pro tier** API key
374+
- **Body**:
375+
- `text` (string, required): Meal description (max 500 characters)
376+
- Optional knobs: `maxResults`, `confidence`, `filterForSuggestions`
377+
- **What you get**:
378+
- AI-interpreted items with unit normalization and gram estimates
379+
- USDA-backed search results with confidence scores
380+
- Response meta showing cache status and model identifier (`@cf/meta/llama-2-7b-chat-int8`)
381+
- **Generate a Pro key**: `GET /_admin/generate-key?tier=pro`
382+
367383
---
368384

369385
## Getting Started & Deployment
@@ -576,6 +592,8 @@ We offer the following tiers for our API:
576592
| Pro | $50/month | 100,000 |
577593
| Enterprise | Custom | Custom |
578594
595+
- **Premium Features**: The `POST /v2/ai-natural-language-search` endpoint and future AI add-ons are available to Pro keys (and above) only. Requests from Free keys return `403 Forbidden`.
596+
579597
For more details, please visit our pricing page at [example.com/pricing](https://example.com/pricing).
580598
581599
---

openapi.json

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,95 @@
235235
"429": { "$ref": "#/components/responses/TooManyRequests" }
236236
}
237237
}
238+
},
239+
"/v2/ai-natural-language-search": {
240+
"post": {
241+
"summary": "Premium AI-Powered Natural Language Search",
242+
"description": "Parses complex meal descriptions using Cloudflare Workers AI (Meta Llama 2 7B) to produce structured food items, quantity estimates, and confidence scores. **Requires a Pro-tier API key.** The endpoint caches responses and returns USDA search suggestions alongside the AI interpretation.",
243+
"operationId": "ai_natural_language_search",
244+
"security": [{ "ApiKeyAuth": [] }],
245+
"tags": ["Food", "Premium"],
246+
"requestBody": {
247+
"required": true,
248+
"content": {
249+
"application/json": {
250+
"schema": {
251+
"type": "object",
252+
"required": ["text"],
253+
"properties": {
254+
"text": {
255+
"type": "string",
256+
"description": "Natural language meal description (500 characters max).",
257+
"example": "A grilled chicken breast with 2 cups of steamed broccoli"
258+
},
259+
"maxResults": {
260+
"type": "integer",
261+
"minimum": 1,
262+
"maximum": 25,
263+
"default": 5,
264+
"description": "Maximum USDA search results to return per parsed food item."
265+
},
266+
"confidence": {
267+
"type": "number",
268+
"minimum": 0,
269+
"maximum": 1,
270+
"default": 0.8,
271+
"description": "Minimum string-similarity confidence required for USDA results."
272+
},
273+
"filterForSuggestions": {
274+
"type": "boolean",
275+
"default": false,
276+
"description": "When true, results are filtered to only suggestions above the confidence threshold."
277+
}
278+
}
279+
}
280+
}
281+
}
282+
},
283+
"responses": {
284+
"200": {
285+
"description": "Successful AI parsing and USDA lookup.",
286+
"headers": {
287+
"X-Cache-Status": {
288+
"schema": { "type": "string" },
289+
"description": "Cache status for the AI response (MISS, HIT, or STALE)."
290+
},
291+
"X-RateLimit-Limit": {
292+
"schema": { "type": "integer" },
293+
"description": "Maximum requests allowed in the current window."
294+
},
295+
"X-RateLimit-Remaining": {
296+
"schema": { "type": "integer" },
297+
"description": "Remaining requests in the current window."
298+
},
299+
"X-RateLimit-Reset": {
300+
"schema": { "type": "integer" },
301+
"description": "Seconds until the current window resets."
302+
}
303+
},
304+
"content": {
305+
"application/json": {
306+
"schema": {
307+
"$ref": "#/components/schemas/AiNaturalLanguageSearchResponse"
308+
}
309+
}
310+
}
311+
},
312+
"400": { "$ref": "#/components/responses/BadRequest" },
313+
"401": { "$ref": "#/components/responses/Unauthorized" },
314+
"403": {
315+
"description": "Forbidden – API key tier is not authorized for premium AI endpoints.",
316+
"content": {
317+
"application/json": {
318+
"schema": {
319+
"$ref": "#/components/schemas/ErrorResponse"
320+
}
321+
}
322+
}
323+
},
324+
"429": { "$ref": "#/components/responses/TooManyRequests" }
325+
}
326+
}
238327
}
239328
},
240329
"components": {
@@ -406,6 +495,59 @@
406495
}
407496
}
408497
},
498+
"ParsedAiFoodItem": {
499+
"type": "object",
500+
"properties": {
501+
"quantity": { "type": "number" },
502+
"unit": { "type": "string", "nullable": true },
503+
"foodName": { "type": "string" },
504+
"quantityInGrams": { "type": "number", "nullable": true },
505+
"modifiers": {
506+
"type": "array",
507+
"items": { "type": "string" },
508+
"description": "Preparation or context modifiers detected by Workers AI."
509+
},
510+
"category": { "type": "string", "nullable": true },
511+
"combinedWith": { "type": "string", "nullable": true }
512+
}
513+
},
514+
"AiNaturalLanguageSearchResponse": {
515+
"type": "object",
516+
"properties": {
517+
"success": { "type": "boolean" },
518+
"data": {
519+
"type": "object",
520+
"properties": {
521+
"query": { "type": "string" },
522+
"searchResults": {
523+
"type": "array",
524+
"description": "Filtered USDA search results enriched with confidence scores.",
525+
"items": {
526+
"type": "object",
527+
"additionalProperties": true
528+
}
529+
},
530+
"totalResults": { "type": "integer" },
531+
"foodNameConfidence": {
532+
"type": "number",
533+
"description": "Average confidence score across parsed items."
534+
},
535+
"parsedItems": {
536+
"type": "array",
537+
"items": { "$ref": "#/components/schemas/ParsedAiFoodItem" }
538+
}
539+
}
540+
},
541+
"meta": {
542+
"type": "object",
543+
"properties": {
544+
"requestId": { "type": "string" },
545+
"cacheStatus": { "type": "string" },
546+
"model": { "type": "string", "example": "@cf/meta/llama-2-7b-chat-int8" }
547+
}
548+
}
549+
}
550+
},
409551
"ParsedFoodItem": {
410552
"type": "object",
411553
"properties": {

package-lock.json

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"npm": ">=8.0.0"
2929
},
3030
"dependencies": {
31+
"@cloudflare/ai": "^1.0.0",
3132
"itty-router": "^4.0.23",
3233
"zod": "^3.25.76"
3334
},

0 commit comments

Comments
 (0)