1import { Hono } from "https://esm.sh/hono@3.11.7";
2import { OpenAI } from "https://esm.town/v/std/openai";
3import type { ParseRequest, ParseResponse, Recipe } from "../../shared/types.ts";
45const app = new Hono();
6const openai = new OpenAI();
78// Function to validate and clean recipe data
171const html = await response.text();
172
173// Use OpenAI to parse the recipe from HTML
174const completion = await openai.chat.completions.create({
175model: "gpt-4o-mini",
176messages: [
191192try {
193// Try to extract JSON from the response (sometimes OpenAI adds extra text)
194let jsonText = recipeText.trim();
195
219} catch (parseError) {
220console.error('JSON parsing error for URL:', parseError);
221console.error('Raw response from OpenAI:', recipeText);
222return c.json({
223success: false,
224error: `Invalid recipe format returned. OpenAI response: ${recipeText.substring(0, 200)}...`
225} as ParseResponse);
226}
243}
244
245// Use OpenAI Vision to parse recipe from image
246const completion = await openai.chat.completions.create({
247model: "gpt-4o-mini",
248messages: [
269270const recipeText = completion.choices[0]?.message?.content;
271console.log('OpenAI response:', recipeText);
272
273if (!recipeText) {
274return c.json({ success: false, error: 'OpenAI returned empty response' } as ParseResponse);
275}
276277try {
278// Try to extract JSON from the response (sometimes OpenAI adds extra text)
279let jsonText = recipeText.trim();
280
305} catch (parseError) {
306console.error('JSON parsing error:', parseError);
307console.error('Raw response from OpenAI:', recipeText);
308return c.json({
309success: false,
310error: `Invalid recipe format returned. OpenAI response: ${recipeText.substring(0, 200)}...`
311} as ParseResponse);
312}
352
353// Parse recipe from plain text
354const completion = await openai.chat.completions.create({
355model: "gpt-4o-mini",
356messages: [
366367const recipeText = completion.choices[0]?.message?.content;
368console.log('OpenAI response for text:', recipeText);
369
370if (!recipeText) {
371return c.json({ success: false, error: 'OpenAI returned empty response' } as ParseResponse);
372}
373374try {
375// Try to extract JSON from the response (sometimes OpenAI adds extra text)
376let jsonText = recipeText.trim();
377
402} catch (parseError) {
403console.error('JSON parsing error for text:', parseError);
404console.error('Raw response from OpenAI:', recipeText);
405return c.json({
406success: false,
407error: `Invalid recipe format returned. OpenAI response: ${recipeText.substring(0, 200)}...`
408} as ParseResponse);
409}
22- **Backend**: Hono API framework
23- **Database**: SQLite for recipe storage
24- **AI**: OpenAI GPT-4 for intelligent recipe parsing
25- **File Processing**: PDF parsing and image OCR capabilities
26
NewPerspctovologyAppmain.tsx1 match
1// val.js
23const OPENAI_API_KEY = process.env.OPENAI_API_KEY; // set this later
45export default async (req, res) => {
1# Plant Information API
23A REST API that provides detailed plant information using OpenAI's GPT model with intelligent caching for improved performance and reduced API costs.
45## Project Structure
19- Get comprehensive plant information by name
20- Structured JSON response with 8 key plant characteristics
21- Powered by OpenAI GPT-4o-mini for accurate plant data
22- **Intelligent caching system** - stores successful responses and serves cached data for repeated requests
23- Cache management endpoints for monitoring and administration
4647### GET /plant/:name
48Returns detailed information about a specific plant. If the plant information is already cached, returns the cached response immediately. Otherwise, fetches new information from OpenAI and caches it for future requests.
4950**Parameters:**
6869**Cache Indicators:**
70- `_cached`: Boolean indicating if the response came from cache (true) or OpenAI (false)
71- `_cacheTimestamp`: ISO timestamp of when the response was generated
72174- `200`: Success
175- `400`: Bad request (missing plant name)
176- `500`: Server error (OpenAI API issues, parsing errors)
177178Error responses include descriptive error messages and may include additional debugging information.
216- **Plant name normalization**: Plant names are normalized (lowercased, special characters removed, spaces converted to underscores) for consistent caching
217- **Cache hits**: Subsequent requests for the same plant (even with different capitalization or spacing) will return cached responses instantly
218- **Cache misses**: New plants trigger OpenAI API calls and the responses are automatically cached
219- **Performance**: Cached responses are served in milliseconds vs. seconds for OpenAI API calls
220- **Cost efficiency**: Reduces OpenAI API usage and associated costs
221222## Technical Details
224- **Main entry point**: `index.ts` at project root with HTTP trigger
225- Built with Hono framework
226- Uses OpenAI GPT-4o-mini model
227- SQLite database for caching with automatic table creation
228- Includes input validation and error handling
1import { Hono } from "https://esm.sh/hono@3.11.7";
2import { OpenAI } from "https://esm.town/v/std/openai";
3import { readFile } from "https://esm.town/v/std/utils/index.ts";
4import { sqlite } from "https://esm.town/v/stevekrouse/sqlite";
20});
2122// Initialize OpenAI
23const openai = new OpenAI();
2425// Initialize cache on startup with error handling
88}
8990console.log(`Fetching fresh data from OpenAI for: "${plantName}"`);
91// If not cached, fetch from OpenAI
92const prompt = `Please provide detailed information about the plant "${plantName}" in the following JSON format. Be specific and accurate:
93105Only return the JSON object, no additional text.`;
106107const completion = await openai.chat.completions.create({
108messages: [
109{ role: "user", content: prompt }
117
118if (!responseText) {
119return c.json({ error: "No response from OpenAI" }, 500);
120}
121129}
130
131// Parse the JSON response from OpenAI
132const plantInfo: PlantInfo = JSON.parse(cleanedResponse);
133
1import { OpenAI } from "https://esm.town/v/std/openai";
23// --- TYPE DEFINITIONS ---
296*/
297export default async function(req: Request): Promise<Response> {
298const openai = new OpenAI();
299const url = new URL(req.url);
300320throw new Error("Goal is required for synthesis.");
321}
322const completion = await openai.chat.completions.create({
323model: "gpt-4o",
324messages: [
338throw new Error("An array of tasks is required for reschedule.");
339}
340const completion = await openai.chat.completions.create({
341model: "gpt-4o",
342messages: [
143Note: When changing a SQLite table's schema, change the table's name (e.g., add _2 or _3) to create a fresh table.
144145### OpenAI
146```ts
147import { OpenAI } from "npm:openai";
148const openai = new OpenAI();
149const completion = await openai.chat.completions.create({
150messages: [
151{ role: "user", content: "Say hello in a creative way" },
val-town-http-mcp-servervalley.txt4 matches
86Note: When changing a SQLite table's schema, change the table's name (e.g., add _2 or _3) to create a fresh table.
8788### OpenAI
8990```ts
91import { OpenAI } from "https://esm.town/v/std/openai";
92const openai = new OpenAI();
93const completion = await openai.chat.completions.create({
94messages: [
95{ role: "user", content: "Say hello in a creative way" },
val-town-http-mcp-servertownie.txt7 matches
8384<library>
85## OpenAI
8687Val Town includes a free, proxied OpenAI:
8889```ts
90import { OpenAI } from "https://esm.town/v/std/openai";
91const openai = new OpenAI();
92const completion = await openai.chat.completions.create({
93messages: [
94{ role: "user", content: "Say hello in a creative way" },
99```
100101OpenAI only works on the server. If the val includes client-side code, use dynamic imports to import this module in the server function, e.g.:
102`const { OpenAI } = await import "https://esm.town/v/std/openai");`
103</library>
104
71```
7273### OpenAI Integration
74```typescript
75import { OpenAI } from "https://esm.town/v/std/openai";
76const openai = new OpenAI();
77const completion = await openai.chat.completions.create({
78messages: [{ role: "user", content: "Say hello" }],
79model: "gpt-4o-mini",