mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-18 16:02:10 +00:00
feat: generate and fix scripts using Autopilot powered by OpenAI #1827)
* feat(frontend): generate simple script from prompt * feat(backend): add OpenAI key workspace settings * feat(frontend): add OpenAI key workplace settings * feat: proxy to backend + support all languages * fix: openapi spec * feat: ScriptGen new UI + gpt 4 * fix: openai key sqlx data * fix: diffEditor optional * feat: beta + minor improvements * feat: resource type support * feat: edit with AI * feat: AI fix * feat: minor improvements content max length, format, env info * fix: minor
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
-- Add down migration script here
|
||||
ALTER TABLE workspace_settings DROP COLUMN openai_key;
|
||||
@@ -0,0 +1,2 @@
|
||||
-- Add up migration script here
|
||||
ALTER TABLE workspace_settings ADD COLUMN openai_key VARCHAR(255);
|
||||
+65
-4
@@ -734,6 +734,11 @@
|
||||
"name": "error_handler",
|
||||
"ordinal": 11,
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"name": "openai_key",
|
||||
"ordinal": 12,
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"nullable": [
|
||||
@@ -748,6 +753,7 @@
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
],
|
||||
"parameters": {
|
||||
@@ -1257,7 +1263,8 @@
|
||||
"bash",
|
||||
"postgresql",
|
||||
"nativets",
|
||||
"bun"
|
||||
"bun",
|
||||
"mysql"
|
||||
]
|
||||
},
|
||||
"name": "script_lang"
|
||||
@@ -2449,6 +2456,11 @@
|
||||
"name": "error_handler",
|
||||
"ordinal": 11,
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"name": "openai_key",
|
||||
"ordinal": 12,
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"nullable": [
|
||||
@@ -2463,6 +2475,7 @@
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
],
|
||||
"parameters": {
|
||||
@@ -2550,7 +2563,8 @@
|
||||
"bash",
|
||||
"postgresql",
|
||||
"nativets",
|
||||
"bun"
|
||||
"bun",
|
||||
"mysql"
|
||||
]
|
||||
},
|
||||
"name": "script_lang"
|
||||
@@ -2616,6 +2630,18 @@
|
||||
},
|
||||
"query": "UPDATE schedule SET error = NULL WHERE workspace_id = $1 AND path = $2"
|
||||
},
|
||||
"57ab0eabaaef495e12c4f04cb8e3073772f611283c0a424fd8c8f1368742d310": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"nullable": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
}
|
||||
},
|
||||
"query": "UPDATE workspace_settings SET openai_key = NULL WHERE workspace_id = $1"
|
||||
},
|
||||
"5850e0c1f7dee98455027a4c0db6ccea0af2c58aee656ef43964b515de054888": {
|
||||
"describe": {
|
||||
"columns": [
|
||||
@@ -2794,7 +2820,8 @@
|
||||
"bash",
|
||||
"postgresql",
|
||||
"nativets",
|
||||
"bun"
|
||||
"bun",
|
||||
"mysql"
|
||||
]
|
||||
},
|
||||
"name": "script_lang"
|
||||
@@ -3832,6 +3859,26 @@
|
||||
},
|
||||
"query": "DELETE FROM resource WHERE resource_type = 'cache' AND to_timestamp((value->>'expire')::int) < now() RETURNING path"
|
||||
},
|
||||
"87874d29c44f03ff4d7d9cb9dc92900fb5eb6ce38408fe7f8e0f3455c77c3590": {
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "openai_key",
|
||||
"ordinal": 0,
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"nullable": [
|
||||
true
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
}
|
||||
},
|
||||
"query": "SELECT openai_key FROM workspace_settings WHERE workspace_id = $1"
|
||||
},
|
||||
"8876fa929ffb175cd976a2bca1195704aa9fe7215013ae29e49ef15cb201ba57": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
@@ -3895,7 +3942,8 @@
|
||||
"bash",
|
||||
"postgresql",
|
||||
"nativets",
|
||||
"bun"
|
||||
"bun",
|
||||
"mysql"
|
||||
]
|
||||
},
|
||||
"name": "script_lang"
|
||||
@@ -6166,6 +6214,19 @@
|
||||
},
|
||||
"query": "SELECT name, (EXISTS (SELECT 1 FROM (SELECT key, value FROM jsonb_each_text(extra_perms) WHERE key = ANY($1)) t WHERE value::boolean IS true)) as write, $1 && owners::text[] as owner FROM folder\n WHERE extra_perms ?| $1 AND workspace_id = $2"
|
||||
},
|
||||
"d2fefff37e6e0d1c8061f3215cb740b9af6798bf1605e79be0786b1f08b55f02": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"nullable": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Text"
|
||||
]
|
||||
}
|
||||
},
|
||||
"query": "UPDATE workspace_settings SET openai_key = $1 WHERE workspace_id = $2"
|
||||
},
|
||||
"d4bf68b4c2bfd11db84787e41e92c13612fda7352e841f3cdef45ea762588f04": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
|
||||
@@ -971,6 +971,8 @@ paths:
|
||||
type: string
|
||||
deploy_to:
|
||||
type: string
|
||||
openai_key:
|
||||
type: string
|
||||
error_handler:
|
||||
type: string
|
||||
|
||||
@@ -1124,6 +1126,49 @@ paths:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
/w/{workspace}/workspaces/edit_openai_key:
|
||||
post:
|
||||
summary: edit OpenAI key
|
||||
operationId: editOpenaiKey
|
||||
tags:
|
||||
- workspace
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
requestBody:
|
||||
description: WorkspaceOpenAIKey
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
openai_key:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: status
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
/w/{workspace}/workspaces/exists_openai_key:
|
||||
get:
|
||||
summary: OpenAI key exists
|
||||
operationId: existsOpenaiKey
|
||||
tags:
|
||||
- workspace
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
|
||||
responses:
|
||||
"200":
|
||||
description: status
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: boolean
|
||||
|
||||
/w/{workspace}/workspaces/edit_error_handler:
|
||||
post:
|
||||
|
||||
@@ -46,6 +46,7 @@ mod groups;
|
||||
mod inputs;
|
||||
pub mod jobs;
|
||||
mod oauth2;
|
||||
mod openai;
|
||||
mod raw_apps;
|
||||
mod resources;
|
||||
mod schedule;
|
||||
@@ -199,7 +200,8 @@ pub async fn run_server(
|
||||
users::workspaced_service().layer(Extension(argon2.clone())),
|
||||
)
|
||||
.nest("/variables", variables::workspaced_service())
|
||||
.nest("/workspaces", workspaces::workspaced_service()),
|
||||
.nest("/workspaces", workspaces::workspaced_service())
|
||||
.nest("/openai", openai::workspaced_service()),
|
||||
)
|
||||
.nest("/workspaces", workspaces::global_service())
|
||||
.nest(
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
use crate::{db::DB, users::Authed, HTTP_CLIENT};
|
||||
|
||||
use axum::{
|
||||
body::{Bytes, StreamBody},
|
||||
extract::{Extension, Path},
|
||||
http::HeaderMap,
|
||||
response::IntoResponse,
|
||||
routing::post,
|
||||
Router,
|
||||
};
|
||||
use windmill_audit::{audit_log, ActionKind};
|
||||
use windmill_common::error::{to_anyhow, Error};
|
||||
|
||||
pub fn workspaced_service() -> Router {
|
||||
let router = Router::new().route("/proxy/*openai_path", post(proxy));
|
||||
|
||||
router
|
||||
}
|
||||
|
||||
struct OpenAIKey {
|
||||
openai_key: Option<String>,
|
||||
}
|
||||
|
||||
async fn proxy(
|
||||
authed: Authed,
|
||||
Extension(db): Extension<DB>,
|
||||
Path((w_id, openai_path)): Path<(String, String)>,
|
||||
body: Bytes,
|
||||
) -> impl IntoResponse {
|
||||
tracing::info!("reached openai endpoint");
|
||||
|
||||
let mut tx = db.begin().await?;
|
||||
let settings = sqlx::query_as!(
|
||||
OpenAIKey,
|
||||
"SELECT openai_key FROM workspace_settings WHERE workspace_id = $1",
|
||||
&w_id
|
||||
)
|
||||
.fetch_one(&mut tx)
|
||||
.await
|
||||
.map_err(|e| Error::InternalErr(format!("getting openai_key: {e}")))?;
|
||||
tx.commit().await?;
|
||||
|
||||
let openai_key = match settings.openai_key {
|
||||
Some(key) => key,
|
||||
None => {
|
||||
return Err(Error::BadRequest(
|
||||
"openai_key is not set for this workspace".to_string(),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
let resp = HTTP_CLIENT
|
||||
.post(String::from("https://api.openai.com/v1/") + &openai_path)
|
||||
.header("content-type", "application/json")
|
||||
.header("authorization", format!("Bearer {}", openai_key))
|
||||
.body(body)
|
||||
.send()
|
||||
.await
|
||||
.map_err(to_anyhow)?;
|
||||
|
||||
let mut tx = db.begin().await?;
|
||||
audit_log(
|
||||
&mut tx,
|
||||
&authed.username,
|
||||
"openai.request",
|
||||
ActionKind::Update,
|
||||
&w_id,
|
||||
Some(&authed.email),
|
||||
Some([("openai_path", &format!("{:?}", openai_path)[..])].into()),
|
||||
)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
|
||||
let mut headers = HeaderMap::new();
|
||||
for (k, v) in resp.headers().iter() {
|
||||
headers.insert(k, v.clone());
|
||||
}
|
||||
|
||||
let stream = resp.bytes_stream();
|
||||
|
||||
Ok((headers, StreamBody::new(stream)))
|
||||
}
|
||||
@@ -66,6 +66,8 @@ pub fn workspaced_service() -> Router {
|
||||
.route("/edit_deploy_to", post(edit_deploy_to))
|
||||
.route("/tarball", get(tarball_workspace))
|
||||
.route("/premium_info", get(premium_info))
|
||||
.route("/edit_openai_key", post(edit_openai_key))
|
||||
.route("/exists_openai_key", get(exists_openai_key) )
|
||||
.route("/edit_error_handler", post(edit_error_handler));
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
@@ -113,6 +115,7 @@ pub struct WorkspaceSettings {
|
||||
pub plan: Option<String>,
|
||||
pub webhook: Option<String>,
|
||||
pub deploy_to: Option<String>,
|
||||
pub openai_key: Option<String>,
|
||||
pub error_handler: Option<String>,
|
||||
}
|
||||
|
||||
@@ -153,6 +156,11 @@ struct EditWebhook {
|
||||
webhook: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct EditOpenAIKey {
|
||||
openai_key: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct CreateWorkspace {
|
||||
id: String,
|
||||
@@ -652,6 +660,71 @@ async fn edit_webhook(
|
||||
Ok(format!("Edit webhook for workspace {}", &w_id))
|
||||
}
|
||||
|
||||
async fn edit_openai_key(
|
||||
authed: Authed,
|
||||
Extension(db): Extension<DB>,
|
||||
Path(w_id): Path<String>,
|
||||
Authed { is_admin, username, .. }: Authed,
|
||||
Json(eo): Json<EditOpenAIKey>,
|
||||
) -> Result<String> {
|
||||
require_admin(is_admin, &username)?;
|
||||
|
||||
let mut tx = db.begin().await?;
|
||||
|
||||
if let Some(openai_key) = &eo.openai_key {
|
||||
sqlx::query!(
|
||||
"UPDATE workspace_settings SET openai_key = $1 WHERE workspace_id = $2",
|
||||
openai_key,
|
||||
&w_id
|
||||
)
|
||||
.execute(&mut tx)
|
||||
.await?;
|
||||
} else {
|
||||
sqlx::query!(
|
||||
"UPDATE workspace_settings SET openai_key = NULL WHERE workspace_id = $1",
|
||||
&w_id,
|
||||
)
|
||||
.execute(&mut tx)
|
||||
.await?;
|
||||
}
|
||||
audit_log(
|
||||
&mut tx,
|
||||
&authed.username,
|
||||
"workspaces.edit_openai_key",
|
||||
ActionKind::Update,
|
||||
&w_id,
|
||||
Some(&authed.email),
|
||||
Some([("openai_key", &format!("{:?}", eo.openai_key)[..])].into()),
|
||||
)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
|
||||
Ok(format!("Edit openai_key for workspace {}", &w_id))
|
||||
}
|
||||
|
||||
|
||||
async fn exists_openai_key(
|
||||
Extension(db): Extension<DB>,
|
||||
Path(w_id): Path<String>,
|
||||
Authed { is_admin, username, .. }: Authed,
|
||||
) -> JsonResult<bool> {
|
||||
require_admin(is_admin, &username)?;
|
||||
|
||||
let mut tx = db.begin().await?;
|
||||
let openai_key = sqlx::query_scalar!(
|
||||
"SELECT openai_key FROM workspace_settings WHERE workspace_id = $1",
|
||||
&w_id
|
||||
)
|
||||
.fetch_one(&mut tx)
|
||||
.await
|
||||
.map_err(|e| Error::InternalErr(format!("getting openai_key: {e}")))?;
|
||||
tx.commit().await?;
|
||||
|
||||
let exists = openai_key.is_some();
|
||||
|
||||
Ok(Json(exists))
|
||||
}
|
||||
|
||||
|
||||
async fn edit_error_handler(
|
||||
authed: Authed,
|
||||
|
||||
Generated
+509
-64
@@ -30,6 +30,7 @@
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-svelte": "^0.246.0",
|
||||
"monaco-languageclient": "~6.0.3",
|
||||
"openai": "^4.0.0-beta.4",
|
||||
"quill": "^1.3.7",
|
||||
"svelte-autosize": "^1.0.1",
|
||||
"svelte-chartjs": "^3.1.0",
|
||||
@@ -663,6 +664,33 @@
|
||||
"node-pre-gyp": "bin/node-pre-gyp"
|
||||
}
|
||||
},
|
||||
"node_modules/@mapbox/node-pre-gyp/node_modules/agent-base": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
||||
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"debug": "4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@mapbox/node-pre-gyp/node_modules/https-proxy-agent": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
||||
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"agent-base": "6",
|
||||
"debug": "4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/@mapbox/point-geometry": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz",
|
||||
@@ -1218,8 +1246,16 @@
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.3.tgz",
|
||||
"integrity": "sha512-wheIYdr4NYML61AjC8MKj/2jrR/kDQri/CIpVoZwldwhnIrD/j9jIU5bJ8yBKuB2VhpFV7Ab6G2XkBjv9r9Zzw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-wheIYdr4NYML61AjC8MKj/2jrR/kDQri/CIpVoZwldwhnIrD/j9jIU5bJ8yBKuB2VhpFV7Ab6G2XkBjv9r9Zzw=="
|
||||
},
|
||||
"node_modules/@types/node-fetch": {
|
||||
"version": "2.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.4.tgz",
|
||||
"integrity": "sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg==",
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"form-data": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/normalize-package-data": {
|
||||
"version": "2.4.1",
|
||||
@@ -1234,6 +1270,11 @@
|
||||
"integrity": "sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/qs": {
|
||||
"version": "6.9.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
|
||||
"integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw=="
|
||||
},
|
||||
"node_modules/@types/semver": {
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz",
|
||||
@@ -1628,6 +1669,17 @@
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/abort-controller": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
|
||||
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
|
||||
"dependencies": {
|
||||
"event-target-shim": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.5"
|
||||
}
|
||||
},
|
||||
"node_modules/abstract-leveldown": {
|
||||
"version": "6.2.3",
|
||||
"resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-6.2.3.tgz",
|
||||
@@ -1706,17 +1758,17 @@
|
||||
"ag-grid-community": "^28"
|
||||
}
|
||||
},
|
||||
"node_modules/agent-base": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
||||
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"node_modules/agentkeepalive": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz",
|
||||
"integrity": "sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==",
|
||||
"dependencies": {
|
||||
"debug": "4"
|
||||
"debug": "^4.1.0",
|
||||
"depd": "^2.0.0",
|
||||
"humanize-ms": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6.0.0"
|
||||
"node": ">= 8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ajv": {
|
||||
@@ -1854,6 +1906,11 @@
|
||||
"integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"node_modules/autoprefixer": {
|
||||
"version": "10.4.14",
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz",
|
||||
@@ -1897,6 +1954,11 @@
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||
},
|
||||
"node_modules/base-64": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz",
|
||||
"integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA=="
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
@@ -2152,6 +2214,14 @@
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/charenc": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
|
||||
"integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/chart.js": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.3.0.tgz",
|
||||
@@ -2262,6 +2332,17 @@
|
||||
"integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"dependencies": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/commander": {
|
||||
"version": "10.0.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
|
||||
@@ -2331,6 +2412,14 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/crypt": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
|
||||
"integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/css-declaration-sorter": {
|
||||
"version": "6.4.0",
|
||||
"resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.0.tgz",
|
||||
@@ -2659,7 +2748,6 @@
|
||||
"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"
|
||||
},
|
||||
@@ -2787,6 +2875,14 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/delegates": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
|
||||
@@ -2794,6 +2890,14 @@
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/depd": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-indent": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz",
|
||||
@@ -2833,6 +2937,15 @@
|
||||
"node": ">=0.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/digest-fetch": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/digest-fetch/-/digest-fetch-1.3.0.tgz",
|
||||
"integrity": "sha512-CGJuv6iKNM7QyZlM2T3sPAdZWd/p9zQiRNS9G+9COUCwzWFTs0Xp8NF5iePx7wtvhDykReiRRrSeNb4oMmB8lA==",
|
||||
"dependencies": {
|
||||
"base-64": "^0.1.0",
|
||||
"md5": "^2.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dir-glob": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
|
||||
@@ -3280,6 +3393,14 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/event-target-shim": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
|
||||
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/eventemitter3": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz",
|
||||
@@ -3430,6 +3551,36 @@
|
||||
"integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
|
||||
"integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/form-data-encoder": {
|
||||
"version": "1.7.2",
|
||||
"resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz",
|
||||
"integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A=="
|
||||
},
|
||||
"node_modules/formdata-node": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz",
|
||||
"integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==",
|
||||
"dependencies": {
|
||||
"node-domexception": "1.0.0",
|
||||
"web-streams-polyfill": "4.0.0-beta.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 12.20"
|
||||
}
|
||||
},
|
||||
"node_modules/fraction.js": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz",
|
||||
@@ -3861,18 +4012,12 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/https-proxy-agent": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
||||
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"node_modules/humanize-ms": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
|
||||
"integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==",
|
||||
"dependencies": {
|
||||
"agent-base": "6",
|
||||
"debug": "4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
"ms": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ieee754": {
|
||||
@@ -4027,6 +4172,11 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-buffer": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
|
||||
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
|
||||
},
|
||||
"node_modules/is-core-module": {
|
||||
"version": "2.11.0",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
|
||||
@@ -4659,6 +4809,16 @@
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/md5": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
|
||||
"integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==",
|
||||
"dependencies": {
|
||||
"charenc": "0.0.2",
|
||||
"crypt": "0.0.2",
|
||||
"is-buffer": "~1.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mdn-data": {
|
||||
"version": "2.0.30",
|
||||
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
|
||||
@@ -4739,6 +4899,25 @@
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-types": {
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"dependencies": {
|
||||
"mime-db": "1.52.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mimic-response": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz",
|
||||
@@ -4927,8 +5106,7 @@
|
||||
"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
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"node_modules/mz": {
|
||||
"version": "2.7.0",
|
||||
@@ -5000,12 +5178,28 @@
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/node-domexception": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
|
||||
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/jimmywarting"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://paypal.me/jimmywarting"
|
||||
}
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.6.11",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz",
|
||||
"integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
@@ -5131,6 +5325,14 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/object-inspect": {
|
||||
"version": "1.12.3",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
|
||||
"integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/object-is": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz",
|
||||
@@ -5191,6 +5393,28 @@
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/openai": {
|
||||
"version": "4.0.0-beta.4",
|
||||
"resolved": "https://registry.npmjs.org/openai/-/openai-4.0.0-beta.4.tgz",
|
||||
"integrity": "sha512-8U1E4IHxemQE/VePwOpd4kaq0/vRTK9GJpHWrF6KQ3GEshWkUN///gCA+PtVFyf+irZrDGqjBAb3C02zn0UZBg==",
|
||||
"dependencies": {
|
||||
"@types/node": "^18.11.18",
|
||||
"@types/node-fetch": "^2.6.4",
|
||||
"@types/qs": "^6.9.7",
|
||||
"abort-controller": "^3.0.0",
|
||||
"agentkeepalive": "^4.2.1",
|
||||
"digest-fetch": "^1.3.0",
|
||||
"form-data-encoder": "1.7.2",
|
||||
"formdata-node": "^4.3.2",
|
||||
"node-fetch": "^2.6.7",
|
||||
"qs": "^6.10.3"
|
||||
}
|
||||
},
|
||||
"node_modules/openai/node_modules/@types/node": {
|
||||
"version": "18.16.19",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.19.tgz",
|
||||
"integrity": "sha512-IXl7o+R9iti9eBW4Wg2hx1xQDig183jj7YLn8F7udNceyfkbn1ZxmzZXuak20gR40D7pIkIY1kYGx5VIGbaHKA=="
|
||||
},
|
||||
"node_modules/openapi-typescript-codegen": {
|
||||
"version": "0.24.0",
|
||||
"resolved": "https://registry.npmjs.org/openapi-typescript-codegen/-/openapi-typescript-codegen-0.24.0.tgz",
|
||||
@@ -6119,6 +6343,20 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.11.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz",
|
||||
"integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==",
|
||||
"dependencies": {
|
||||
"side-channel": "^1.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/quadprog": {
|
||||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npmjs.org/quadprog/-/quadprog-1.6.1.tgz",
|
||||
@@ -6630,6 +6868,19 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
|
||||
"integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.0",
|
||||
"get-intrinsic": "^1.0.2",
|
||||
"object-inspect": "^1.9.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/signal-exit": {
|
||||
"version": "3.0.7",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
||||
@@ -7606,9 +7857,7 @@
|
||||
"node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||
},
|
||||
"node_modules/trim-newlines": {
|
||||
"version": "3.0.1",
|
||||
@@ -7937,6 +8186,14 @@
|
||||
"npm": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/web-streams-polyfill": {
|
||||
"version": "4.0.0-beta.3",
|
||||
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz",
|
||||
"integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==",
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/web-worker": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.2.0.tgz",
|
||||
@@ -7946,16 +8203,12 @@
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||
},
|
||||
"node_modules/whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
@@ -8572,6 +8825,29 @@
|
||||
"rimraf": "^3.0.2",
|
||||
"semver": "^7.3.5",
|
||||
"tar": "^6.1.11"
|
||||
},
|
||||
"dependencies": {
|
||||
"agent-base": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
||||
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"debug": "4"
|
||||
}
|
||||
},
|
||||
"https-proxy-agent": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
||||
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"agent-base": "6",
|
||||
"debug": "4"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@mapbox/point-geometry": {
|
||||
@@ -9043,8 +9319,16 @@
|
||||
"@types/node": {
|
||||
"version": "20.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.3.tgz",
|
||||
"integrity": "sha512-wheIYdr4NYML61AjC8MKj/2jrR/kDQri/CIpVoZwldwhnIrD/j9jIU5bJ8yBKuB2VhpFV7Ab6G2XkBjv9r9Zzw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-wheIYdr4NYML61AjC8MKj/2jrR/kDQri/CIpVoZwldwhnIrD/j9jIU5bJ8yBKuB2VhpFV7Ab6G2XkBjv9r9Zzw=="
|
||||
},
|
||||
"@types/node-fetch": {
|
||||
"version": "2.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.4.tgz",
|
||||
"integrity": "sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg==",
|
||||
"requires": {
|
||||
"@types/node": "*",
|
||||
"form-data": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"@types/normalize-package-data": {
|
||||
"version": "2.4.1",
|
||||
@@ -9059,6 +9343,11 @@
|
||||
"integrity": "sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/qs": {
|
||||
"version": "6.9.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
|
||||
"integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw=="
|
||||
},
|
||||
"@types/semver": {
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz",
|
||||
@@ -9288,6 +9577,14 @@
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"abort-controller": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
|
||||
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
|
||||
"requires": {
|
||||
"event-target-shim": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"abstract-leveldown": {
|
||||
"version": "6.2.3",
|
||||
"resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-6.2.3.tgz",
|
||||
@@ -9340,14 +9637,14 @@
|
||||
"svelte": "^3.55.0"
|
||||
}
|
||||
},
|
||||
"agent-base": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
||||
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"agentkeepalive": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz",
|
||||
"integrity": "sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==",
|
||||
"requires": {
|
||||
"debug": "4"
|
||||
"debug": "^4.1.0",
|
||||
"depd": "^2.0.0",
|
||||
"humanize-ms": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"ajv": {
|
||||
@@ -9454,6 +9751,11 @@
|
||||
"integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
|
||||
"optional": true
|
||||
},
|
||||
"asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"autoprefixer": {
|
||||
"version": "10.4.14",
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz",
|
||||
@@ -9478,6 +9780,11 @@
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||
},
|
||||
"base-64": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz",
|
||||
"integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA=="
|
||||
},
|
||||
"base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
@@ -9642,6 +9949,11 @@
|
||||
"supports-color": "^7.1.0"
|
||||
}
|
||||
},
|
||||
"charenc": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
|
||||
"integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA=="
|
||||
},
|
||||
"chart.js": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.3.0.tgz",
|
||||
@@ -9720,6 +10032,14 @@
|
||||
"integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==",
|
||||
"dev": true
|
||||
},
|
||||
"combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"requires": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"commander": {
|
||||
"version": "10.0.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
|
||||
@@ -9774,6 +10094,11 @@
|
||||
"which": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"crypt": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
|
||||
"integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow=="
|
||||
},
|
||||
"css-declaration-sorter": {
|
||||
"version": "6.4.0",
|
||||
"resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.0.tgz",
|
||||
@@ -10009,7 +10334,6 @@
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
@@ -10101,6 +10425,11 @@
|
||||
"object-keys": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
|
||||
},
|
||||
"delegates": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
|
||||
@@ -10108,6 +10437,11 @@
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"depd": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
|
||||
},
|
||||
"detect-indent": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz",
|
||||
@@ -10138,6 +10472,15 @@
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz",
|
||||
"integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw=="
|
||||
},
|
||||
"digest-fetch": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/digest-fetch/-/digest-fetch-1.3.0.tgz",
|
||||
"integrity": "sha512-CGJuv6iKNM7QyZlM2T3sPAdZWd/p9zQiRNS9G+9COUCwzWFTs0Xp8NF5iePx7wtvhDykReiRRrSeNb4oMmB8lA==",
|
||||
"requires": {
|
||||
"base-64": "^0.1.0",
|
||||
"md5": "^2.3.0"
|
||||
}
|
||||
},
|
||||
"dir-glob": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
|
||||
@@ -10477,6 +10820,11 @@
|
||||
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
|
||||
"dev": true
|
||||
},
|
||||
"event-target-shim": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
|
||||
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="
|
||||
},
|
||||
"eventemitter3": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz",
|
||||
@@ -10603,6 +10951,30 @@
|
||||
"integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
|
||||
"dev": true
|
||||
},
|
||||
"form-data": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
|
||||
"integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
},
|
||||
"form-data-encoder": {
|
||||
"version": "1.7.2",
|
||||
"resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz",
|
||||
"integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A=="
|
||||
},
|
||||
"formdata-node": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz",
|
||||
"integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==",
|
||||
"requires": {
|
||||
"node-domexception": "1.0.0",
|
||||
"web-streams-polyfill": "4.0.0-beta.3"
|
||||
}
|
||||
},
|
||||
"fraction.js": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz",
|
||||
@@ -10920,15 +11292,12 @@
|
||||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"https-proxy-agent": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
||||
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"humanize-ms": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
|
||||
"integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==",
|
||||
"requires": {
|
||||
"agent-base": "6",
|
||||
"debug": "4"
|
||||
"ms": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"ieee754": {
|
||||
@@ -11039,6 +11408,11 @@
|
||||
"binary-extensions": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"is-buffer": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
|
||||
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
|
||||
},
|
||||
"is-core-module": {
|
||||
"version": "2.11.0",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
|
||||
@@ -11509,6 +11883,16 @@
|
||||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"md5": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
|
||||
"integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==",
|
||||
"requires": {
|
||||
"charenc": "0.0.2",
|
||||
"crypt": "0.0.2",
|
||||
"is-buffer": "~1.1.6"
|
||||
}
|
||||
},
|
||||
"mdn-data": {
|
||||
"version": "2.0.30",
|
||||
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
|
||||
@@ -11567,6 +11951,19 @@
|
||||
"integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==",
|
||||
"dev": true
|
||||
},
|
||||
"mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
|
||||
},
|
||||
"mime-types": {
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"requires": {
|
||||
"mime-db": "1.52.0"
|
||||
}
|
||||
},
|
||||
"mimic-response": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz",
|
||||
@@ -11700,8 +12097,7 @@
|
||||
"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
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"mz": {
|
||||
"version": "2.7.0",
|
||||
@@ -11761,12 +12157,15 @@
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node-domexception": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
|
||||
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.11",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz",
|
||||
"integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
}
|
||||
@@ -11852,6 +12251,11 @@
|
||||
"integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
|
||||
"dev": true
|
||||
},
|
||||
"object-inspect": {
|
||||
"version": "1.12.3",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
|
||||
"integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g=="
|
||||
},
|
||||
"object-is": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz",
|
||||
@@ -11899,6 +12303,30 @@
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"openai": {
|
||||
"version": "4.0.0-beta.4",
|
||||
"resolved": "https://registry.npmjs.org/openai/-/openai-4.0.0-beta.4.tgz",
|
||||
"integrity": "sha512-8U1E4IHxemQE/VePwOpd4kaq0/vRTK9GJpHWrF6KQ3GEshWkUN///gCA+PtVFyf+irZrDGqjBAb3C02zn0UZBg==",
|
||||
"requires": {
|
||||
"@types/node": "^18.11.18",
|
||||
"@types/node-fetch": "^2.6.4",
|
||||
"@types/qs": "^6.9.7",
|
||||
"abort-controller": "^3.0.0",
|
||||
"agentkeepalive": "^4.2.1",
|
||||
"digest-fetch": "^1.3.0",
|
||||
"form-data-encoder": "1.7.2",
|
||||
"formdata-node": "^4.3.2",
|
||||
"node-fetch": "^2.6.7",
|
||||
"qs": "^6.10.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": {
|
||||
"version": "18.16.19",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.19.tgz",
|
||||
"integrity": "sha512-IXl7o+R9iti9eBW4Wg2hx1xQDig183jj7YLn8F7udNceyfkbn1ZxmzZXuak20gR40D7pIkIY1kYGx5VIGbaHKA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"openapi-typescript-codegen": {
|
||||
"version": "0.24.0",
|
||||
"resolved": "https://registry.npmjs.org/openapi-typescript-codegen/-/openapi-typescript-codegen-0.24.0.tgz",
|
||||
@@ -12506,6 +12934,14 @@
|
||||
"integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
|
||||
"dev": true
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.11.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz",
|
||||
"integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==",
|
||||
"requires": {
|
||||
"side-channel": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"quadprog": {
|
||||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npmjs.org/quadprog/-/quadprog-1.6.1.tgz",
|
||||
@@ -12874,6 +13310,16 @@
|
||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
||||
"dev": true
|
||||
},
|
||||
"side-channel": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
|
||||
"integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
|
||||
"requires": {
|
||||
"call-bind": "^1.0.0",
|
||||
"get-intrinsic": "^1.0.2",
|
||||
"object-inspect": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"signal-exit": {
|
||||
"version": "3.0.7",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
||||
@@ -13605,9 +14051,7 @@
|
||||
"tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||
},
|
||||
"trim-newlines": {
|
||||
"version": "3.0.1",
|
||||
@@ -13822,6 +14266,11 @@
|
||||
"vscode-jsonrpc": "~8.1.0"
|
||||
}
|
||||
},
|
||||
"web-streams-polyfill": {
|
||||
"version": "4.0.0-beta.3",
|
||||
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz",
|
||||
"integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug=="
|
||||
},
|
||||
"web-worker": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.2.0.tgz",
|
||||
@@ -13831,16 +14280,12 @@
|
||||
"webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||
},
|
||||
"whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
|
||||
@@ -92,6 +92,7 @@
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-svelte": "^0.246.0",
|
||||
"monaco-languageclient": "~6.0.3",
|
||||
"openai": "^4.0.0-beta.4",
|
||||
"quill": "^1.3.7",
|
||||
"svelte-autosize": "^1.0.1",
|
||||
"svelte-chartjs": "^3.1.0",
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
<script lang="ts">
|
||||
import { BROWSER } from 'esm-env'
|
||||
import { onMount } from 'svelte'
|
||||
|
||||
import 'monaco-editor/esm/vs/editor/edcore.main'
|
||||
import { editor as meditor } from 'monaco-editor/esm/vs/editor/editor.api'
|
||||
import 'monaco-editor/esm/vs/basic-languages/python/python.contribution'
|
||||
import 'monaco-editor/esm/vs/basic-languages/go/go.contribution'
|
||||
import 'monaco-editor/esm/vs/basic-languages/shell/shell.contribution'
|
||||
import 'monaco-editor/esm/vs/basic-languages/typescript/typescript.contribution'
|
||||
import 'monaco-editor/esm/vs/basic-languages/sql/sql.contribution'
|
||||
import 'monaco-editor/esm/vs/language/typescript/monaco.contribution'
|
||||
import { Breakpoints } from './apps/gridUtils'
|
||||
|
||||
meditor.defineTheme('myTheme', {
|
||||
base: 'vs',
|
||||
inherit: true,
|
||||
rules: [],
|
||||
colors: {
|
||||
'editorLineNumber.foreground': '#999',
|
||||
'editorGutter.background': '#F9FAFB'
|
||||
}
|
||||
})
|
||||
meditor.setTheme('myTheme')
|
||||
|
||||
export let automaticLayout = true
|
||||
export let fixedOverflowWidgets = true
|
||||
export let sideBySideMinWidth = Breakpoints.lg
|
||||
|
||||
let diffEditor: meditor.IStandaloneDiffEditor
|
||||
let diffDivEl: HTMLDivElement | null = null
|
||||
|
||||
function loadDiffEditor() {
|
||||
diffEditor = meditor.createDiffEditor(diffDivEl!, {
|
||||
automaticLayout,
|
||||
renderSideBySide: window.innerWidth >= sideBySideMinWidth,
|
||||
domReadOnly: true,
|
||||
readOnly: true,
|
||||
minimap: {
|
||||
enabled: false
|
||||
},
|
||||
fixedOverflowWidgets,
|
||||
scrollBeyondLastLine: false,
|
||||
lineDecorationsWidth: 15,
|
||||
lineNumbersMinChars: 2,
|
||||
autoDetectHighContrast: true,
|
||||
scrollbar: { alwaysConsumeMouseWheel: false }
|
||||
})
|
||||
}
|
||||
|
||||
export function setDiff(
|
||||
original: string,
|
||||
modified: string,
|
||||
lang: 'typescript' | 'python' | 'go' | 'shell' | 'sql' | 'graphql'
|
||||
): void {
|
||||
diffEditor.setModel({
|
||||
original: meditor.createModel(original, lang),
|
||||
modified: meditor.createModel(modified, lang)
|
||||
})
|
||||
|
||||
if (lang !== 'shell') {
|
||||
diffEditor?.getModifiedEditor().getAction('editor.action.formatDocument')?.run()
|
||||
}
|
||||
}
|
||||
|
||||
export function getOriginal(): string {
|
||||
return diffEditor.getModel()?.original.getValue() ?? ''
|
||||
}
|
||||
|
||||
export function getModified(): string {
|
||||
return diffEditor.getModel()?.modified.getValue() ?? ''
|
||||
}
|
||||
|
||||
export function show(): void {
|
||||
diffDivEl?.classList.remove('hidden')
|
||||
}
|
||||
export function hide(): void {
|
||||
diffDivEl?.classList.add('hidden')
|
||||
}
|
||||
|
||||
function onResize() {
|
||||
diffEditor.updateOptions({ renderSideBySide: window.innerWidth >= sideBySideMinWidth })
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
if (BROWSER) {
|
||||
loadDiffEditor()
|
||||
window.addEventListener('resize', onResize)
|
||||
return () => {
|
||||
diffEditor?.dispose()
|
||||
window.removeEventListener('resize', onResize)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<div bind:this={diffDivEl} class="{$$props.class} editor" />
|
||||
@@ -7,6 +7,10 @@
|
||||
import { ClipboardCopy, Download, Expand } from 'lucide-svelte'
|
||||
import Portal from 'svelte-portal'
|
||||
import ObjectViewer from './propertyPicker/ObjectViewer.svelte'
|
||||
import ScriptFix from './codeGen/ScriptFix.svelte'
|
||||
import type { Preview } from '$lib/gen'
|
||||
import type Editor from './Editor.svelte'
|
||||
import type DiffEditor from './DiffEditor.svelte'
|
||||
|
||||
export let result: any
|
||||
export let requireHtmlApproval = false
|
||||
@@ -14,6 +18,9 @@
|
||||
export let disableExpand = false
|
||||
export let jobId: string | undefined = undefined
|
||||
export let workspaceId: string | undefined = undefined
|
||||
export let editor: Editor | undefined = undefined
|
||||
export let diffEditor: DiffEditor | undefined = undefined
|
||||
export let lang: Preview.language | undefined = undefined
|
||||
|
||||
let resultKind:
|
||||
| 'json'
|
||||
@@ -223,12 +230,15 @@
|
||||
href="data:application/octet-stream;base64,{result.file}">Download</a
|
||||
>
|
||||
</div>
|
||||
{:else if !forceJson && resultKind == 'error'}<div>
|
||||
{:else if !forceJson && resultKind == 'error'}<div class="flex flex-col items-start">
|
||||
<span class="text-red-500 font-semibold text-sm whitespace-pre-wrap"
|
||||
>{#if result.error.name || result.error.message}{result.error.name}: {result.error
|
||||
.message}{:else}{JSON.stringify(result.error, null, 4)}{/if}</span
|
||||
>
|
||||
<pre class="text-sm whitespace-pre-wrap text-gray-900">{result.error.stack ?? ''}</pre>
|
||||
{#if lang && editor && diffEditor}
|
||||
<ScriptFix error={JSON.stringify(result.error)} {lang} {editor} {diffEditor} />
|
||||
{/if}
|
||||
</div>
|
||||
{:else if !forceJson && resultKind == 'approval'}<div class="flex flex-col gap-3 mt-8 mx-4">
|
||||
<Button
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
KeyCode,
|
||||
KeyMod,
|
||||
Uri as mUri,
|
||||
languages
|
||||
languages,
|
||||
type IRange
|
||||
} from 'monaco-editor/esm/vs/editor/editor.api'
|
||||
import 'monaco-editor/esm/vs/basic-languages/python/python.contribution'
|
||||
import 'monaco-editor/esm/vs/basic-languages/go/go.contribution'
|
||||
@@ -145,6 +146,35 @@
|
||||
}
|
||||
}
|
||||
|
||||
export function getSelectedLines(): string | undefined {
|
||||
if (editor) {
|
||||
const selection = editor.getSelection()
|
||||
if (selection) {
|
||||
const range: IRange = {
|
||||
startLineNumber: selection.startLineNumber,
|
||||
startColumn: 1,
|
||||
endLineNumber: selection.endLineNumber + 1,
|
||||
endColumn: 1
|
||||
}
|
||||
return editor.getModel()?.getValueInRange(range)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function onDidChangeCursorSelection(f: (e: meditor.ICursorSelectionChangedEvent) => void) {
|
||||
if (editor) {
|
||||
return editor.onDidChangeCursorSelection(f)
|
||||
}
|
||||
}
|
||||
|
||||
export function show(): void {
|
||||
divEl?.classList.remove('hidden')
|
||||
}
|
||||
|
||||
export function hide(): void {
|
||||
divEl?.classList.add('hidden')
|
||||
}
|
||||
|
||||
export function setCode(ncode: string, noHistory: boolean = false): void {
|
||||
code = ncode
|
||||
if (noHistory) {
|
||||
|
||||
@@ -37,6 +37,8 @@
|
||||
import { capitalize } from '$lib/utils'
|
||||
import type { Schema, SchemaProperty, SupportedLanguage } from '$lib/common'
|
||||
import ScriptVersionHistory from './ScriptVersionHistory.svelte'
|
||||
import { ScriptGen } from './codeGen'
|
||||
import type DiffEditor from './DiffEditor.svelte'
|
||||
|
||||
export let lang: SupportedLanguage
|
||||
export let editor: Editor | undefined
|
||||
@@ -55,6 +57,7 @@
|
||||
export let collabLive = false
|
||||
export let collabUsers: { name: string }[] = []
|
||||
export let scriptPath: string | undefined = undefined
|
||||
export let diffEditor: DiffEditor | undefined = undefined
|
||||
|
||||
let contextualVariablePicker: ItemPicker
|
||||
let variablePicker: ItemPicker
|
||||
@@ -462,6 +465,8 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<ScriptGen {editor} {diffEditor} {lang} {iconOnly} />
|
||||
|
||||
<!-- <Popover
|
||||
notClickable
|
||||
placement="bottom"
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
import { WebsocketProvider } from 'y-websocket'
|
||||
import Modal from './common/modal/Modal.svelte'
|
||||
import { Icon } from 'svelte-awesome'
|
||||
import DiffEditor from './DiffEditor.svelte'
|
||||
|
||||
// Exported
|
||||
export let schema: Schema | any = emptySchema()
|
||||
@@ -36,6 +37,7 @@
|
||||
export let fixedOverflowWidgets = true
|
||||
export let noSyncFromGithub = false
|
||||
export let editor: Editor | undefined = undefined
|
||||
export let diffEditor: DiffEditor | undefined = undefined
|
||||
export let collabMode = false
|
||||
export let edit = true
|
||||
|
||||
@@ -242,6 +244,7 @@
|
||||
{websocketAlive}
|
||||
collabUsers={peers}
|
||||
kind={asKind(kind)}
|
||||
{diffEditor}
|
||||
/>
|
||||
{#if !noSyncFromGithub}
|
||||
<div class="py-1">
|
||||
@@ -296,6 +299,12 @@
|
||||
automaticLayout={true}
|
||||
{fixedOverflowWidgets}
|
||||
/>
|
||||
<DiffEditor
|
||||
bind:this={diffEditor}
|
||||
automaticLayout
|
||||
{fixedOverflowWidgets}
|
||||
class="hidden flex-1 h-full !overflow-visible"
|
||||
/>
|
||||
{/key}
|
||||
</div>
|
||||
</Pane>
|
||||
@@ -344,7 +353,14 @@
|
||||
</div>
|
||||
</Pane>
|
||||
<Pane size={67}>
|
||||
<LogPanel {lang} previewJob={testJob} {pastPreviews} previewIsLoading={testIsLoading} />
|
||||
<LogPanel
|
||||
{lang}
|
||||
previewJob={testJob}
|
||||
{pastPreviews}
|
||||
previewIsLoading={testIsLoading}
|
||||
{editor}
|
||||
{diffEditor}
|
||||
/>
|
||||
</Pane>
|
||||
</Splitpanes>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
<script lang="ts">
|
||||
import { Button } from '../common'
|
||||
|
||||
import { SUPPORTED_LANGUAGES, fixScript } from './lib'
|
||||
import type { SupportedLanguage } from '$lib/common'
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
import type Editor from '../Editor.svelte'
|
||||
import { faCheck, faClose, faMagicWandSparkles } from '@fortawesome/free-solid-svg-icons'
|
||||
import { WorkspaceService } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import type DiffEditor from '../DiffEditor.svelte'
|
||||
import { scriptLangToEditorLang } from '$lib/scripts'
|
||||
|
||||
// props
|
||||
export let lang: SupportedLanguage
|
||||
export let editor: Editor | undefined
|
||||
export let diffEditor: DiffEditor | undefined
|
||||
export let error: string
|
||||
|
||||
// state
|
||||
let genLoading: boolean = false
|
||||
let openAIAvailable: boolean | undefined = undefined
|
||||
let generatedCode = ''
|
||||
|
||||
async function onFix() {
|
||||
if (!error) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
// close popup ^^
|
||||
const elem = document.activeElement as HTMLElement
|
||||
if (elem.blur) {
|
||||
elem.blur()
|
||||
}
|
||||
|
||||
genLoading = true
|
||||
generatedCode = await fixScript({
|
||||
language: lang,
|
||||
code: editor?.getCode() || '',
|
||||
error
|
||||
})
|
||||
} catch (err) {
|
||||
sendUserToast('Failed to generate code', true)
|
||||
console.error(err)
|
||||
} finally {
|
||||
genLoading = false
|
||||
}
|
||||
}
|
||||
|
||||
function acceptDiff() {
|
||||
editor?.setCode(diffEditor?.getModified() || '')
|
||||
editor?.format()
|
||||
generatedCode = ''
|
||||
error = ''
|
||||
}
|
||||
|
||||
function rejectDiff() {
|
||||
generatedCode = ''
|
||||
}
|
||||
|
||||
async function checkIfOpenAIAvailable(lang: SupportedLanguage) {
|
||||
try {
|
||||
const exists = await WorkspaceService.existsOpenaiKey({ workspace: $workspaceStore! })
|
||||
openAIAvailable = exists && SUPPORTED_LANGUAGES.has(lang)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
sendUserToast('Failed to check if OpenAI is available', true)
|
||||
}
|
||||
}
|
||||
|
||||
function showDiff() {
|
||||
diffEditor?.setDiff(editor?.getCode() || '', generatedCode, scriptLangToEditorLang(lang))
|
||||
diffEditor?.show()
|
||||
editor?.hide()
|
||||
}
|
||||
|
||||
function hideDiff() {
|
||||
editor?.show()
|
||||
diffEditor?.hide()
|
||||
}
|
||||
|
||||
$: checkIfOpenAIAvailable(lang)
|
||||
|
||||
$: lang && (generatedCode = '')
|
||||
|
||||
$: generatedCode && showDiff()
|
||||
$: !generatedCode && hideDiff()
|
||||
</script>
|
||||
|
||||
{#if error}
|
||||
{#if openAIAvailable}
|
||||
<div class="mt-2">
|
||||
{#if generatedCode}
|
||||
<div class="flex gap-1">
|
||||
<Button
|
||||
title="Discard generated code"
|
||||
size="xs"
|
||||
color="red"
|
||||
spacingSize="xs2"
|
||||
on:click={rejectDiff}
|
||||
variant="contained"
|
||||
startIcon={{ icon: faClose }}
|
||||
>
|
||||
Discard
|
||||
</Button><Button
|
||||
title="Accept generated code"
|
||||
size="xs"
|
||||
color="green"
|
||||
spacingSize="xs2"
|
||||
on:click={acceptDiff}
|
||||
startIcon={{ icon: faCheck }}
|
||||
>
|
||||
Accept
|
||||
</Button>
|
||||
</div>
|
||||
{:else}
|
||||
<Button
|
||||
title="Generate code from prompt"
|
||||
size="xs"
|
||||
color="blue"
|
||||
spacingSize="xs2"
|
||||
startIcon={{ icon: faMagicWandSparkles }}
|
||||
loading={genLoading}
|
||||
on:click={onFix}
|
||||
>
|
||||
AI Fix
|
||||
</Button>
|
||||
{/if}</div
|
||||
>
|
||||
{/if}
|
||||
{/if}
|
||||
@@ -0,0 +1,199 @@
|
||||
<script lang="ts">
|
||||
import { Button } from '../common'
|
||||
|
||||
import { SUPPORTED_LANGUAGES, editScript, generateScript } from './lib'
|
||||
import type { SupportedLanguage } from '$lib/common'
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
import type Editor from '../Editor.svelte'
|
||||
import { faCheck, faClose, faMagicWandSparkles } from '@fortawesome/free-solid-svg-icons'
|
||||
import Popup from '../common/popup/Popup.svelte'
|
||||
import { fade } from 'svelte/transition'
|
||||
import { Icon } from 'svelte-awesome'
|
||||
import { WorkspaceService } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import type DiffEditor from '../DiffEditor.svelte'
|
||||
import { scriptLangToEditorLang } from '$lib/scripts'
|
||||
import type { Selection } from 'monaco-editor/esm/vs/editor/editor.api'
|
||||
|
||||
// props
|
||||
export let iconOnly: boolean = false
|
||||
export let lang: SupportedLanguage
|
||||
export let editor: Editor | undefined
|
||||
export let diffEditor: DiffEditor | undefined
|
||||
|
||||
// state
|
||||
let funcDesc: string = ''
|
||||
let genLoading: boolean = false
|
||||
let openAIAvailable: boolean | undefined = undefined
|
||||
let button: HTMLButtonElement | undefined
|
||||
let input: HTMLInputElement | undefined
|
||||
let generatedCode = ''
|
||||
let selection: Selection | undefined
|
||||
let isEdit = false
|
||||
|
||||
async function onGenerate() {
|
||||
try {
|
||||
// close popup ^^
|
||||
const elem = document.activeElement as HTMLElement
|
||||
if (elem.blur) {
|
||||
elem.blur()
|
||||
}
|
||||
|
||||
genLoading = true
|
||||
if (isEdit && selection) {
|
||||
const selectedCode = editor?.getSelectedLines() || ''
|
||||
const originalCode = editor?.getCode() || ''
|
||||
const selectionGenCode = await editScript({
|
||||
language: lang,
|
||||
description: funcDesc,
|
||||
selectedCode
|
||||
})
|
||||
generatedCode = originalCode.replace(selectedCode, selectionGenCode + '\n')
|
||||
} else {
|
||||
generatedCode = await generateScript({
|
||||
language: lang,
|
||||
description: funcDesc
|
||||
})
|
||||
}
|
||||
funcDesc = ''
|
||||
} catch (err) {
|
||||
sendUserToast('Failed to generate code', true)
|
||||
console.error(err)
|
||||
} finally {
|
||||
genLoading = false
|
||||
}
|
||||
}
|
||||
|
||||
function acceptDiff() {
|
||||
editor?.setCode(diffEditor?.getModified() || '')
|
||||
editor?.format()
|
||||
generatedCode = ''
|
||||
}
|
||||
|
||||
function rejectDiff() {
|
||||
generatedCode = ''
|
||||
}
|
||||
|
||||
async function checkIfOpenAIAvailable(lang: SupportedLanguage) {
|
||||
try {
|
||||
const exists = await WorkspaceService.existsOpenaiKey({ workspace: $workspaceStore! })
|
||||
openAIAvailable = exists && SUPPORTED_LANGUAGES.has(lang)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
sendUserToast('Failed to check if OpenAI is available', true)
|
||||
}
|
||||
}
|
||||
|
||||
function showDiff() {
|
||||
diffEditor?.setDiff(editor?.getCode() || '', generatedCode, scriptLangToEditorLang(lang))
|
||||
diffEditor?.show()
|
||||
editor?.hide()
|
||||
}
|
||||
|
||||
function hideDiff() {
|
||||
editor?.show()
|
||||
diffEditor?.hide()
|
||||
}
|
||||
|
||||
function setSelectionHandler() {
|
||||
editor?.onDidChangeCursorSelection((e) => {
|
||||
selection = e.selection
|
||||
})
|
||||
}
|
||||
|
||||
$: checkIfOpenAIAvailable(lang)
|
||||
|
||||
$: input?.focus()
|
||||
|
||||
$: lang && (generatedCode = '')
|
||||
|
||||
$: generatedCode && showDiff()
|
||||
$: !generatedCode && hideDiff()
|
||||
$: editor && setSelectionHandler()
|
||||
$: selection && (isEdit = !selection.isEmpty())
|
||||
</script>
|
||||
|
||||
{#if openAIAvailable}
|
||||
{#if generatedCode}
|
||||
<div class="flex gap-1 px-2">
|
||||
<Button
|
||||
title="Discard generated code"
|
||||
btnClasses="!font-medium"
|
||||
size="xs"
|
||||
color="red"
|
||||
spacingSize="xs2"
|
||||
on:click={rejectDiff}
|
||||
variant="contained"
|
||||
startIcon={{ icon: faClose }}
|
||||
{iconOnly}
|
||||
>
|
||||
Discard
|
||||
</Button><Button
|
||||
title="Accept generated code"
|
||||
btnClasses="!font-medium"
|
||||
size="xs"
|
||||
color="green"
|
||||
spacingSize="xs2"
|
||||
on:click={acceptDiff}
|
||||
startIcon={{ icon: faCheck }}
|
||||
{iconOnly}
|
||||
>
|
||||
Accept
|
||||
</Button>
|
||||
</div>
|
||||
{:else}
|
||||
<Button
|
||||
title="Generate code from prompt"
|
||||
btnClasses="!font-medium text-gray-600"
|
||||
size="xs"
|
||||
color="light"
|
||||
spacingSize="md"
|
||||
bind:element={button}
|
||||
startIcon={{ icon: faMagicWandSparkles }}
|
||||
{iconOnly}
|
||||
loading={genLoading}
|
||||
>
|
||||
{isEdit ? 'AI Edit' : 'AI Gen'}
|
||||
</Button>
|
||||
{/if}
|
||||
{#if !generatedCode}
|
||||
<Popup
|
||||
ref={button}
|
||||
options={{ placement: 'top-start' }}
|
||||
transition={fade}
|
||||
closeOn={[]}
|
||||
wrapperClasses="!z-[1002]"
|
||||
outerClasses="rounded shadow-xl bg-white border p-3 w-96"
|
||||
>
|
||||
<label class="block text-gray-900">
|
||||
<div class="pb-1 text-sm text-gray-600">Prompt</div>
|
||||
<div class="flex w-full">
|
||||
<input
|
||||
type="text"
|
||||
bind:this={input}
|
||||
bind:value={funcDesc}
|
||||
class="!w-auto grow"
|
||||
on:keypress={({ key }) => {
|
||||
if (key === 'Enter') {
|
||||
onGenerate()
|
||||
}
|
||||
}}
|
||||
placeholder={isEdit
|
||||
? 'Describe the changes you want'
|
||||
: 'Describe what the script should do'}
|
||||
/>
|
||||
<Button
|
||||
size="xs"
|
||||
color="blue"
|
||||
buttonType="button"
|
||||
btnClasses="!p-1 !w-[34px] !ml-1"
|
||||
aria-label="Generate"
|
||||
on:click={onGenerate}
|
||||
>
|
||||
<Icon data={faMagicWandSparkles} />
|
||||
</Button>
|
||||
</div>
|
||||
</label>
|
||||
</Popup>
|
||||
{/if}
|
||||
{/if}
|
||||
@@ -0,0 +1 @@
|
||||
export { default as ScriptGen } from './ScriptGen.svelte'
|
||||
@@ -0,0 +1,280 @@
|
||||
import { OpenAI } from 'openai'
|
||||
import { OpenAPI } from '../../gen/core/OpenAPI'
|
||||
import { ResourceService, Script } from '../../gen'
|
||||
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { formatResourceTypes } from './utils'
|
||||
import { scriptLangToEditorLang } from '$lib/scripts'
|
||||
|
||||
const WARNING_MSG =
|
||||
'WARNING: this code was generated by OpenAI, it might not be accurate. Use at your own risk.'
|
||||
|
||||
const COMMENT_TYPES = {
|
||||
[Script.language.PYTHON3]: '#',
|
||||
[Script.language.DENO]: '//',
|
||||
[Script.language.GO]: '//',
|
||||
[Script.language.BASH]: '#',
|
||||
[Script.language.POSTGRESQL]: '--',
|
||||
[Script.language.MYSQL]: '--',
|
||||
[Script.language.NATIVETS]: '//',
|
||||
[Script.language.BUN]: '//'
|
||||
}
|
||||
|
||||
const PROMPTS = {
|
||||
[Script.language
|
||||
.PYTHON3]: `Write a function in python called "main". The function should {description}. Specify the parameter types. Do not call the main function.
|
||||
You have access to the following resource types, if you need them, you have to define a TypedDict with the name specified (DO NOT CAPITALIZE) and add them as parameters: {resourceTypes}`,
|
||||
[Script.language
|
||||
.DENO]: `Write a function in typescript called "main". The function should {description}. Specify the parameter types. You are in a Deno environment. You can import deno libraries or you can also import npm libraries like that: "import ... from "npm:{package}";". Export the "main" function like this: "export function main(...)". Do not call the main function.
|
||||
You have access to the following resource types, if you need them, you have to define the type with the name specified and add them as parameters: {resourceTypes}
|
||||
If the type name conflicts with the imported object, rename the imported object NOT THE TYPE.`,
|
||||
[Script.language.GO]:
|
||||
'Write a function in go called "main". The function should {description}. Import the packages you need. The return type of the function has to be ({return_type}, error). The file package has to be "inner".',
|
||||
[Script.language.BASH]:
|
||||
'Write bash code that should {description}. Do not include "#!/bin/bash". Arguments are always string and can only be obtained with "var1="$1"", "var2="$2"", etc... You do not need to check if the arguments are present.',
|
||||
[Script.language.POSTGRESQL]:
|
||||
'Write SQL code for a PostgreSQL that should {description}. Arguments can be obtained directly in the statement with $1::{type}, $2::{type}, etc... Name the parameters by adding comments before the command like that: -- $1 name1 (one per row, do not include the type)',
|
||||
[Script.language.MYSQL]:
|
||||
'Write SQL code for MySQL that should {description}. Arguments can be obtained directly in the statement with ?. Name the parameters by adding comments before the command like that: -- ? name1 ({type}) (one per row)',
|
||||
[Script.language
|
||||
.NATIVETS]: `Write a function in typescript called "main". The function should {description}. Specify the parameter types. You should use fetch and are not allowed to import any libraries. Export the "main" function like this: "export function main(...)". Do not call the main function.
|
||||
You have access to the following resource types, if you need them, you have to define the type with the name specified and add them as parameters: {resourceTypes}
|
||||
If the type name conflicts with the imported object, rename the imported object NOT THE TYPE.`,
|
||||
[Script.language
|
||||
.BUN]: `Write a function in typescript called "main". The function should {description}. Specify the parameter types. You are in a Node.js environment. You can import npm libraries. Export the "main" function like this: "export function main(...)". Do not call the main function.
|
||||
You have access to the following resource types, if you need them, you have to define the type with the name specified and add them as parameters: {resourceTypes}
|
||||
If the type name conflicts with the imported object, rename the imported object NOT THE TYPE.`
|
||||
}
|
||||
|
||||
function scriptLangToEnvironment(lang: Script.language) {
|
||||
if (lang === Script.language.DENO) {
|
||||
return 'typescript in a deno running environment'
|
||||
} else if (lang === Script.language.BUN) {
|
||||
return 'typescript in a node.js running environment'
|
||||
} else if (lang === Script.language.NATIVETS) {
|
||||
return 'typescript where you should use fetch and are not allowed to import any libraries'
|
||||
} else {
|
||||
return lang
|
||||
}
|
||||
}
|
||||
|
||||
const SYSTEM_PROMPT =
|
||||
'You write code as queried by the user. Only output code. Wrap the code like that: ```language\n{code}\n```. Put any explanation directly in the code as comments.'
|
||||
|
||||
const EDIT_SYSTEM_PROMPT =
|
||||
'You edit the code as queried by the user. Only output code. Wrap the code like that: ```language\n{code}\n```. Put any explanation directly in the code as comments.'
|
||||
|
||||
const EDIT_PROMPT =
|
||||
"Here's my environement: {environment}\nHere's my code: ```{lang}\n{code}\n```\nMy instructions: {description}"
|
||||
|
||||
const FIX_PROMPT =
|
||||
"Here's my environement: {environment}\nHere's my code: ```{lang}\n{code}\n```\nI get the following error: {error}\nFix it for me."
|
||||
|
||||
const FIX_SYSTEM_PROMPT =
|
||||
'You fix the code shared by the user. Only output code. Wrap the code like that: ```language\n{code}\n```. Put explanations directly in the code as comments.'
|
||||
|
||||
export const SUPPORTED_LANGUAGES = new Set(Object.keys(PROMPTS))
|
||||
|
||||
let workspace: string | undefined = undefined
|
||||
|
||||
workspaceStore.subscribe((value) => {
|
||||
workspace = value
|
||||
})
|
||||
|
||||
interface BaseOptions {
|
||||
language: Script.language
|
||||
}
|
||||
|
||||
interface ScriptGenerationOptions extends BaseOptions {
|
||||
language: Script.language
|
||||
description: string
|
||||
}
|
||||
|
||||
interface EditScriptOptions extends ScriptGenerationOptions {
|
||||
selectedCode: string
|
||||
}
|
||||
|
||||
interface FixScriptOpions extends BaseOptions {
|
||||
code: string
|
||||
error: string
|
||||
}
|
||||
|
||||
export async function generateScript(scriptOptions: ScriptGenerationOptions): Promise<string> {
|
||||
if (!workspace) {
|
||||
throw new Error('No workspace selected')
|
||||
}
|
||||
|
||||
const baseURL = `${location.origin}${OpenAPI.BASE}/w/${workspace}/openai/proxy`
|
||||
const openai = new OpenAI({
|
||||
baseURL,
|
||||
apiKey: 'fakekey',
|
||||
defaultHeaders: {
|
||||
Authorization: ''
|
||||
}
|
||||
})
|
||||
|
||||
let prompt = PROMPTS[scriptOptions.language].replace('{description}', scriptOptions.description)
|
||||
|
||||
if (
|
||||
[Script.language.DENO, Script.language.BUN, Script.language.NATIVETS].includes(
|
||||
scriptOptions.language
|
||||
)
|
||||
) {
|
||||
const resourceTypes = await ResourceService.listResourceType({ workspace })
|
||||
const resourceTypesText = formatResourceTypes(resourceTypes, true)
|
||||
prompt = prompt.replace('{resourceTypes}', resourceTypesText)
|
||||
} else if (scriptOptions.language == Script.language.PYTHON3) {
|
||||
const resourceTypes = await ResourceService.listResourceType({ workspace })
|
||||
const resourceTypesText = formatResourceTypes(resourceTypes, false)
|
||||
prompt = prompt.replace('{resourceTypes}', resourceTypesText)
|
||||
}
|
||||
|
||||
const completion = await openai.chat.completions.create({
|
||||
model: 'gpt-4',
|
||||
max_tokens: 2048,
|
||||
messages: [
|
||||
{
|
||||
role: 'system',
|
||||
content: SYSTEM_PROMPT
|
||||
},
|
||||
{
|
||||
role: 'user',
|
||||
content: prompt
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
let result = completion.choices[0]?.message?.content
|
||||
|
||||
if (!result) {
|
||||
throw new Error('No result from OpenAI')
|
||||
}
|
||||
|
||||
const match = result.match(/```[a-zA-z]+\n([\s\S]*?)\n```/)
|
||||
|
||||
if (!match || match.length < 2) {
|
||||
throw new Error('No code block found')
|
||||
}
|
||||
|
||||
result = match[1]
|
||||
|
||||
if (scriptOptions.language == Script.language.GO) {
|
||||
const warning = COMMENT_TYPES[scriptOptions.language] + ' ' + WARNING_MSG + '\n'
|
||||
|
||||
return result.trim().replace('package inner\n', 'package inner\n' + warning)
|
||||
} else if (scriptOptions.language == Script.language.BASH) {
|
||||
return (
|
||||
'# shellcheck shell=bash\n' +
|
||||
COMMENT_TYPES[scriptOptions.language] +
|
||||
' ' +
|
||||
WARNING_MSG +
|
||||
'\n\n' +
|
||||
result.trim()
|
||||
)
|
||||
} else {
|
||||
return COMMENT_TYPES[scriptOptions.language] + ' ' + WARNING_MSG + '\n\n' + result.trim()
|
||||
}
|
||||
}
|
||||
|
||||
export async function editScript(scriptOptions: EditScriptOptions): Promise<string> {
|
||||
if (!workspace) {
|
||||
throw new Error('No workspace selected')
|
||||
}
|
||||
|
||||
const baseURL = `${location.origin}${OpenAPI.BASE}/w/${workspace}/openai/proxy`
|
||||
const openai = new OpenAI({
|
||||
baseURL,
|
||||
apiKey: 'fakekey',
|
||||
defaultHeaders: {
|
||||
Authorization: ''
|
||||
}
|
||||
})
|
||||
|
||||
let prompt = EDIT_PROMPT.replace('{lang}', scriptLangToEditorLang(scriptOptions.language))
|
||||
.replace('{code}', scriptOptions.selectedCode)
|
||||
.replace('{description}', scriptOptions.description)
|
||||
.replace('{environment}', scriptLangToEnvironment(scriptOptions.language))
|
||||
|
||||
const completion = await openai.chat.completions.create({
|
||||
model: 'gpt-4',
|
||||
max_tokens: 512,
|
||||
messages: [
|
||||
{
|
||||
role: 'system',
|
||||
content: EDIT_SYSTEM_PROMPT
|
||||
},
|
||||
{
|
||||
role: 'user',
|
||||
content: prompt
|
||||
}
|
||||
],
|
||||
temperature: 0.5
|
||||
})
|
||||
|
||||
let result = completion.choices[0]?.message?.content
|
||||
|
||||
if (!result) {
|
||||
throw new Error('No result from OpenAI')
|
||||
}
|
||||
|
||||
const match = result.match(/```[a-zA-z]+\n([\s\S]*?)\n```/)
|
||||
|
||||
if (!match || match.length < 2) {
|
||||
throw new Error('No code block found')
|
||||
}
|
||||
|
||||
result = match[1]
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
export async function fixScript(scriptOptions: FixScriptOpions) {
|
||||
if (!workspace) {
|
||||
throw new Error('No workspace selected')
|
||||
}
|
||||
|
||||
const baseURL = `${location.origin}${OpenAPI.BASE}/w/${workspace}/openai/proxy`
|
||||
const openai = new OpenAI({
|
||||
baseURL,
|
||||
apiKey: 'fakekey',
|
||||
defaultHeaders: {
|
||||
Authorization: ''
|
||||
}
|
||||
})
|
||||
|
||||
let prompt = FIX_PROMPT.replace('{lang}', scriptLangToEditorLang(scriptOptions.language))
|
||||
.replace('{code}', scriptOptions.code)
|
||||
.replace('{error}', scriptOptions.error)
|
||||
.replace('{environment}', scriptLangToEnvironment(scriptOptions.language))
|
||||
|
||||
const completion = await openai.chat.completions.create({
|
||||
model: 'gpt-4',
|
||||
max_tokens: 512,
|
||||
messages: [
|
||||
{
|
||||
role: 'system',
|
||||
content: FIX_SYSTEM_PROMPT
|
||||
},
|
||||
{
|
||||
role: 'user',
|
||||
content: prompt
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
let result = completion.choices[0]?.message?.content
|
||||
|
||||
if (!result) {
|
||||
throw new Error('No result from OpenAI')
|
||||
}
|
||||
|
||||
const match = result.match(/```[a-zA-z]+\n([\s\S]*?)\n```/)
|
||||
|
||||
if (!match || match.length < 2) {
|
||||
throw new Error('No code block found')
|
||||
}
|
||||
|
||||
result = match[1]
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import type { Schema, SchemaProperty } from '../../common'
|
||||
|
||||
import type { ResourceType } from '../../gen'
|
||||
|
||||
import { capitalize } from '$lib/utils'
|
||||
|
||||
function compile(schema: Schema) {
|
||||
function rec(x: { [name: string]: SchemaProperty }, root = false) {
|
||||
let res = '{ '
|
||||
const entries = Object.entries(x)
|
||||
if (entries.length == 0) {
|
||||
return 'any'
|
||||
}
|
||||
let i = 0
|
||||
for (let [name, prop] of entries) {
|
||||
if (prop.type == 'object') {
|
||||
res += `${name}: ${rec(prop.properties ?? {})}`
|
||||
} else if (prop.type == 'array') {
|
||||
res += `${name}: ${prop?.items?.type ?? 'any'}[]`
|
||||
} else {
|
||||
let typ = prop?.type ?? 'any'
|
||||
if (typ == 'integer') {
|
||||
typ = 'number'
|
||||
}
|
||||
res += `${name}: ${typ}`
|
||||
}
|
||||
i++
|
||||
if (i < entries.length) {
|
||||
res += ', '
|
||||
}
|
||||
}
|
||||
res += ' }'
|
||||
return res
|
||||
}
|
||||
return rec(schema.properties, true)
|
||||
}
|
||||
|
||||
function toCamel(s) {
|
||||
return s.replace(/([-_][a-z])/gi, ($1) => {
|
||||
return $1.toUpperCase().replace('-', '').replace('_', '')
|
||||
})
|
||||
}
|
||||
|
||||
export function formatResourceTypes(resourceTypes: ResourceType[], camel = false) {
|
||||
const result = resourceTypes.map((resourceType) => {
|
||||
return `${camel ? toCamel(capitalize(resourceType.name)) : resourceType.name} ${compile(
|
||||
resourceType.schema
|
||||
)}`
|
||||
})
|
||||
|
||||
return result.join(', ')
|
||||
}
|
||||
@@ -19,11 +19,15 @@
|
||||
import { Pane, Splitpanes } from 'svelte-splitpanes'
|
||||
import SplitPanesWrapper from '../splitPanes/SplitPanesWrapper.svelte'
|
||||
import { Loader2 } from 'lucide-svelte'
|
||||
import type Editor from '../Editor.svelte'
|
||||
import type DiffEditor from '../DiffEditor.svelte'
|
||||
|
||||
export let lang: Preview.language | undefined
|
||||
export let previewIsLoading = false
|
||||
export let previewJob: Job | undefined
|
||||
export let pastPreviews: CompletedJob[] = []
|
||||
export let editor: Editor | undefined = undefined
|
||||
export let diffEditor: DiffEditor | undefined = undefined
|
||||
|
||||
type DrawerContent = {
|
||||
mode: 'json' | Preview.language | 'plain'
|
||||
@@ -92,6 +96,9 @@
|
||||
workspaceId={previewJob?.workspace_id}
|
||||
jobId={previewJob?.id}
|
||||
result={previewJob.result}
|
||||
{editor}
|
||||
{diffEditor}
|
||||
{lang}
|
||||
/>
|
||||
</div>
|
||||
{:else}
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
let customer_id: string | undefined = undefined
|
||||
let webhook: string | undefined = undefined
|
||||
let workspaceToDeployTo: string | undefined = undefined
|
||||
let openAIKey: string | undefined = undefined
|
||||
let errorHandlerInitialPath: string
|
||||
let errorHandlerScriptPath: string
|
||||
let errorHandlerItemKind: 'script' = 'script'
|
||||
@@ -125,6 +126,23 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function editOpenAIKey(): Promise<void> {
|
||||
// in JS, an empty string is also falsy
|
||||
if (openAIKey) {
|
||||
await WorkspaceService.editOpenaiKey({
|
||||
workspace: $workspaceStore!,
|
||||
requestBody: { openai_key: openAIKey }
|
||||
})
|
||||
sendUserToast('OpenAI key set')
|
||||
} else {
|
||||
await WorkspaceService.editOpenaiKey({
|
||||
workspace: $workspaceStore!,
|
||||
requestBody: { openai_key: undefined }
|
||||
})
|
||||
sendUserToast(`OpenAI key removed`)
|
||||
}
|
||||
}
|
||||
|
||||
async function loadSettings(): Promise<void> {
|
||||
const settings = await WorkspaceService.getSettings({ workspace: $workspaceStore! })
|
||||
team_name = settings.slack_name
|
||||
@@ -139,6 +157,7 @@
|
||||
customer_id = settings.customer_id
|
||||
workspaceToDeployTo = settings.deploy_to
|
||||
webhook = settings.webhook
|
||||
openAIKey = settings.openai_key
|
||||
errorHandlerScriptPath = (settings.error_handler ?? '').split('/').slice(1).join('/')
|
||||
errorHandlerInitialPath = errorHandlerScriptPath
|
||||
}
|
||||
@@ -275,6 +294,14 @@
|
||||
<Tab size="md" value="error_handler">
|
||||
<div class="flex gap-2 items-center my-1">Error Handler</div>
|
||||
</Tab>
|
||||
|
||||
<Tab size="md" value="openai">
|
||||
<div class="flex gap-2 items-center my-1"
|
||||
>OpenAI Credentials <span class="text-white px-2 py-1 rounded-full text-xs bg-red-500"
|
||||
>Beta</span
|
||||
></div
|
||||
>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</div>
|
||||
{#if tab == 'users'}
|
||||
@@ -848,6 +875,17 @@
|
||||
></div
|
||||
>
|
||||
</div>
|
||||
{:else if tab == 'openai'}
|
||||
<PageHeader title="OpenAI Credentials" primary={false} />
|
||||
<div class="mt-2"
|
||||
><Alert type="info" title="Experimental feature"
|
||||
>Enter your OpenAI api key to unlock Windmill's AI features!</Alert
|
||||
></div
|
||||
>
|
||||
<div class="flex gap-2 mt-5">
|
||||
<input type="text" placeholder="Secret API key" bind:value={openAIKey} />
|
||||
<Button size="md" on:click={editOpenAIKey}>Save</Button>
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="bg-red-100 border-l-4 border-red-600 text-orange-700 p-4 m-4" role="alert">
|
||||
|
||||
Reference in New Issue
Block a user