From 4eedd5e9687d6b638fa28cde91f90b7ab390b750 Mon Sep 17 00:00:00 2001 From: Jason Liu Date: Sat, 17 Feb 2024 21:04:35 -0500 Subject: [PATCH] feat(Instructor): introduce Instructor Hub with tutorials, examples, and new CLI (#439) --- docs/hub/index.md | 92 ++ docs/hub/multiple_classification.md | 51 + docs/hub/single_classification.md | 47 + instructor-hub-proxy/.editorconfig | 13 + instructor-hub-proxy/.gitignore | 172 +++ instructor-hub-proxy/.prettierrc | 6 + instructor-hub-proxy/create.sql | 10 + instructor-hub-proxy/package-lock.json | 1322 +++++++++++++++++ instructor-hub-proxy/package.json | 20 + instructor-hub-proxy/src/index.ts | 27 + instructor-hub-proxy/src/router.ts | 128 ++ instructor-hub-proxy/tsconfig.json | 103 ++ .../worker-configuration.d.ts | 16 + instructor-hub-proxy/wrangler.toml | 56 + instructor/cli/cli.py | 2 + instructor/cli/hub.py | 167 +++ mkdocs.yml | 8 +- pyproject.toml | 2 +- tests/openai/docs/test_hub.py | 12 + tutorials/README.md | 64 - tutorials/assets/article.txt | 1 - tutorials/helpers.py | 32 - tutorials/requirements.txt | 8 - 23 files changed, 2250 insertions(+), 109 deletions(-) create mode 100644 docs/hub/index.md create mode 100644 docs/hub/multiple_classification.md create mode 100644 docs/hub/single_classification.md create mode 100644 instructor-hub-proxy/.editorconfig create mode 100644 instructor-hub-proxy/.gitignore create mode 100644 instructor-hub-proxy/.prettierrc create mode 100644 instructor-hub-proxy/create.sql create mode 100644 instructor-hub-proxy/package-lock.json create mode 100644 instructor-hub-proxy/package.json create mode 100644 instructor-hub-proxy/src/index.ts create mode 100644 instructor-hub-proxy/src/router.ts create mode 100644 instructor-hub-proxy/tsconfig.json create mode 100644 instructor-hub-proxy/worker-configuration.d.ts create mode 100644 instructor-hub-proxy/wrangler.toml create mode 100644 instructor/cli/hub.py create mode 100644 tests/openai/docs/test_hub.py delete mode 100644 tutorials/README.md delete mode 100644 tutorials/assets/article.txt delete mode 100644 tutorials/helpers.py delete mode 100644 tutorials/requirements.txt diff --git a/docs/hub/index.md b/docs/hub/index.md new file mode 100644 index 0000000..ecc5fe1 --- /dev/null +++ b/docs/hub/index.md @@ -0,0 +1,92 @@ +# Instructor Hub + +Welcome to instructor hub, the goal of this project is to provide a set of tutorials and examples to help you get started, and allow you to pull in the code you need to get started with `instructor` + +Make sure you're using the latest version of `instructor` by running: + +```bash +pip install -U instructor +``` + +## Contributing + +We welcome contributions to the instructor hub, if you have a tutorial or example you'd like to add, please open a pull request in `docs/hub` and we'll review it. + +1. The code must be in a single file +2. Make sure that its referenced in the `mkdocs.yml` +3. Make sure that the code is unit tested. + +### Using pytest_examples + +By running the following command you can run the tests and update the examples. This ensures that the examples are always up to date. +Linted correctly and that the examples are working, make sure to include a `if __name__ == "__main__":` block in your code and add some asserts to ensure that the code is working. + +```bash +poetry run pytest tests/openai/docs/test_hub.py --update-examples +``` + +## CLI Usage + +Instructor hub comes with a command line interface (CLI) that allows you to view and interact with the tutorials and examples and allows you to pull in the code you need to get started with the API. + +### List Cookbooks + +By running `instructor hub list` you can see all the available tutorials and examples. By clickony (doc) you can see the full tutorial back on this website. + +```bash +$ instructor hub list --sort +``` + +| hub_id | slug | title | n_downloads | +| ------ | ----------------------------- | ----------------------------- | ----------- | +| 2 | multiple_classification (doc) | Multiple Classification Model | 24 | +| 1 | single_classification (doc) | Single Classification Model | 2 | + +### Searching for Cookbooks + +You can search for a tutorial by running `instructor hub list -q `. This will return a list of tutorials that match the query. + +```bash +$ instructor hub list -q multi +``` + +| hub_id | slug | title | n_downloads | +| ------ | ----------------------------- | ----------------------------- | ----------- | +| 2 | multiple_classification (doc) | Multiple Classification Model | 24 | + +### Reading a Cookbook + +To read a tutorial, you can run `instructor hub pull --id --page` to see the full tutorial in the terminal. You can use `j,k` to scroll up and down, and `q` to quit. You can also run it without `--page` to print the tutorial to the terminal. + +```bash +$ instructor hub pull --id 2 --page +``` + +### Pulling in Code + +You can pull in the code with `--py --output=` to save the code to a file, or you cal also run it without `--output` to print the code to the terminal. + +```bash +$ instructor hub pull --id 2 --py --output=run.py +$ instructor hub pull --id 2 --py > run.py +``` + +You can run the code instantly if you `|` it to `python`: + +```bash +$ instructor hub pull --id 2 --py | python +``` + +## Call for Contributions + +We're looking for a bunch more hub examples, if you have a tutorial or example you'd like to add, please open a pull request in `docs/hub` and we'll review it. + +- [ ] Converting the cookbooks to the new format +- [ ] Validator examples +- [ ] Data extraction examples +- [ ] Streaming examples (Iterable and Partial) +- [ ] Batch Parsing examples +- [ ] Open Examples, together, anyscale, ollama, llama-cpp, etc +- [ ] Query Expansion examples +- [ ] Batch Data Processing examples +- [ ] Batch Data Processing examples with Cache diff --git a/docs/hub/multiple_classification.md b/docs/hub/multiple_classification.md new file mode 100644 index 0000000..61254e5 --- /dev/null +++ b/docs/hub/multiple_classification.md @@ -0,0 +1,51 @@ +For multi-label classification, we introduce a new enum class and a different Pydantic model to handle multiple labels. + +```python +import openai +import instructor + +from typing import List, Literal +from pydantic import BaseModel, Field + +# Apply the patch to the OpenAI client +# enables response_model keyword +client = instructor.patch(openai.OpenAI()) + +LABELS = Literal["ACCOUNT", "BILLING", "GENERAL_QUERY"] + + +class MultiClassPrediction(BaseModel): + labels: List[LABELS] = Field( + ..., + description="Only select the labels that apply to the support ticket.", + ) + + +def multi_classify(data: str) -> MultiClassPrediction: + return client.chat.completions.create( + model="gpt-4-turbo-preview", # gpt-3.5-turbo fails + response_model=MultiClassPrediction, + messages=[ + { + "role": "system", + "content": f"You are a support agent at a tech company. Only select the labels that apply to the support ticket.", + }, + { + "role": "user", + "content": f"Classify the following support ticket: {data}", + }, + ], + ) # type: ignore + + +if __name__ == "__main__": + ticket = "My account is locked and I can't access my billing info." + prediction = multi_classify(ticket) + assert {"ACCOUNT", "BILLING"} == {label for label in prediction.labels} + print("input:", ticket) + #> input: My account is locked and I can't access my billing info. + print("labels:", LABELS) + #> labels: typing.Literal['ACCOUNT', 'BILLING', 'GENERAL_QUERY'] + print("prediction:", prediction) + #> prediction: labels=['ACCOUNT', 'BILLING'] +``` diff --git a/docs/hub/single_classification.md b/docs/hub/single_classification.md new file mode 100644 index 0000000..955e15f --- /dev/null +++ b/docs/hub/single_classification.md @@ -0,0 +1,47 @@ +# Single-Label Classification + +This example demonstrates how to perform single-label classification using the OpenAI API. The example uses the `gpt-3.5-turbo` model to classify text as either `SPAM` or `NOT_SPAM`. + +```python +from pydantic import BaseModel, Field +from typing import Literal +from openai import OpenAI +import instructor + +# Apply the patch to the OpenAI client +# enables response_model keyword +client = instructor.patch(OpenAI()) + + +class ClassificationResponse(BaseModel): + label: Literal["SPAM", "NOT_SPAM"] = Field( + ..., + description="The predicted class label.", + ) + + +def classify(data: str) -> ClassificationResponse: + """Perform single-label classification on the input text.""" + return client.chat.completions.create( + model="gpt-3.5-turbo", + response_model=ClassificationResponse, + messages=[ + { + "role": "user", + "content": f"Classify the following text: {data}", + }, + ], + ) + + +if __name__ == "__main__": + for text, label in [ + ("Hey Jason! You're awesome", "NOT_SPAM"), + ("I am a nigerian prince and I need your help.", "SPAM"), + ]: + prediction = classify(text) + assert prediction.label == label + print(f"Text: {text}, Predicted Label: {prediction.label}") + #> Text: Hey Jason! You're awesome, Predicted Label: NOT_SPAM + #> Text: I am a nigerian prince and I need your help., Predicted Label: SPAM +``` diff --git a/instructor-hub-proxy/.editorconfig b/instructor-hub-proxy/.editorconfig new file mode 100644 index 0000000..64ab260 --- /dev/null +++ b/instructor-hub-proxy/.editorconfig @@ -0,0 +1,13 @@ +# http://editorconfig.org +root = true + +[*] +indent_style = tab +tab_width = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.yml] +indent_style = space diff --git a/instructor-hub-proxy/.gitignore b/instructor-hub-proxy/.gitignore new file mode 100644 index 0000000..3b0fe33 --- /dev/null +++ b/instructor-hub-proxy/.gitignore @@ -0,0 +1,172 @@ +# Logs + +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) + +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data + +pids +_.pid +_.seed +\*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover + +lib-cov + +# Coverage directory used by tools like istanbul + +coverage +\*.lcov + +# nyc test coverage + +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release + +# Dependency directories + +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +\*.tsbuildinfo + +# Optional npm cache directory + +.npm + +# Optional eslint cache + +.eslintcache + +# Optional stylelint cache + +.stylelintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +\*.tgz + +# Yarn Integrity file + +.yarn-integrity + +# dotenv environment variable files + +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) + +.cache +.parcel-cache + +# Next.js build output + +.next +out + +# Nuxt.js build / generate output + +.nuxt +dist + +# Gatsby files + +.cache/ + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# vuepress v2.x temp and cache directory + +.temp +.cache + +# Docusaurus cache and generated files + +.docusaurus + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + +# Stores VSCode versions used for testing VSCode extensions + +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.\* + +# wrangler project + +.dev.vars +.wrangler/ diff --git a/instructor-hub-proxy/.prettierrc b/instructor-hub-proxy/.prettierrc new file mode 100644 index 0000000..5c7b5d3 --- /dev/null +++ b/instructor-hub-proxy/.prettierrc @@ -0,0 +1,6 @@ +{ + "printWidth": 140, + "singleQuote": true, + "semi": true, + "useTabs": true +} diff --git a/instructor-hub-proxy/create.sql b/instructor-hub-proxy/create.sql new file mode 100644 index 0000000..267bfe0 --- /dev/null +++ b/instructor-hub-proxy/create.sql @@ -0,0 +1,10 @@ +CREATE TABLE hub_analytics ( + id SERIAL PRIMARY KEY, + event_type VARCHAR(255) NOT NULL, + user_agent VARCHAR(255) NOT NULL, + request_ip VARCHAR(100) NOT NULL, + request_time TIMESTAMP WITH TIME ZONE NOT NULL, + branch VARCHAR(255) NOT NULL, + slug VARCHAR(255) NOT NULL +); + diff --git a/instructor-hub-proxy/package-lock.json b/instructor-hub-proxy/package-lock.json new file mode 100644 index 0000000..34df987 --- /dev/null +++ b/instructor-hub-proxy/package-lock.json @@ -0,0 +1,1322 @@ +{ + "name": "instructor-hub-proxy", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "instructor-hub-proxy", + "version": "0.0.0", + "dependencies": { + "fuse.js": "^7.0.0", + "yaml": "^2.3.4" + }, + "devDependencies": { + "@cloudflare/workers-types": "^4.20240208.0", + "itty-router": "^3.0.12", + "typescript": "^5.0.4", + "wrangler": "^3.0.0" + } + }, + "node_modules/@cloudflare/kv-asset-handler": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.3.1.tgz", + "integrity": "sha512-lKN2XCfKCmpKb86a1tl4GIwsJYDy9TGuwjhDELLmpKygQhw8X2xR4dusgpC5Tg7q1pB96Eb0rBo81kxSILQMwA==", + "dev": true, + "dependencies": { + "mime": "^3.0.0" + } + }, + "node_modules/@cloudflare/workerd-darwin-64": { + "version": "1.20240129.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20240129.0.tgz", + "integrity": "sha512-DfVVB5IsQLVcWPJwV019vY3nEtU88c2Qu2ST5SQxqcGivZ52imagLRK0RHCIP8PK4piSiq90qUC6ybppUsw8eg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-darwin-arm64": { + "version": "1.20240129.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20240129.0.tgz", + "integrity": "sha512-t0q8ABkmumG1zRM/MZ/vIv/Ysx0vTAXnQAPy/JW5aeQi/tqrypXkO9/NhPc0jbF/g/hIPrWEqpDgEp3CB7Da7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-linux-64": { + "version": "1.20240129.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20240129.0.tgz", + "integrity": "sha512-sFV1uobHgDI+6CKBS/ZshQvOvajgwl6BtiYaH4PSFSpvXTmRx+A9bcug+6BnD+V4WgwxTiEO2iR97E1XuwDAVw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-linux-arm64": { + "version": "1.20240129.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20240129.0.tgz", + "integrity": "sha512-O7q7htHaFRp8PgTqNJx1/fYc3+LnvAo6kWWB9a14C5OWak6AAZk42PNpKPx+DXTmGvI+8S1+futBGUeJ8NPDXg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-windows-64": { + "version": "1.20240129.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20240129.0.tgz", + "integrity": "sha512-YqGno0XSqqqkDmNoGEX6M8kJlI2lEfWntbTPVtHaZlaXVR9sWfoD7TEno0NKC95cXFz+ioyFLbgbOdnfWwmVAA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workers-types": { + "version": "4.20240208.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20240208.0.tgz", + "integrity": "sha512-MVGTTjZpJu4kJONvai5SdJzWIhOJbuweVZ3goI7FNyG+JdoQH41OoB+nMhLsX626vPLZVWGPIWsiSo/WZHzgQw==", + "dev": true + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-plugins/node-globals-polyfill": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-globals-polyfill/-/node-globals-polyfill-0.2.3.tgz", + "integrity": "sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==", + "dev": true, + "peerDependencies": { + "esbuild": "*" + } + }, + "node_modules/@esbuild-plugins/node-modules-polyfill": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-modules-polyfill/-/node-modules-polyfill-0.2.2.tgz", + "integrity": "sha512-LXV7QsWJxRuMYvKbiznh+U1ilIop3g2TeKRzUxOG5X3YITc8JyyTa90BmLwqqv0YnX4v32CSlG+vsziZp9dMvA==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^4.0.0", + "rollup-plugin-node-polyfills": "^0.2.1" + }, + "peerDependencies": { + "esbuild": "*" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", + "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", + "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", + "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", + "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", + "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", + "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", + "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", + "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", + "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", + "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", + "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", + "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", + "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", + "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", + "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", + "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", + "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", + "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", + "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", + "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", + "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", + "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@fastify/busboy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz", + "integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@types/node": { + "version": "20.11.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.19.tgz", + "integrity": "sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/as-table": { + "version": "1.0.55", + "resolved": "https://registry.npmjs.org/as-table/-/as-table-1.0.55.tgz", + "integrity": "sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==", + "dev": true, + "dependencies": { + "printable-characters": "^1.0.42" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/blake3-wasm": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/blake3-wasm/-/blake3-wasm-2.1.5.tgz", + "integrity": "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==", + "dev": true + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/capnp-ts": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/capnp-ts/-/capnp-ts-0.7.0.tgz", + "integrity": "sha512-XKxXAC3HVPv7r674zP0VC3RTXz+/JKhfyw94ljvF80yynK6VkTnqE3jMuN8b3dUVmmc43TjyxjW4KTsmB3c86g==", + "dev": true, + "dependencies": { + "debug": "^4.3.1", + "tslib": "^2.2.0" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-2.0.2.tgz", + "integrity": "sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/esbuild": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", + "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.17.19", + "@esbuild/android-arm64": "0.17.19", + "@esbuild/android-x64": "0.17.19", + "@esbuild/darwin-arm64": "0.17.19", + "@esbuild/darwin-x64": "0.17.19", + "@esbuild/freebsd-arm64": "0.17.19", + "@esbuild/freebsd-x64": "0.17.19", + "@esbuild/linux-arm": "0.17.19", + "@esbuild/linux-arm64": "0.17.19", + "@esbuild/linux-ia32": "0.17.19", + "@esbuild/linux-loong64": "0.17.19", + "@esbuild/linux-mips64el": "0.17.19", + "@esbuild/linux-ppc64": "0.17.19", + "@esbuild/linux-riscv64": "0.17.19", + "@esbuild/linux-s390x": "0.17.19", + "@esbuild/linux-x64": "0.17.19", + "@esbuild/netbsd-x64": "0.17.19", + "@esbuild/openbsd-x64": "0.17.19", + "@esbuild/sunos-x64": "0.17.19", + "@esbuild/win32-arm64": "0.17.19", + "@esbuild/win32-ia32": "0.17.19", + "@esbuild/win32-x64": "0.17.19" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true + }, + "node_modules/exit-hook": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz", + "integrity": "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/fuse.js": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.0.0.tgz", + "integrity": "sha512-14F4hBIxqKvD4Zz/XjDc3y94mNZN6pRv3U13Udo0lNLCWRBUsrMv2xwcF/y/Z5sV6+FQW+/ow68cHpm4sunt8Q==", + "engines": { + "node": ">=10" + } + }, + "node_modules/get-source": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/get-source/-/get-source-2.0.12.tgz", + "integrity": "sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==", + "dev": true, + "dependencies": { + "data-uri-to-buffer": "^2.0.0", + "source-map": "^0.6.1" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/hasown": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", + "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/itty-router": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/itty-router/-/itty-router-3.0.12.tgz", + "integrity": "sha512-s98XTPhle6GGbaFf0kYrOD3Q8gyhnqvOqkwYijC3AmkceNKqWUp13YHg6dWmqmVv4pP7l7c94XI92I0EXVGO0w==", + "dev": true + }, + "node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dev": true, + "dependencies": { + "sourcemap-codec": "^1.4.8" + } + }, + "node_modules/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/miniflare": { + "version": "3.20240129.3", + "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20240129.3.tgz", + "integrity": "sha512-PCmLJ+UvtbpPj/fgNzTGbd+U5QBkt3akRNcdks9RBJU2SH+gUCp7iahsaI4GA344NX5MIbC6ctw1A6TfcA+aFA==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "0.8.1", + "acorn": "^8.8.0", + "acorn-walk": "^8.2.0", + "capnp-ts": "^0.7.0", + "exit-hook": "^2.2.1", + "glob-to-regexp": "^0.4.1", + "stoppable": "^1.1.0", + "undici": "^5.28.2", + "workerd": "1.20240129.0", + "ws": "^8.11.0", + "youch": "^3.2.2", + "zod": "^3.20.6" + }, + "bin": { + "miniflare": "bootstrap.js" + }, + "engines": { + "node": ">=16.13" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "dev": true, + "bin": { + "mustache": "bin/mustache" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-to-regexp": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", + "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/printable-characters": { + "version": "1.0.42", + "resolved": "https://registry.npmjs.org/printable-characters/-/printable-characters-1.0.42.tgz", + "integrity": "sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==", + "dev": true + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/rollup-plugin-inject": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-inject/-/rollup-plugin-inject-3.0.2.tgz", + "integrity": "sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==", + "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject.", + "dev": true, + "dependencies": { + "estree-walker": "^0.6.1", + "magic-string": "^0.25.3", + "rollup-pluginutils": "^2.8.1" + } + }, + "node_modules/rollup-plugin-node-polyfills": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-node-polyfills/-/rollup-plugin-node-polyfills-0.2.1.tgz", + "integrity": "sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==", + "dev": true, + "dependencies": { + "rollup-plugin-inject": "^3.0.0" + } + }, + "node_modules/rollup-pluginutils": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", + "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "dev": true, + "dependencies": { + "estree-walker": "^0.6.1" + } + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dev": true, + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "deprecated": "Please use @jridgewell/sourcemap-codec instead", + "dev": true + }, + "node_modules/stacktracey": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/stacktracey/-/stacktracey-2.1.8.tgz", + "integrity": "sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw==", + "dev": true, + "dependencies": { + "as-table": "^1.0.36", + "get-source": "^2.0.12" + } + }, + "node_modules/stoppable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", + "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==", + "dev": true, + "engines": { + "node": ">=4", + "npm": ">=6" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici": { + "version": "5.28.3", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.3.tgz", + "integrity": "sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==", + "dev": true, + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/workerd": { + "version": "1.20240129.0", + "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20240129.0.tgz", + "integrity": "sha512-t4pnsmjjk/u+GdVDgH2M1AFmJaBUABshYK/vT/HNrAXsHSwN6VR8Yqw0JQ845OokO34VLkuUtYQYyxHHKpdtsw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "workerd": "bin/workerd" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "@cloudflare/workerd-darwin-64": "1.20240129.0", + "@cloudflare/workerd-darwin-arm64": "1.20240129.0", + "@cloudflare/workerd-linux-64": "1.20240129.0", + "@cloudflare/workerd-linux-arm64": "1.20240129.0", + "@cloudflare/workerd-windows-64": "1.20240129.0" + } + }, + "node_modules/wrangler": { + "version": "3.28.3", + "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.28.3.tgz", + "integrity": "sha512-pLuvWA5W8FhjI/a7Mr5F491KOqNMYzyWVN7dmwr+52sPv2BFrfN1v6btmhHYotSblCH8yfs5DmuxwdKuVPMw9w==", + "dev": true, + "dependencies": { + "@cloudflare/kv-asset-handler": "0.3.1", + "@esbuild-plugins/node-globals-polyfill": "^0.2.3", + "@esbuild-plugins/node-modules-polyfill": "^0.2.2", + "blake3-wasm": "^2.1.5", + "chokidar": "^3.5.3", + "esbuild": "0.17.19", + "miniflare": "3.20240129.3", + "nanoid": "^3.3.3", + "path-to-regexp": "^6.2.0", + "resolve": "^1.22.8", + "resolve.exports": "^2.0.2", + "selfsigned": "^2.0.1", + "source-map": "0.6.1", + "xxhash-wasm": "^1.0.1" + }, + "bin": { + "wrangler": "bin/wrangler.js", + "wrangler2": "bin/wrangler.js" + }, + "engines": { + "node": ">=16.17.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@cloudflare/workers-types": "^4.20230914.0" + }, + "peerDependenciesMeta": { + "@cloudflare/workers-types": { + "optional": true + } + } + }, + "node_modules/ws": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", + "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xxhash-wasm": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.0.2.tgz", + "integrity": "sha512-ibF0Or+FivM9lNrg+HGJfVX8WJqgo+kCLDc4vx6xMeTce7Aj+DLttKbxxRR/gNLSAelRc1omAPlJ77N/Jem07A==", + "dev": true + }, + "node_modules/yaml": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "engines": { + "node": ">= 14" + } + }, + "node_modules/youch": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/youch/-/youch-3.3.3.tgz", + "integrity": "sha512-qSFXUk3UZBLfggAW3dJKg0BMblG5biqSF8M34E06o5CSsZtH92u9Hqmj2RzGiHDi64fhe83+4tENFP2DB6t6ZA==", + "dev": true, + "dependencies": { + "cookie": "^0.5.0", + "mustache": "^4.2.0", + "stacktracey": "^2.1.8" + } + }, + "node_modules/zod": { + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", + "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/instructor-hub-proxy/package.json b/instructor-hub-proxy/package.json new file mode 100644 index 0000000..83afddb --- /dev/null +++ b/instructor-hub-proxy/package.json @@ -0,0 +1,20 @@ +{ + "name": "instructor-hub-proxy", + "version": "0.0.0", + "private": true, + "scripts": { + "deploy": "wrangler deploy", + "dev": "wrangler dev", + "start": "wrangler dev" + }, + "devDependencies": { + "@cloudflare/workers-types": "^4.20240208.0", + "itty-router": "^3.0.12", + "typescript": "^5.0.4", + "wrangler": "^3.0.0" + }, + "dependencies": { + "fuse.js": "^7.0.0", + "yaml": "^2.3.4" + } +} diff --git a/instructor-hub-proxy/src/index.ts b/instructor-hub-proxy/src/index.ts new file mode 100644 index 0000000..5dcaa56 --- /dev/null +++ b/instructor-hub-proxy/src/index.ts @@ -0,0 +1,27 @@ +/** + * Welcome to Cloudflare Workers! This is your first worker. + * + * - Run `npm run dev` in your terminal to start a development server + * - Open a browser tab at http://localhost:8787/ to see your worker in action + * - Run `npm run deploy` to publish your worker + * + * Learn more at https://developers.cloudflare.com/workers/ + */ + +import apiRouter from './router'; + +export interface Env { + // If you set another name in wrangler.toml as the value for 'binding', + // replace "DB" with the variable name you defined. + DB: D1Database; +} +// Export a default object containing event handlers +export default { + // The fetch handler is invoked when this worker receives a HTTP(S) request + // and should return a Response (optionally wrapped in a Promise) + async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise { + // @ts-ignore + request.env = env; + return apiRouter.handle(request); + }, +}; diff --git a/instructor-hub-proxy/src/router.ts b/instructor-hub-proxy/src/router.ts new file mode 100644 index 0000000..12e4fd8 --- /dev/null +++ b/instructor-hub-proxy/src/router.ts @@ -0,0 +1,128 @@ +import { Router } from 'itty-router'; +import YAML from 'yaml'; +import Fuse from 'fuse.js'; + +// now let's create a router (note the lack of "new") +const router = Router(); + +// Function to track analytics +async function trackAnalytics(request: any, env: Env, event_type: string, slug: string, branch: string) { + const user_agent = request.headers.get('User-Agent') || 'unknown'; + const request_ip = request.headers.get('CF-Connecting-IP') || 'unknown'; // Cloudflare passes the client IP + const request_time = new Date().toISOString(); + + // Prepare and execute the insert statement for analytics tracking + // @ts-ignore + await env.DB.prepare( + 'INSERT INTO hub_analytics (event_type, user_agent, request_ip, request_time, slug, branch) VALUES (?, ?, ?, ?, ?, ?)' + ) + .bind(event_type, user_agent, request_ip, request_time, slug, branch) + .run(); +} + +// GET collection index +router.get('/api/:branch/items', async (request) => { + const { query, params, env } = request; + await trackAnalytics(request, env, 'COLLECTION_INDEX', 'index', params.branch); + + /** + * { + * success: true, + * meta: {...}, + * results: [ { slug: 'single_classification', 'n': 2 } ] + * } + */ + const counts = await env.DB.prepare( + `SELECT slug, count(1) as n + FROM hub_analytics + WHERE branch = ? AND event_type != 'COLLECTION_INDEX' + GROUP BY slug` + ) + .bind(params.branch) + .all(); + + const url = `https://raw.githubusercontent.com/jxnl/instructor/${params.branch}/mkdocs.yml?raw=true`; + const mkdoc_yml = await fetch(url).then((res) => res.text()); + const mkdocs = YAML.parse(mkdoc_yml); + var cookbooks = mkdocs.nav + ?.filter((obj: Map) => 'Hub' in obj)[0] + .Hub.map((obj: any, index: number) => { + const [name, path] = Object.entries(obj)[0]; + // Extract slug by getting the substring after the last '/' + // @ts-ignore + const slug = path.substring(path.lastIndexOf('/') + 1, path.lastIndexOf('.')); + const count = counts.results.find((obj: any) => obj.slug === slug)?.n || 0; + return { id: index, name, path, slug, count }; + }) + .filter(({ slug }: any) => slug !== 'index'); + + // Search for cookbooks + const queryStr = query.q; + if (queryStr !== undefined && queryStr !== '') { + const fuse = new Fuse(cookbooks, { + keys: ['name', 'slug'], + threshold: 0.3, + }); + cookbooks = fuse.search(queryStr as string).map((obj: any) => obj.item); + } + + return new Response(JSON.stringify(cookbooks), { + headers: { + 'content-type': 'application/json', + }, + }); +}); + +// GET content +router.get('/api/:branch/items/:slug/md', async (request) => { + const { params, env } = request; + await trackAnalytics(request, env, 'CONTENT_MARKDOWN', params.slug, params.branch); + const raw_content = `https://raw.githubusercontent.com/jxnl/instructor/${params.branch}/docs/hub/${params.slug}.md?raw=true`; + const content = await fetch(raw_content).then((res) => res.text()); + + return new Response(content, { + headers: { + 'content-type': 'text/plain', + }, + }); +}); + +// GET content python +router.get('/api/:branch/items/:slug/py', async (request) => { + const { params, env } = request; + await trackAnalytics(request, env, 'CONTENT_PYTHON', params.slug, params.branch); + const raw_content = `https://raw.githubusercontent.com/jxnl/instructor/${params.branch}/docs/hub/${params.slug}.md?raw=true`; + const content = await fetch(raw_content).then((res) => res.text()); + + // Extract all Python code blocks from within ```py or ```python blocks in the markdown + const python_codes = content.match(/(?<=```(?:py|python)\n)[\s\S]+?(?=\n```)/g); + + if (python_codes === null) { + return new Response('No Python code found in this document.', { + headers: { + 'content-type': 'text/plain', + }, + }); + } + + if (python_codes.length === 0) { + return new Response('No Python code found in this document.', { + headers: { + 'content-type': 'text/plain', + }, + }); + } + + const python_code = python_codes.join('\n\n'); + + return new Response(python_code, { + headers: { + 'content-type': 'text/plain', + }, + }); +}); + +// 404 for everything else +router.all('*', () => new Response('Not Found.', { status: 404 })); + +export default router; diff --git a/instructor-hub-proxy/tsconfig.json b/instructor-hub-proxy/tsconfig.json new file mode 100644 index 0000000..b08cfd9 --- /dev/null +++ b/instructor-hub-proxy/tsconfig.json @@ -0,0 +1,103 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Projects */ + // "incremental": true, /* Enable incremental compilation */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2021" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + "lib": ["es2021"] /* Specify a set of bundled library declaration files that describe the target runtime environment. */, + "jsx": "react" /* Specify what JSX code is generated. */, + // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ + // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + + /* Modules */ + "module": "es2022" /* Specify what module code is generated. */, + // "rootDir": "./", /* Specify the root folder within your source files. */ + "moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */, + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ + "types": [ + "@cloudflare/workers-types/2023-07-01" + ] /* Specify type package names to be included without being referenced in a source file. */, + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + "resolveJsonModule": true /* Enable importing .json files */, + // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + "allowJs": true /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */, + "checkJs": false /* Enable error reporting in type-checked JavaScript files. */, + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + "noEmit": true /* Disable emitting files from a compilation. */, + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + "isolatedModules": true /* Ensure that each file can be safely transpiled without relying on other imports. */, + "allowSyntheticDefaultImports": true /* Allow 'import x from y' when a module doesn't have a default export. */, + // "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */, + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + + /* Type Checking */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ + // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ + // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} diff --git a/instructor-hub-proxy/worker-configuration.d.ts b/instructor-hub-proxy/worker-configuration.d.ts new file mode 100644 index 0000000..963ac89 --- /dev/null +++ b/instructor-hub-proxy/worker-configuration.d.ts @@ -0,0 +1,16 @@ +interface Env { + // Example binding to KV. Learn more at https://developers.cloudflare.com/workers/runtime-apis/kv/ + // MY_KV_NAMESPACE: KVNamespace; + // + // Example binding to Durable Object. Learn more at https://developers.cloudflare.com/workers/runtime-apis/durable-objects/ + // MY_DURABLE_OBJECT: DurableObjectNamespace; + // + // Example binding to R2. Learn more at https://developers.cloudflare.com/workers/runtime-apis/r2/ + // MY_BUCKET: R2Bucket; + // + // Example binding to a Service. Learn more at https://developers.cloudflare.com/workers/runtime-apis/service-bindings/ + // MY_SERVICE: Fetcher; + // + // Example binding to a Queue. Learn more at https://developers.cloudflare.com/queues/javascript-apis/ + // MY_QUEUE: Queue; +} diff --git a/instructor-hub-proxy/wrangler.toml b/instructor-hub-proxy/wrangler.toml new file mode 100644 index 0000000..df32278 --- /dev/null +++ b/instructor-hub-proxy/wrangler.toml @@ -0,0 +1,56 @@ +name = "instructor-hub-proxy" +main = "src/index.ts" +compatibility_date = "2024-02-08" + +# Variable bindings. These are arbitrary, plaintext strings (similar to environment variables) +# Note: Use secrets to store sensitive data. +# Docs: https://developers.cloudflare.com/workers/platform/environment-variables +# [vars] +# MY_VARIABLE = "production_value" + +# Bind a KV Namespace. Use KV as persistent storage for small key-value pairs. +# Docs: https://developers.cloudflare.com/workers/runtime-apis/kv +# [[kv_namespaces]] +# binding = "MY_KV_NAMESPACE" +# id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + +# Bind an R2 Bucket. Use R2 to store arbitrarily large blobs of data, such as files. +# Docs: https://developers.cloudflare.com/r2/api/workers/workers-api-usage/ +# [[r2_buckets]] +# binding = "MY_BUCKET" +# bucket_name = "my-bucket" + +# Bind a Queue producer. Use this binding to schedule an arbitrary task that may be processed later by a Queue consumer. +# Docs: https://developers.cloudflare.com/queues/get-started +# [[queues.producers]] +# binding = "MY_QUEUE" +# queue = "my-queue" + +# Bind a Queue consumer. Queue Consumers can retrieve tasks scheduled by Producers to act on them. +# Docs: https://developers.cloudflare.com/queues/get-started +# [[queues.consumers]] +# queue = "my-queue" + +# Bind another Worker service. Use this binding to call another Worker without network overhead. +# Docs: https://developers.cloudflare.com/workers/platform/services +# [[services]] +# binding = "MY_SERVICE" +# service = "my-service" + +# Bind a Durable Object. Durable objects are a scale-to-zero compute primitive based on the actor model. +# Durable Objects can live for as long as needed. Use these when you need a long-running "server", such as in realtime apps. +# Docs: https://developers.cloudflare.com/workers/runtime-apis/durable-objects +# [[durable_objects.bindings]] +# name = "MY_DURABLE_OBJECT" +# class_name = "MyDurableObject" + +# Durable Object migrations. +# Docs: https://developers.cloudflare.com/workers/learning/using-durable-objects#configure-durable-object-classes-with-migrations +# [[migrations]] +# tag = "v1" +# new_classes = ["MyDurableObject"] + +[[d1_databases]] +binding = "DB" # i.e. available in your Worker on env.DB +database_name = "cli_analytics" +database_id = "607034d8-267d-42d7-8c0b-462aec83d955" \ No newline at end of file diff --git a/instructor/cli/cli.py b/instructor/cli/cli.py index 46fd5a0..d6efae9 100644 --- a/instructor/cli/cli.py +++ b/instructor/cli/cli.py @@ -2,6 +2,7 @@ import typer import instructor.cli.jobs as jobs import instructor.cli.files as files import instructor.cli.usage as usage +import instructor.cli.hub as hub app = typer.Typer( name="instructor-ft", @@ -11,3 +12,4 @@ app = typer.Typer( app.add_typer(jobs.app, name="jobs", help="Monitor and create fine tuning jobs") app.add_typer(files.app, name="files", help="Manage files on OpenAI's servers") app.add_typer(usage.app, name="usage", help="Check OpenAI API usage data") +app.add_typer(hub.app, name="hub", help="Interact with the instructor hub") diff --git a/instructor/cli/hub.py b/instructor/cli/hub.py new file mode 100644 index 0000000..abd804e --- /dev/null +++ b/instructor/cli/hub.py @@ -0,0 +1,167 @@ +from typing import Optional + +import typer +import httpx + +from pydantic import BaseModel +from rich.console import Console +from rich.table import Table +from rich.markdown import Markdown + +app = typer.Typer( + name="hub", + help="Interact with the instructor hub, a collection of examples and cookbooks for the instructor library.", + short_help="Interact with the instructor hub", +) +console = Console() + + +class HubPage(BaseModel): + id: int + name: str + slug: str + branch: str = "main" + count: int = 0 + + def get_doc_url(self) -> str: + return f"https://jxnl.github.io/instructor/hub/{self.slug}/" + + def get_md_url(self) -> str: + return f"https://raw.githubusercontent.com/jxnl/instructor/{self.branch}/docs/hub/{self.slug}.md?raw=true" + + def render_doc_link(self) -> str: + return f"[link={self.get_doc_url()}](doc)[/link]" + + def render_slug(self) -> str: + return f"{self.slug} {self.render_doc_link()}" + + +class HubClient: + def __init__( + self, base_url: str = "https://instructor-hub-proxy.jason-a3f.workers.dev" + ): + self.base_url = base_url + + def get_cookbooks(self, branch: str, q: Optional[str] = None, sort: bool = False): + """Get collection index of cookbooks.""" + url = f"{self.base_url}/api/{branch}/items/" + + if q: + url += f"?q={q}" + + response = httpx.get(url) + if response.status_code == 200: + pages = [HubPage(**page) for page in response.json()] + if sort: + return sorted(pages, key=lambda x: x.count, reverse=True) + return pages + else: + raise Exception(f"Failed to fetch cookbooks: {response.status_code}") + + def get_content_markdown(self, branch, slug): + """Get markdown content.""" + url = f"{self.base_url}/api/{branch}/items/{slug}/md/" + response = httpx.get(url) + if response.status_code == 200: + return response.text + else: + raise Exception(f"Failed to fetch markdown content: {response.status_code}") + + def get_content_python(self, branch, slug): + """Get Python code blocks from content.""" + url = f"{self.base_url}/api/{branch}/items/{slug}/py/" + response = httpx.get(url) + if response.status_code == 200: + return response.text + else: + raise Exception(f"Failed to fetch Python content: {response.status_code}") + + def get_cookbook_id(self, id: int, branch: str = "main") -> HubPage: + for cookbook in self.get_cookbooks(branch): + if cookbook.id == id: + return cookbook + + def get_cookbook_slug(self, slug: str, branch: str = "main") -> HubPage: + for cookbook in self.get_cookbooks(branch): + if cookbook.slug == slug: + return cookbook + + +@app.command( + "list", + help="List all available cookbooks", + short_help="List all available cookbooks", +) +def list_cookbooks( + q: Optional[str] = typer.Option(None, "-q", help="Search for cookbooks by name"), + sort: bool = typer.Option(False, "--sort", help="Sort the cookbooks by popularity"), + branch: str = typer.Option( + "main", + "--branch", + "-b", + help="Specific branch to fetch the cookbooks from. Defaults to 'main'.", + ), +): + table = Table(title="Available Cookbooks") + table.add_column("hub_id", justify="right", style="cyan", no_wrap=True) + table.add_column("slug", style="green") + table.add_column("title", style="white") + table.add_column("n_downloads", justify="right") + + client = HubClient() + for cookbook in client.get_cookbooks(branch, q=q, sort=sort): + ii = cookbook.id + slug = cookbook.render_slug() + title = cookbook.name + table.add_row(str(ii), slug, title, str(cookbook.count)) + + console.print(table) + + +@app.command( + "pull", + help="Pull the latest cookbooks from the instructor hub, optionally outputting to a file", + short_help="Pull the latest cookbooks", +) +def pull( + id: Optional[int] = typer.Option(None, "--id", "-i", help="The cookbook id"), + slug: Optional[str] = typer.Option(None, "--slug", "-s", help="The cookbook slug"), + py: bool = typer.Option(False, "--py", help="Output to a Python file"), + file: Optional[str] = typer.Option(None, "--output", help="Output to a file"), + branch: str = typer.Option( + "main", help="Specific branch to fetch the cookbooks from." + ), + page: bool = typer.Option( + False, "--page", "-p", help="Paginate the output with a less-like pager" + ), +): + client = HubClient() + cookbook = ( + client.get_cookbook_id(id, branch=branch) + if id + else client.get_cookbook_slug(slug, branch=branch) + if slug + else None + ) + if not cookbook: + typer.echo("Please provide a valid cookbook id or slug.") + raise typer.Exit(code=1) + + output = ( + client.get_content_python(branch, cookbook.slug) + if py + else Markdown(client.get_content_markdown(branch, cookbook.slug)) + ) + + if file: + with open(file, "w") as f: + f.write(output) + return + + if page: + with console.pager(styles=True): + console.print(output) + elif py: + print(output) + else: + console.print(output) diff --git a/mkdocs.yml b/mkdocs.yml index a2e9155..12135f4 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -114,7 +114,6 @@ markdown_extensions: - pymdownx.tabbed: alternate_style: true combine_header_slug: true - slugify: !!python/object/apply:pymdownx.slugs.slugify - pymdownx.tasklist: custom_checkbox: true nav: @@ -164,6 +163,10 @@ nav: - Image to Ad Copy: 'examples/image_to_ad_copy.md' - Ollama: 'examples/ollama.md' - SQLModel Integration: 'examples/sqlmodel.md' + - Hub: + - Introduction: 'hub/index.md' + - Single Classification Model: 'hub/single_classification.md' + - Multiple Classification Model: 'hub/multiple_classification.md' - Tutorials: - Introduction: 'tutorials/1-introduction.ipynb' - Tips and Tricks: 'tutorials/2-tips.ipynb' @@ -234,5 +237,4 @@ extra: - icon: fontawesome/brands/twitter link: https://twitter.com/jxnlco - icon: fontawesome/brands/github - link: https://github.com/jxnl -copyright: Copyright © 2023 Jason Liu + link: https://github.com/jxnl \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index ef2a620..32b562d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "instructor" -version = "0.5.2" +version = "0.6.0" description = "structured outputs for llm" authors = ["Jason Liu "] license = "MIT" diff --git a/tests/openai/docs/test_hub.py b/tests/openai/docs/test_hub.py new file mode 100644 index 0000000..5c982a3 --- /dev/null +++ b/tests/openai/docs/test_hub.py @@ -0,0 +1,12 @@ +import pytest +from pytest_examples import find_examples, CodeExample, EvalExample + + +@pytest.mark.parametrize("example", find_examples("docs/hub"), ids=str) +def test_format_blog(example: CodeExample, eval_example: EvalExample): + if eval_example.update_examples: + eval_example.format(example) + eval_example.run_print_update(example) + else: + eval_example.lint(example) + eval_example.run(example) diff --git a/tutorials/README.md b/tutorials/README.md deleted file mode 100644 index 524c36e..0000000 --- a/tutorials/README.md +++ /dev/null @@ -1,64 +0,0 @@ -# Introduction - -This section includes a list of notebooks that walk you through some simple concepts in Instructor. We start small and then work our way up to more complex and tricky implementations using the library. - -## Overview - -Currently we have the following notebooks avaliable - -1. `Introduction` - This is a quick walkthrough some of the benefits of Pydantic and how the Instructor Library integrates nicely with Pydantic with `instructor.patch()` - -2. `Tips` - Quick demonstration of how to use enums, `Pydantic` models and structured prompting to get specific output formats - -3. `Applications Rag`: Learn how to generate nested models with `Pydantic` by rewriting user queries - -4. `Knowledge Graphs`: Dive deep into the use of LLMs to break down complex topics into simple knowledge graphs - -5. `Validation` : Learn how to use Pydantic's inbuilt validators to perform more complex validation and checks on the outputs of your functions - -6. `Chain Of Density` : Learn how to produce high quality summaries that consistently beat out human-generated ones using `Chain of Density` summarization. - - - -## Installation - -We utilise the Graphviz package in this tutorial series. If you don't have it on hand, you should download it. Mac users can do so by running `brew install graphviz` while Linux users can try `sudo apt install graphviz` ( modify to your system specific package manager). Here is a link to their official [documentation](https://graphviz.org/download/) - -If you're encountering an error like the following when trying to run graphviz after installing it, just restart the notebook and verify you've got graphviz installed by running `dot -v` in your shell. - -``` -Command '[PosixPath('dot'), '-Kdot', '-Tsvg']' died with . -``` - -Here are the steps to start running the notebooks - -1. Create a virtual environment - -``` -python3 -m venv .venv -source .venv .venv/bin/activate -``` - -2. Install the dependencies - -``` -pip3 install -r requirements.txt -``` - -3. Add the virtual environment to Jupyter notebook - -``` -python -m ipykernel install --user --name=instructor-env -``` - -4. Add OpenAI API Key into your shell by running the following command. This will be set for as long as the shell is open. - -``` -export OPENAI_API_KEY= -``` - -5. Start Jupyter Notebook - -``` -jupyter notebook -``` \ No newline at end of file diff --git a/tutorials/assets/article.txt b/tutorials/assets/article.txt deleted file mode 100644 index 28b96b5..0000000 --- a/tutorials/assets/article.txt +++ /dev/null @@ -1 +0,0 @@ -We are used to seeing celebrities airbrushed to perfection but this weekend two fabulous famous females have spoken out about their normal bodies. Model Chrissy Teigen proudly showed off her stretch marks in an Instagram post that has been praised by her fans. And the singer Pink hit back at critics who fat shamed her for an outfit she wore to a recent charity event alongside her husband Carey Hart. Scroll down for video . Model Chrissy Teigen was praised this week as she posted a picture of herself to Instagram showing off her stretch marks . Chrissy's fans were happy that she shared the picture, with one of them commenting that 'real women' have stretch marks . Chrissy, 29, posted the picture of her thighs which had clear stretch marks on them saying: 'Bruises from bumping kitchen drawer handles for a week. Stretchies say hi!' She received praise from many fans, such as Instagram user @saraelizabef  who said: 'Love it! Real women have stretch marks #respect'. Another follower, @emmalittle5, commented: 'I have so much respect for you! I have stretchies too and I appreciate someone being real about them and acknowledging them thanks.' Meanwhile, Pink took to Twitter to speak out against those who had commented on her weight at an event she attended to support a doctor friend. She said: 'I can see that some of you are concerned about me from your comments about my weight. 'You’re referring to the pictures of me from last night’s cancer benefit that I attended to support my dear friend Dr Maggie DiNome. The singer Pink hit back at those who criticised her weight at an event recently, saying that she was happy with her body . In a message posted to her Twitter account Pink jokingly referred to herself as 'cheesecake' and said that she felt beautiful in her dress . She continued: 'She was given the Duke Award for her tireless efforts and stellar contributions to the eradication of cancer. But unfortunately, my weight seems much more important to some of you. 'While I admit that the dress didn’t photograph as well as it did in my kitchen, I will also admit that I felt very pretty. In fact, I feel beautiful. 'So, my good and concerned peoples, please don’t worry about me. I’m not worried about me. And I’m not worried about you either:)… . 'I am perfectly fine, perfectly happy, and my healthy, voluptuous and crazy strong body is having some much deserved time off. Thanks for your concern. Love, cheesecake.' And Chrissy and Pink aren't the first stars to make comments about their bodies or to be keen to show off their more natural selves. Kelly Clarkson recently gave an interview to Ellen DeGeneres in which she said that she was used to being bullied about her weight . Recently Kelly Clarkson gave an interview to American chat show host Ellen DeGeneres in which she discussed how she had been facing criticism for her weight for years. She said: 'I’m such a creative person that I yo yo. So sometimes I’m more fit and I get into kickboxing hardcore. And then sometimes I don’t and I’m like.. I’d rather have wine.' 'We are who we are. Whatever size,' Kelly told Ellen, prompting applause from the studio audience. 'You know, if it’s you, you’re just like whatever,' she said. 'I think what hurts my feelings..... is that I’ll have a meet and greet after the show and a girl who is, like, bigger than me will be in the meet and greet and be like, 'wow, if they think you’re big, I must be so fat to them.' In 2012 Girls star and producer Lena Dunham hit back after she was criticised for wearing a pair of short shorts on the red carpet. In 2012 Lena Dunham recieved harsh criticism for this outfit. She said she didn't think a thinner woman would have been criticised in the same way . Lena told her critics: 'I am going to live to be 100, and I am going to show my thighs every day till I die.' She said at the time: 'Last week I wore something to an event...a big top and little shorts, and a bunch of [blog posts] came out that I had been out without pants [trousers],' 'I actually saw it...'Love it or hate it: The no-pants look.' My mom...thought it was so funny. 'My boyfriend was like, 'People seem to be worked up about you going out without pants.' But I didn't go out without pants! I had shorts on.' Lena continued: 'If Olivia Wilde had gone to a party in...little shorts, she might have been on a 'weird dressed list' or been told her outfit was cute. 'I don't think a girl with tiny thighs would have received such no-pants attention. I think what it really was...'Why did you all make us look at your thighs?' 'My response is, get used to it because I am going to live to be 100, and I am going to show my thighs every day till I die.' Tyra Banks' weight has gone up and down over the years and the model says that anyone who doesn't like the way she looks can kiss her fat a** . Former supermodel Tyra Banks similarly hit back after she was subject to mean remarks about her fuller figure. She said: 'To all of you that have something nasty to say about me, or other women that are built like me, women that sometimes or all the time look like this, women whose names you know, women whose names you don't, women who have been picked on, women whose husbands put them down, women at work or girls in school — I have one thing to say to you. Kiss my fat a**!' In 2014 when she was criticised for her appearance at the Golden Globes actress Gabourey Sidibe had the perfect response to her haters. She said: 'To the people making mean comments about my [Golden Globes] pics, I mos def cried about it on that private jet on the way to my dream job last night #jk.' \ No newline at end of file diff --git a/tutorials/helpers.py b/tutorials/helpers.py deleted file mode 100644 index 3d7d5fe..0000000 --- a/tutorials/helpers.py +++ /dev/null @@ -1,32 +0,0 @@ -import pandas as pd - - -def flatten_dict(d, parent_key="", sep="_"): - """ - Flatten a nested dictionary. - - :param d: The nested dictionary to flatten. - :param parent_key: The base key to use for the flattened keys. - :param sep: Separator to use between keys. - :return: A flattened dictionary. - """ - items = [] - for k, v in d.items(): - new_key = f"{parent_key}{sep}{k}" if parent_key else k - if isinstance(v, dict): - items.extend(flatten_dict(v, new_key, sep=sep).items()) - else: - items.append((new_key, v)) - return dict(items) - - -def dicts_to_df(list_of_dicts): - """ - Convert a list of dictionaries to a pandas DataFrame. - - :param list_of_dicts: List of dictionaries, potentially nested. - :return: A pandas DataFrame representing the flattened data. - """ - # Flatten each dictionary and create a DataFrame - flattened_data = [flatten_dict(d) for d in list_of_dicts] - return pd.DataFrame(flattened_data) diff --git a/tutorials/requirements.txt b/tutorials/requirements.txt deleted file mode 100644 index 30f21af..0000000 --- a/tutorials/requirements.txt +++ /dev/null @@ -1,8 +0,0 @@ -ipykernel -jupyter -instructor -openai>=1.1.0 -pydantic -graphviz -spacy -nltk \ No newline at end of file