mirror of
https://github.com/System-End/site.git
synced 2026-04-19 19:45:07 +00:00
Bin Development 2024-05-02 (#1190)
* added caching for images (need to fix) * added part fetching (needs fixing) * Add more clicky buttons * Add endpoint for project suggestions * Improve project idea prompt * Add project idea section --------- Co-authored-by: Max Wofford <max@maxwofford.com>
This commit is contained in:
parent
457d5b2607
commit
ea455cfa81
9 changed files with 358 additions and 255 deletions
|
|
@ -57,6 +57,7 @@
|
|||
"next": "^12.3.1",
|
||||
"next-transpile-modules": "^10.0.1",
|
||||
"nextjs-current-url": "^1.0.3",
|
||||
"openai": "^4.42.0",
|
||||
"pcb-stackup": "^4.2.8",
|
||||
"react": "^17.0.2",
|
||||
"react-before-after-slider-component": "^1.1.8",
|
||||
|
|
|
|||
40
pages/api/bin/openai.js
Normal file
40
pages/api/bin/openai.js
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import OpenAI from 'openai';
|
||||
|
||||
const generateProjectIdea = async (parts) => {
|
||||
|
||||
let prompt = `I'm running a hardware program around the raspberry pi pico w where high schoolers will build a simple project using the following parts. Please propose a simple project in 1-2 sentences to use as a prompt for the high schoolers to build with:
|
||||
|
||||
`
|
||||
parts.forEach((part) => {
|
||||
prompt += `- ${part}\n`
|
||||
})
|
||||
|
||||
prompt += `
|
||||
The project should only involve household items like lamps. The project should only use sensors provided, and use those sensors for their intended use. For example, an accelerometer cannot be used to measure humidity or tilt.`
|
||||
|
||||
// expects OPENAI_API_KEY
|
||||
const openai = new OpenAI();
|
||||
const chatCompletion = await openai.chat.completions.create({
|
||||
messages: [{ role: 'user', content: prompt }],
|
||||
model: 'gpt-3.5-turbo',
|
||||
});
|
||||
|
||||
return chatCompletion.choices[0].message.content
|
||||
}
|
||||
|
||||
export default async function handler(req, res) {
|
||||
const requestedParts = req.body.parts
|
||||
|
||||
const availablePartsReq = await fetch('https://hackclub.com/api/bin/wokwi/parts')
|
||||
const availableParts = await availablePartsReq.json()
|
||||
|
||||
// check that the requested parts are in the available parts
|
||||
const parts = requestedParts.map((requestedPart) => {
|
||||
return availableParts.find((availablePart) => availablePart.wokwiName === requestedPart)?.name
|
||||
})
|
||||
|
||||
const recommendation = await generateProjectIdea(parts)
|
||||
|
||||
res.send({recommendation, parts})
|
||||
}
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
var fetchedParts;
|
||||
var selectedParts = []
|
||||
var rolled = false;
|
||||
async function fetchParts() {
|
||||
/*
|
||||
const response = await fetch('https://hackclub.com/api/bin/wokwi/parts/');
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok.');
|
||||
|
|
@ -9,192 +9,19 @@ async function fetchParts() {
|
|||
data = await response.json();
|
||||
|
||||
data = removeItemByAttribute(data, "type", "Microprocessor");
|
||||
console.log(data)*/
|
||||
data = [
|
||||
{
|
||||
"name": "Motion Sensor",
|
||||
"flavorText": "Detects movement.",
|
||||
"type": "Component",
|
||||
"wokwiName": "wokwi-pir-motion-sensor",
|
||||
"wokwiXOffset": 89
|
||||
},
|
||||
{
|
||||
"name": "Temperature Sensor",
|
||||
"flavorText": "Temp checker!",
|
||||
"type": "Component",
|
||||
"wokwiName": "board-ds18b20",
|
||||
"wokwiXOffset": 32.88
|
||||
},
|
||||
{
|
||||
"name": "Clock (RTC)",
|
||||
"flavorText": "It's a clock!",
|
||||
"type": "Component",
|
||||
"wokwiName": "wokwi-ds1307",
|
||||
"wokwiXOffset": 99
|
||||
},
|
||||
{
|
||||
"name": "Buzzer",
|
||||
"flavorText": "Make noise!",
|
||||
"type": "Component",
|
||||
"wokwiName": "wokwi-buzzer",
|
||||
"notes (internal)": "Double check if active or passive",
|
||||
"wokwiXOffset": 69
|
||||
},
|
||||
{
|
||||
"name": "Humidity",
|
||||
"flavorText": "Moisture monitor",
|
||||
"imageUrl": "https://cloud-q01dbzfhj-hack-club-bot.vercel.app/1humidity.png",
|
||||
"type": "Component",
|
||||
"wokwiName": "wokwi-dht22",
|
||||
"notes (internal)": "We actually send the dht11",
|
||||
"wokwiXOffset": 56
|
||||
},
|
||||
{
|
||||
"name": "Rotary Encoder",
|
||||
"flavorText": "Detect spinning!",
|
||||
"type": "Component",
|
||||
"wokwiName": "wokwi-ky-040",
|
||||
"wokwiXOffset": 120
|
||||
},
|
||||
{
|
||||
"name": "Shift Register",
|
||||
"flavorText": "Switch inputs!",
|
||||
"type": "Component",
|
||||
"wokwiName": "wokwi-74hc595",
|
||||
"wokwiXOffset": 76
|
||||
},
|
||||
{
|
||||
"name": "Range finder",
|
||||
"flavorText": "Measure distance!",
|
||||
"type": "Component",
|
||||
"wokwiName": "wokwi-hc-sr04",
|
||||
"wokwiXOffset": 168.7
|
||||
},
|
||||
{
|
||||
"name": "Keypad",
|
||||
"flavorText": "Dial a number!",
|
||||
"type": "Component",
|
||||
"wokwiName": "wokwi-membrane-keypad",
|
||||
"wokwiXOffset": 264.8
|
||||
},
|
||||
{
|
||||
"name": "Accelerometer",
|
||||
"flavorText": "Speedchecker!",
|
||||
"type": "Component",
|
||||
"wokwiName": "wokwi-mpu6050",
|
||||
"wokwiXOffset": 82
|
||||
},
|
||||
{
|
||||
"name": "Neopixel LED",
|
||||
"flavorText": "Technicolor!",
|
||||
"type": "Component",
|
||||
"wokwiName": "wokwi-neopixel",
|
||||
"wokwiXOffset": 21
|
||||
},
|
||||
{
|
||||
"name": "LED",
|
||||
"flavorText": "It's lit!",
|
||||
"imageUrl": "https://cloud-q01dbzfhj-hack-club-bot.vercel.app/4led.png",
|
||||
"type": "Component",
|
||||
"wokwiName": "wokwi-led",
|
||||
"wokwiXOffset": 24
|
||||
},
|
||||
{
|
||||
"name": "Stepper Motor",
|
||||
"flavorText": "It spins!",
|
||||
"type": "Component",
|
||||
"wokwiName": "wokwi-stepper-motor,wokwi-a4988",
|
||||
"wokwiXOffset": 162
|
||||
},
|
||||
{
|
||||
"name": "Slider",
|
||||
"flavorText": "A sliding input!",
|
||||
"type": "Component",
|
||||
"wokwiName": "wokwi-slide-potentiometer",
|
||||
"wokwiXOffset": 210.2
|
||||
},
|
||||
{
|
||||
"name": "Thermistor",
|
||||
"flavorText": "Temperature checker!",
|
||||
"type": "Component",
|
||||
"wokwiName": "wokwi-ntc-temperature-sensor",
|
||||
"wokwiXOffset": 139
|
||||
},
|
||||
{
|
||||
"name": "Relay",
|
||||
"flavorText": "Turn things on and off!",
|
||||
"imageUrl": "https://cloud-q01dbzfhj-hack-club-bot.vercel.app/0relay.png",
|
||||
"type": "Component",
|
||||
"wokwiName": "wokwi-relay-module",
|
||||
"wokwiXOffset": 130
|
||||
},
|
||||
{
|
||||
"name": "LCD",
|
||||
"flavorText": "Display text!",
|
||||
"type": "Component",
|
||||
"wokwiName": "wokwi-lcd1602",
|
||||
"wokwiXOffset": 303.2
|
||||
},
|
||||
{
|
||||
"name": "Servo",
|
||||
"flavorText": "Move stuff",
|
||||
"type": "Component",
|
||||
"wokwiName": "wokwi-servo",
|
||||
"wokwiXOffset": 178.2
|
||||
},
|
||||
{
|
||||
"name": "Joystick",
|
||||
"flavorText": "It's a joystick!",
|
||||
"type": "Component",
|
||||
"wokwiName": "wokwi-analog-joystick",
|
||||
"wokwiXOffset": 98
|
||||
},
|
||||
{
|
||||
"name": "Potentiometer",
|
||||
"flavorText": "It's a dial!",
|
||||
"type": "Component",
|
||||
"wokwiName": "wokwi-potentiometer",
|
||||
"wokwiXOffset": 76.6
|
||||
},
|
||||
{
|
||||
"name": "Multicolor LED",
|
||||
"flavorText": "Now, in color!",
|
||||
"type": "Component",
|
||||
"wokwiName": "wokwi-rgb-led",
|
||||
"wokwiXOffset": 30
|
||||
},
|
||||
{
|
||||
"name": "Photoresistor",
|
||||
"flavorText": "Detect light!",
|
||||
"type": "Component",
|
||||
"wokwiName": "wokwi-photoresistor-sensor",
|
||||
"wokwiXOffset": 173.6
|
||||
},
|
||||
{
|
||||
"name": "Button",
|
||||
"flavorText": "Bop it!",
|
||||
"type": "Component",
|
||||
"wokwiName": "wokwi-pushbutton",
|
||||
"wokwiXOffset": 67
|
||||
},
|
||||
{
|
||||
"name": "IR Reciever",
|
||||
"flavorText": "Detect Infrared!",
|
||||
"imageUrl": "https://cloud-q01dbzfhj-hack-club-bot.vercel.app/2ir.png",
|
||||
"type": "Component",
|
||||
"wokwiName": "wokwi-ir-receiver",
|
||||
"wokwiXOffset": 62
|
||||
},
|
||||
{
|
||||
"name": "LED Matrix",
|
||||
"flavorText": "Display stuff!",
|
||||
"type": "Component",
|
||||
"wokwiName": "wokwi-max7219-matrix",
|
||||
"wokwiXOffset": 340
|
||||
}
|
||||
]
|
||||
console.log(data)
|
||||
return data
|
||||
}
|
||||
async function preloadImage(item) {
|
||||
let response = await fetch(item.imageUrl);
|
||||
let blob = response.blob();
|
||||
return blob
|
||||
}
|
||||
async function saveImageToCache(item) {
|
||||
const image = await preloadImage(item)
|
||||
const blob = URL.createObjectURL(image)
|
||||
localStorage.setItem(item.wokwiName, blob);
|
||||
}
|
||||
function removeItemByAttribute(arr, attr, value) {
|
||||
return arr.filter(item => item[attr] !== value);
|
||||
}
|
||||
|
|
@ -252,23 +79,79 @@ function rollParts() {
|
|||
addComponentsToPage(data)
|
||||
}
|
||||
rolled = true
|
||||
let results = {}
|
||||
let counter = 0
|
||||
document.querySelector(".gambling-build").classList.remove("disabled")
|
||||
let results = []
|
||||
document.querySelectorAll(".gambling-item-wrapper").forEach((element) => {
|
||||
let randomThingy = getRandomInt(fetchedParts.length - 1)
|
||||
let spinnerImage = element.childNodes[2].childNodes[0]
|
||||
let partTitle = element.childNodes[2].childNodes[1]
|
||||
let flavorText = element.childNodes[2].childNodes[2]
|
||||
let result = fetchedParts[randomThingy]
|
||||
spinnerImage.src = (result.imageURL == "" || result.imageURL == undefined) ? "https://awdev.codes/images/ww.gif" : result.imageURL
|
||||
//spinnerImage.src = (result.imageUrl == "" || result.imageUrl == undefined) ? "https://awdev.codes/images/ww.gif" : result.imageUrl
|
||||
spinnerImage.src = (result.imageUrl == "" || result.imageUrl == undefined) ? localStorage.getItem("wokwi-pedro") : localStorage.getItem(result.wokwiName)
|
||||
partTitle.innerText = result.name;
|
||||
flavorText.innerText = result.flavorText;
|
||||
results[counter] = result.wokwiName
|
||||
counter++;
|
||||
results.push(result.wokwiName)
|
||||
})
|
||||
console.log(results)
|
||||
selectedParts = results
|
||||
}
|
||||
|
||||
window.addEventListener("load", (e) => {
|
||||
fetchParts().then(parts => { fetchedParts = parts });
|
||||
|
||||
async function generateBuildLink(e) {
|
||||
if (!rolled) {
|
||||
return
|
||||
}
|
||||
e.classList.add("disabled")
|
||||
e.classList.add("loading")
|
||||
const payload = {
|
||||
parts: selectedParts
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/bin/wokwi/new/', {
|
||||
mode: 'cors',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(payload)
|
||||
})
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok');
|
||||
}
|
||||
const json = await response.json()
|
||||
const shareLink = json.shareLink
|
||||
|
||||
// window.open(shareLink, '_blank').focus()
|
||||
} catch (error) {
|
||||
console.error('Error:', error)
|
||||
// e.classList.add("error")
|
||||
}
|
||||
e.classList.remove("disabled")
|
||||
e.classList.remove("loading")
|
||||
}
|
||||
window.addEventListener("load", (e) => {
|
||||
fetchParts().then(parts => {
|
||||
fetchedParts = parts;
|
||||
fetchedParts.forEach(part => {
|
||||
if (!(part.imageUrl == undefined)) {
|
||||
console.log(part.wokwiName)
|
||||
saveImageToCache(part);
|
||||
}
|
||||
})
|
||||
saveImageToCache({ wokwiName: "wokwi-pedro", imageUrl: "https://awdev.codes/images/ww.gif" })
|
||||
});
|
||||
|
||||
document.querySelector("#generate-project-idea").addEventListener("click", async (e) => {
|
||||
document.querySelector('#project-idea').innerText = "Thinking..."
|
||||
const res = await fetch('/api/bin/openai/', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ parts: selectedParts })
|
||||
})
|
||||
const json = await res.json()
|
||||
document.querySelector('#project-idea').innerText = json.recommendation
|
||||
})
|
||||
})
|
||||
|
|
@ -60,10 +60,26 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="gambling-controls">
|
||||
<button onclick="rollParts()" class="gambling-roll">Roll!</button>
|
||||
<button onclick="rollParts()" class="gambling-roll hoverable">Roll!</button>
|
||||
<span class="flex-lb"></span>
|
||||
<button onclick="location.href='../selector'" class="gambling-select">Manual Selection</button>
|
||||
<button onclick="" class="gambling-build">Continue<img src="../icons/arrow.svg"></button>
|
||||
<button onclick="location.href='../selector/index.html'" class="gambling-select hoverable">Manual
|
||||
Selection</button>
|
||||
<button onclick="generateBuildLink(this)" class="gambling-build hoverable disabled">Continue<img
|
||||
src="../icons/arrow.svg"></button>
|
||||
</div>
|
||||
</section>
|
||||
<section class="project-idea-section section">
|
||||
<div class="container">
|
||||
<h1>What are we building today?</h1>
|
||||
<textarea id="project-name" placeholder="I'm going to build a..."></textarea>
|
||||
<h2>💡 Need an idea? Click the raccoon!</h2>
|
||||
<div style="display: flex;">
|
||||
<div>
|
||||
<img src="../images/idea.png" style="margin: 0 auto; display: inline; max-width: 10em" id="generate-project-idea">
|
||||
<p><em>(It doesn't know much about electronics, but it'll try its best.)</em></p>
|
||||
</div>
|
||||
<p id="project-idea">🗑️</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<footer>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,20 @@
|
|||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.container {
|
||||
margin: auto;
|
||||
padding: 0 20px;
|
||||
max-width: 52em;
|
||||
}
|
||||
|
||||
.hoverable {
|
||||
transition: 500ms transform;
|
||||
}
|
||||
|
||||
.hoverable:hover {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.flex-lb {
|
||||
width: 100%;
|
||||
display: block;
|
||||
|
|
@ -336,3 +350,16 @@
|
|||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.disabled {
|
||||
cursor: not-allowed !important;
|
||||
}
|
||||
|
||||
.loading {
|
||||
cursor: wait !important;
|
||||
}
|
||||
|
||||
#generate-project-idea {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
|
@ -15,49 +15,7 @@
|
|||
<h1 class="selector-title">The Bin</h1>
|
||||
<button class="selector-continue">Let's Build!<img src="../icons/arrow.svg"></button>
|
||||
</div>
|
||||
<div class="selector-main">
|
||||
<div part_name="relay" class="selector-item">
|
||||
<img class="selector-image" src="../parts/relay.png">
|
||||
<div class="selector-item-name">Relay</div>
|
||||
<div class="selector-item-description">On/Off Switch</div>
|
||||
</div>
|
||||
<div part_name="laser" class="selector-item">
|
||||
<img class="selector-image" src="../parts/laser.png">
|
||||
<div class="selector-item-name">Laser</div>
|
||||
<div class="selector-item-description">Shoots Light</div>
|
||||
</div>
|
||||
<div part_name="led" class="selector-item">
|
||||
<img class="selector-image" src="../parts/led.png">
|
||||
<div class="selector-item-name">LED</div>
|
||||
<div class="selector-item-description">Shines light</div>
|
||||
</div>
|
||||
<div part_name="humidity" class="selector-item">
|
||||
<img class="selector-image" src="../parts/humidity.png">
|
||||
<div class="selector-item-name">Humidity</div>
|
||||
<div class="selector-item-description">Measures humidity</div>
|
||||
</div>
|
||||
<span class="flex-lb"></span>
|
||||
<div part_name="mic" class="selector-item">
|
||||
<img class="selector-image" src="../parts/mic-right.png">
|
||||
<div class="selector-item-name">Mic</div>
|
||||
<div class="selector-item-description">Records sounds</div>
|
||||
</div>
|
||||
<div part_name="mic" class="selector-item">
|
||||
<img class="selector-image" src="../parts/mic.png">
|
||||
<div class="selector-item-name">Mic</div>
|
||||
<div class="selector-item-description">Records sounds</div>
|
||||
</div>
|
||||
<div part_name="led" class="selector-item">
|
||||
<img class="selector-image" src="../parts/led.png">
|
||||
<div class="selector-item-name">LED</div>
|
||||
<div class="selector-item-description">Shines Light</div>
|
||||
</div>
|
||||
<div part_name="relay" class="selector-item">
|
||||
<img class="selector-image" src="../parts/relay.png">
|
||||
<div class="selector-item-name">Relay</div>
|
||||
<div class="selector-item-description">On/Off Switch</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="selector-main"></div>
|
||||
<span class="selector-number"></span>
|
||||
</div>
|
||||
<script src="./script.js"></script>
|
||||
|
|
|
|||
|
|
@ -1,24 +1,36 @@
|
|||
items = document.querySelectorAll(".selector-item")
|
||||
var fetchedParts;
|
||||
async function fetchParts() {
|
||||
const response = await fetch('https://hackclub.com/api/bin/wokwi/parts/');
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok.');
|
||||
}
|
||||
data = await response.json();
|
||||
|
||||
items.forEach(item => {
|
||||
item.addEventListener("click", () => {
|
||||
let isSelected = item.className.includes("selected")
|
||||
if (isSelected) {
|
||||
item.classList.remove("selected")
|
||||
} else {
|
||||
if (getSelectedItems().length < 3) {
|
||||
item.classList.add("selected")
|
||||
data = removeItemByAttribute(data, "type", "Microprocessor");
|
||||
console.log(data)
|
||||
return data
|
||||
}
|
||||
function removeItemByAttribute(arr, attr, value) {
|
||||
return arr.filter(item => item[attr] !== value);
|
||||
}
|
||||
async function preloadImage(item) {
|
||||
let response = await fetch(item.imageUrl);
|
||||
let blob = response.blob();
|
||||
return blob
|
||||
}
|
||||
async function saveImageToCache(item) {
|
||||
const image = await preloadImage(item)
|
||||
const blob = URL.createObjectURL(image)
|
||||
localStorage.setItem(item.wokwiName, blob);
|
||||
addPartToPage(item)
|
||||
}
|
||||
recalculateSelected();
|
||||
})
|
||||
});
|
||||
function getSelectedItems() {
|
||||
return document.querySelectorAll(".selected")
|
||||
}
|
||||
function recalculateSelected() {
|
||||
let numSelectedItems = getSelectedItems().length
|
||||
let selections = []
|
||||
items = document.querySelectorAll(".selector-item")
|
||||
document.querySelector(".selector-number").innerText = `${3 - numSelectedItems} choices remaining.`
|
||||
if (3 - numSelectedItems == 0) {
|
||||
items.forEach(item => {
|
||||
|
|
@ -42,5 +54,58 @@ function recalculateSelected() {
|
|||
return numSelectedItems
|
||||
}
|
||||
|
||||
function addPartToPage(part) {
|
||||
/*
|
||||
<div part_name="mic" class="selector-item">
|
||||
<img class="selector-image" src="../parts/mic.png">
|
||||
<div class="selector-item-name">Mic</div>
|
||||
<div class="selector-item-description">Records sounds</div>
|
||||
</div>
|
||||
*/
|
||||
let selectorItem = document.createElement("div")
|
||||
selectorItem.setAttribute("part_name", part.wokwiName)
|
||||
selectorItem.className = "selector-item"
|
||||
|
||||
let selectorImage = document.createElement("img")
|
||||
selectorImage.src = localStorage.getItem(part.wokwiName)
|
||||
selectorImage.className = "selector-image"
|
||||
selectorItem.appendChild(selectorImage)
|
||||
|
||||
let selectorItemName = document.createElement("div")
|
||||
selectorItemName.innerText = part.name
|
||||
selectorItemName.className = "selector-item-name"
|
||||
selectorItem.appendChild(selectorItemName)
|
||||
|
||||
let selectorItemDesc = document.createElement("div")
|
||||
selectorItemDesc.innerText = part.flavorText
|
||||
selectorItemDesc.className = "selector-item-description"
|
||||
selectorItem.appendChild(selectorItemDesc)
|
||||
|
||||
document.getElementsByClassName("selector-main")[0].appendChild(selectorItem)
|
||||
|
||||
selectorItem.addEventListener("click", () => {
|
||||
let isSelected = selectorItem.className.includes("selected")
|
||||
if (isSelected) {
|
||||
selectorItem.classList.remove("selected")
|
||||
} else {
|
||||
if (getSelectedItems().length < 3) {
|
||||
selectorItem.classList.add("selected")
|
||||
}
|
||||
}
|
||||
recalculateSelected();
|
||||
})
|
||||
}
|
||||
|
||||
window.addEventListener("load", (e) => {
|
||||
recalculateSelected();
|
||||
fetchParts().then(parts => {
|
||||
fetchedParts = parts;
|
||||
fetchedParts.forEach(part => {
|
||||
if (!(part.imageUrl == undefined)) {
|
||||
console.log(part.wokwiName)
|
||||
saveImageToCache(part);
|
||||
}
|
||||
})
|
||||
//saveImageToCache({ wokwiName: "wokwi-pedro", imageUrl: "https://awdev.codes/images/ww.gif" })
|
||||
});
|
||||
})
|
||||
|
|
@ -72,7 +72,7 @@
|
|||
}
|
||||
|
||||
.selector-item-name {
|
||||
font-size: 45px;
|
||||
font-size: 35px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
|
|
|||
115
yarn.lock
115
yarn.lock
|
|
@ -2448,6 +2448,14 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.34.tgz#10964ba0dee6ac4cd462e2795b6bebd407303433"
|
||||
integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==
|
||||
|
||||
"@types/node-fetch@^2.6.4":
|
||||
version "2.6.11"
|
||||
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.11.tgz#9b39b78665dae0e82a08f02f4967d62c66f95d24"
|
||||
integrity sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
form-data "^4.0.0"
|
||||
|
||||
"@types/node@*":
|
||||
version "17.0.23"
|
||||
resolved "https://registry.npmjs.org/@types/node/-/node-17.0.23.tgz"
|
||||
|
|
@ -2463,6 +2471,13 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.40.tgz#968d64746d20cac747a18ca982c0f1fe518c031c"
|
||||
integrity sha512-+yno3ItTEwGxXiS/75Q/aHaa5srkpnJaH+kdkTVJ3DtJEwv92itpKbxU+FjPoh2m/5G9zmUQfrL4A4C13c+iGA==
|
||||
|
||||
"@types/node@^18.11.18":
|
||||
version "18.19.32"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.32.tgz#96e4c80dca0ccf48505add2a399f36465955e0be"
|
||||
integrity sha512-2bkg93YBSDKk8DLmmHnmj/Rwr18TLx7/n+I23BigFwgexUJoMHZOd8X1OFxuF/W3NN0S2W2E5sVabI5CPinNvA==
|
||||
dependencies:
|
||||
undici-types "~5.26.4"
|
||||
|
||||
"@types/parse-json@^4.0.0":
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz"
|
||||
|
|
@ -2590,6 +2605,13 @@
|
|||
dependencies:
|
||||
tslib "^2.3.0"
|
||||
|
||||
abort-controller@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392"
|
||||
integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==
|
||||
dependencies:
|
||||
event-target-shim "^5.0.0"
|
||||
|
||||
acorn-jsx@^5.3.2:
|
||||
version "5.3.2"
|
||||
resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz"
|
||||
|
|
@ -2605,6 +2627,13 @@ add@^2.0.6:
|
|||
resolved "https://registry.npmjs.org/add/-/add-2.0.6.tgz"
|
||||
integrity sha512-j5QzrmsokwWWp6kUcJQySpbG+xfOBqqKnup3OIk1pz+kB/80SLorZ9V8zHFLO92Lcd+hbvq8bT+zOGoPkmBV0Q==
|
||||
|
||||
agentkeepalive@^4.2.1:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923"
|
||||
integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==
|
||||
dependencies:
|
||||
humanize-ms "^1.2.1"
|
||||
|
||||
airtable-plus@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.npmjs.org/airtable-plus/-/airtable-plus-1.0.4.tgz"
|
||||
|
|
@ -4370,6 +4399,11 @@ etag@1.8.1:
|
|||
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
|
||||
integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==
|
||||
|
||||
event-target-shim@^5.0.0:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789"
|
||||
integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==
|
||||
|
||||
eventemitter3@^4.0.1:
|
||||
version "4.0.7"
|
||||
resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz"
|
||||
|
|
@ -4544,6 +4578,11 @@ forever-agent@~0.6.1:
|
|||
resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz"
|
||||
integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
|
||||
|
||||
form-data-encoder@1.7.2:
|
||||
version "1.7.2"
|
||||
resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-1.7.2.tgz#1f1ae3dccf58ed4690b86d87e4f57c654fbab040"
|
||||
integrity sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==
|
||||
|
||||
form-data@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz"
|
||||
|
|
@ -4562,6 +4601,14 @@ form-data@~2.3.2:
|
|||
combined-stream "^1.0.6"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
formdata-node@^4.3.2:
|
||||
version "4.4.1"
|
||||
resolved "https://registry.yarnpkg.com/formdata-node/-/formdata-node-4.4.1.tgz#23f6a5cb9cb55315912cbec4ff7b0f59bbd191e2"
|
||||
integrity sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==
|
||||
dependencies:
|
||||
node-domexception "1.0.0"
|
||||
web-streams-polyfill "4.0.0-beta.3"
|
||||
|
||||
fs.realpath@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
|
||||
|
|
@ -5324,6 +5371,13 @@ https-browserify@1.0.0, https-browserify@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
|
||||
integrity sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==
|
||||
|
||||
humanize-ms@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed"
|
||||
integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==
|
||||
dependencies:
|
||||
ms "^2.0.0"
|
||||
|
||||
iconv-lite@0.4.19:
|
||||
version "0.4.19"
|
||||
resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz"
|
||||
|
|
@ -6571,7 +6625,7 @@ ms@2.1.2:
|
|||
resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
|
||||
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
||||
|
||||
ms@^2.1.1:
|
||||
ms@^2.0.0, ms@^2.1.1:
|
||||
version "2.1.3"
|
||||
resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
|
||||
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
|
||||
|
|
@ -6723,11 +6777,23 @@ nextjs-current-url@^1.0.3:
|
|||
next "^13.4.7"
|
||||
react "^18.2.0"
|
||||
|
||||
node-domexception@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5"
|
||||
integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==
|
||||
|
||||
node-fetch@2.6.1:
|
||||
version "2.6.1"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
|
||||
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
||||
|
||||
node-fetch@^2.6.7:
|
||||
version "2.7.0"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d"
|
||||
integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==
|
||||
dependencies:
|
||||
whatwg-url "^5.0.0"
|
||||
|
||||
node-html-parser@1.4.9:
|
||||
version "1.4.9"
|
||||
resolved "https://registry.yarnpkg.com/node-html-parser/-/node-html-parser-1.4.9.tgz#3c8f6cac46479fae5800725edb532e9ae8fd816c"
|
||||
|
|
@ -6898,6 +6964,20 @@ open@^8.4.0:
|
|||
is-docker "^2.1.1"
|
||||
is-wsl "^2.2.0"
|
||||
|
||||
openai@^4.42.0:
|
||||
version "4.42.0"
|
||||
resolved "https://registry.yarnpkg.com/openai/-/openai-4.42.0.tgz#8e6517839dcfbde848b981965989ccd2a4d70b1c"
|
||||
integrity sha512-xbiQQ2YNqdkE6cHqeWKa7lsAvdYfgp84XiNFOVkAMa6+9KpmOL4hCWCRR6e6I/clpaens/T9XeLVtyC5StXoRw==
|
||||
dependencies:
|
||||
"@types/node" "^18.11.18"
|
||||
"@types/node-fetch" "^2.6.4"
|
||||
abort-controller "^3.0.0"
|
||||
agentkeepalive "^4.2.1"
|
||||
form-data-encoder "1.7.2"
|
||||
formdata-node "^4.3.2"
|
||||
node-fetch "^2.6.7"
|
||||
web-streams-polyfill "^3.2.1"
|
||||
|
||||
optimism@^0.18.0:
|
||||
version "0.18.0"
|
||||
resolved "https://registry.yarnpkg.com/optimism/-/optimism-0.18.0.tgz#e7bb38b24715f3fdad8a9a7fc18e999144bbfa63"
|
||||
|
|
@ -8616,6 +8696,11 @@ tr46@^1.0.1:
|
|||
dependencies:
|
||||
punycode "^2.1.0"
|
||||
|
||||
tr46@~0.0.3:
|
||||
version "0.0.3"
|
||||
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
|
||||
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
|
||||
|
||||
trim-lines@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/trim-lines/-/trim-lines-3.0.1.tgz#d802e332a07df861c48802c04321017b1bd87338"
|
||||
|
|
@ -8788,6 +8873,11 @@ unbox-primitive@^1.0.2:
|
|||
has-symbols "^1.0.3"
|
||||
which-boxed-primitive "^1.0.2"
|
||||
|
||||
undici-types@~5.26.4:
|
||||
version "5.26.5"
|
||||
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
|
||||
integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
|
||||
|
||||
unherit@^1.0.4:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz"
|
||||
|
|
@ -9284,6 +9374,21 @@ web-namespaces@^2.0.0:
|
|||
resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-2.0.1.tgz#1010ff7c650eccb2592cebeeaf9a1b253fd40692"
|
||||
integrity sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==
|
||||
|
||||
web-streams-polyfill@4.0.0-beta.3:
|
||||
version "4.0.0-beta.3"
|
||||
resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz#2898486b74f5156095e473efe989dcf185047a38"
|
||||
integrity sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==
|
||||
|
||||
web-streams-polyfill@^3.2.1:
|
||||
version "3.3.3"
|
||||
resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz#2073b91a2fdb1fbfbd401e7de0ac9f8214cecb4b"
|
||||
integrity sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==
|
||||
|
||||
webidl-conversions@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
|
||||
integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==
|
||||
|
||||
webidl-conversions@^4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
|
||||
|
|
@ -9306,6 +9411,14 @@ whats-that-gerber@^4.2.7:
|
|||
dependencies:
|
||||
xtend "^4.0.2"
|
||||
|
||||
whatwg-url@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
|
||||
integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==
|
||||
dependencies:
|
||||
tr46 "~0.0.3"
|
||||
webidl-conversions "^3.0.0"
|
||||
|
||||
whatwg-url@^7.0.0:
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue